First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / os-support / bus / Sbus.c
blobc864e3385f684eccdddc8f46c343a26829d4dfd1
1 /*
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>
26 #endif
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <sys/ioctl.h>
33 #include <sys/mman.h>
34 #ifdef sun
35 #include <sys/utsname.h>
36 #endif
37 #include "xf86.h"
38 #include "xf86Priv.h"
39 #include "xf86_OSlib.h"
41 #include "xf86sbusBus.h"
42 #include "xf86Sbus.h"
44 int promRootNode;
46 static int promFd = -1;
47 static int promCurrentNode;
48 static int promOpenCount = 0;
49 static int promP1275 = -1;
50 #define MAX_PROP 128
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" },
71 { 0, 0, NULL }
74 int
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)
82 return 0;
83 promCurrentNode = *(int *)promOpio->oprom_array;
84 return *(int *)promOpio->oprom_array;
87 int
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)
95 return 0;
96 promCurrentNode = *(int *)promOpio->oprom_array;
97 return *(int *)promOpio->oprom_array;
100 char *
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)
107 return 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;
118 for (;;) {
119 promOpio->oprom_size = MAX_PROP;
120 if (ioctl(promFd, OPROMNXTPROP, promOpio) < 0)
121 return 0;
122 if (!promOpio->oprom_size)
123 return 0;
124 if (!strcmp(promOpio->oprom_array, prop))
125 return 1;
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
135 static int
136 promSetNode(sbusPromNodePtr pnode)
138 int node;
140 if (!pnode->node || pnode->node == -1)
141 return -1;
142 if (pnode->cookie[0] & PROM_NODE_SIBLING)
143 node = promGetSibling(pnode->cookie[1]);
144 else
145 node = promGetChild(pnode->cookie[1]);
146 if (pnode->node != node)
147 return -1;
148 return 0;
151 static void
152 promIsP1275(void)
154 #ifdef linux
155 FILE *f;
156 char buffer[1024];
158 if (promP1275 != -1)
159 return;
160 promP1275 = 0;
161 f = fopen("/proc/cpuinfo","r");
162 if (!f) return;
163 while (fgets(buffer, 1024, f) != NULL)
164 if (!strncmp (buffer, "type", 4) && strstr (buffer, "sun4u")) {
165 promP1275 = 1;
166 break;
168 fclose(f);
169 #elif defined(sun)
170 struct utsname buffer;
172 if ((uname(&buffer) >= 0) && !strcmp(buffer.machine, "sun4u"))
173 promP1275 = TRUE;
174 else
175 promP1275 = FALSE;
176 #elif defined(__FreeBSD__)
177 promP1275 = TRUE;
178 #else
179 #error Missing promIsP1275() function for this OS
180 #endif
183 _X_EXPORT void
184 sparcPromClose(void)
186 if (promOpenCount > 1) {
187 promOpenCount--;
188 return;
190 if (promFd != -1) {
191 close(promFd);
192 promFd = -1;
194 if (promOpio) {
195 xfree(promOpio);
196 promOpio = NULL;
198 promOpenCount = 0;
201 _X_EXPORT int
202 sparcPromInit(void)
204 if (promOpenCount) {
205 promOpenCount++;
206 return 0;
208 promFd = open("/dev/openprom", O_RDONLY, 0);
209 if (promFd == -1)
210 return -1;
211 promOpio = (struct openpromio *)xalloc(4096);
212 if (!promOpio) {
213 sparcPromClose();
214 return -1;
216 promRootNode = promGetSibling(0);
217 if (!promRootNode) {
218 sparcPromClose();
219 return -1;
221 promIsP1275();
222 promOpenCount++;
224 return 0;
227 _X_EXPORT char *
228 sparcPromGetProperty(sbusPromNodePtr pnode, const char *prop, int *lenp)
230 if (promSetNode(pnode))
231 return NULL;
232 return promGetProperty(prop, lenp);
235 _X_EXPORT int
236 sparcPromGetBool(sbusPromNodePtr pnode, const char *prop)
238 if (promSetNode(pnode))
239 return 0;
240 return promGetBool(prop);
243 static void
244 promWalkAssignNodes(int node, int oldnode, int flags, sbusDevicePtr *devicePtrs)
246 int nextnode;
247 int len, sbus = flags & PROM_NODE_SBUS;
248 char *prop;
249 int devId, i, j;
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)
257 break;
258 while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',')
259 prop++;
260 for (i = 0; sbusDeviceTable[i].devId; i++)
261 if (!strcmp(prop, sbusDeviceTable[i].promName))
262 break;
263 devId = sbusDeviceTable[i].devId;
264 if (!devId)
265 break;
266 if (!sbus) {
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)
275 break;
277 for (i = 0; i < 32; i++) {
278 if (!devicePtrs[i] || devicePtrs[i]->devId != devId)
279 continue;
280 if (devicePtrs[i]->node.node) {
281 if ((devicePtrs[i]->node.cookie[0] & ~PROM_NODE_SIBLING) <=
282 (flags & ~PROM_NODE_SIBLING))
283 continue;
284 for (j = i + 1, pNode = devicePtrs[i]->node; j < 32; j++) {
285 if (!devicePtrs[j] || devicePtrs[j]->devId != devId)
286 continue;
287 pNode2 = devicePtrs[j]->node;
288 devicePtrs[j]->node = pNode;
289 pNode = pNode2;
292 devicePtrs[i]->node.node = node;
293 devicePtrs[i]->node.cookie[0] = flags;
294 devicePtrs[i]->node.cookie[1] = oldnode;
295 break;
297 break;
299 } while (0);
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);
308 if (nextnode)
309 promWalkAssignNodes(nextnode, node, sbus, devicePtrs);
311 nextnode = promGetSibling(node);
312 if (nextnode)
313 promWalkAssignNodes(nextnode, node, PROM_NODE_SIBLING | sbus, devicePtrs);
316 void
317 sparcPromAssignNodes(void)
319 sbusDevicePtr psdp, *psdpp;
320 int n, holes = 0, i, j;
321 FILE *f;
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)
327 holes = 1;
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. */
333 char buffer[64];
334 int fbNum, devId;
335 static struct {
336 int devId;
337 char *prefix;
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" },
347 { 0, NULL },
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)))
354 break;
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);
362 psdp->devId = devId;
363 psdp->fbNum = fbNum;
364 psdp->fd = -2;
367 fclose(f);
369 promGetSibling(0);
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)
373 j++;
374 xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (n + j + 1));
375 for (i = 0, psdpp = xf86SbusInfo; i < 32; i++)
376 if (devicePtrs[i]) {
377 if (devicePtrs[i]->fbNum == -1) {
378 memmove(psdpp + 1, psdpp, sizeof(psdpp) * (n + 1));
379 *psdpp = devicePtrs[i];
380 } else
381 n--;
385 static char *
386 promGetReg(int type)
388 char *prop;
389 int len;
390 static char regstr[40];
392 regstr[0] = 0;
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);
401 else
402 sprintf (regstr, "@%x", (reg[0] >> 11) & 0x1f);
403 } else if (len == 4)
404 sprintf (regstr, "@%x", reg[0]);
405 else {
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]);
417 } else
418 sprintf (regstr, "@%x,%x", regs[0] >> 4, regs[1]);
421 return regstr;
424 static int
425 promWalkNode2Pathname(char *path, int parent, int node, int searchNode, int type)
427 int nextnode;
428 int len, ntype = type;
429 char *prop, *p;
431 prop = promGetProperty("name", &len);
432 *path = '/';
433 if (!prop || len <= 0)
434 return 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);
443 if (*p)
444 strcat (path, p);
445 if (node == searchNode)
446 return 1;
447 nextnode = promGetChild(node);
448 if (nextnode &&
449 promWalkNode2Pathname(strchr(path, 0), node, nextnode, searchNode, ntype))
450 return 1;
451 nextnode = promGetSibling(node);
452 if (nextnode &&
453 promWalkNode2Pathname(path, parent, nextnode, searchNode, type))
454 return 1;
455 return 0;
458 char *
459 sparcPromNode2Pathname(sbusPromNodePtr pnode)
461 char *ret;
463 if (!pnode->node) return NULL;
464 ret = xalloc(4096);
465 if (!ret) return NULL;
466 if (promWalkNode2Pathname(ret, promRootNode, promGetChild(promRootNode), pnode->node, 0))
467 return ret;
468 xfree(ret);
469 return NULL;
472 static int
473 promWalkPathname2Node(char *name, char *regstr, int parent, int type)
475 int len, node, ret;
476 char *prop, *p;
478 for (;;) {
479 prop = promGetProperty("name", &len);
480 if (!prop || len <= 0)
481 return 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)
491 continue;
492 if (*name && strcmp(name, prop))
493 continue;
494 if (*regstr) {
495 p = promGetReg(type);
496 if (! *p || strcmp(p + 1, regstr))
497 continue;
499 break;
501 if (!node) {
502 for (node = promGetChild(parent); node; node = promGetSibling(node)) {
503 ret = promWalkPathname2Node(name, regstr, node, type);
504 if (ret) return ret;
506 return 0;
508 name = strchr(regstr, 0) + 1;
509 if (! *name)
510 return node;
511 p = strchr(name, '/');
512 if (p)
513 *p = 0;
514 else
515 p = strchr(name, 0);
516 regstr = strchr(name, '@');
517 if (regstr)
518 *regstr++ = 0;
519 else
520 regstr = p;
521 if (name == regstr)
522 return 0;
523 parent = node;
528 sparcPromPathname2Node(const char *pathName)
530 int i;
531 char *name, *regstr, *p;
533 i = strlen(pathName);
534 name = xalloc(i + 2);
535 if (! name) return 0;
536 strcpy (name, pathName);
537 name [i + 1] = 0;
538 if (name[0] != '/')
539 return 0;
540 p = strchr(name + 1, '/');
541 if (p)
542 *p = 0;
543 else
544 p = strchr(name, 0);
545 regstr = strchr(name, '@');
546 if (regstr)
547 *regstr++ = 0;
548 else
549 regstr = p;
550 if (name + 1 == regstr)
551 return 0;
552 promGetSibling(0);
553 i = promWalkPathname2Node(name + 1, regstr, promRootNode, 0);
554 xfree(name);
555 return i;
558 _X_EXPORT pointer
559 xf86MapSbusMem(sbusDevicePtr psdp, unsigned long offset, unsigned long size)
561 pointer ret;
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);
568 if (psdp->fd == -1)
569 return NULL;
570 } else if (psdp->fd < 0)
571 return NULL;
573 ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE,
574 psdp->fd, off);
575 if (ret == (pointer) -1) {
576 ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
577 psdp->fd, off);
579 if (ret == (pointer) -1)
580 return NULL;
582 return (char *)ret + (offset - off);
585 _X_EXPORT void
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. */
596 _X_EXPORT void
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;
611 fbcursor.size.y = 1;
612 fbcursor.set = FB_CUR_SETALL;
613 ioctl(psdp->fd, FBIOSCURSOR, &fbcursor);
616 /* Set HW cursor colormap. */
617 _X_EXPORT void
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));
624 red[0] = bg >> 16;
625 green[0] = bg >> 8;
626 blue[0] = bg;
627 red[1] = fg >> 16;
628 green[1] = fg >> 8;
629 blue[1] = fg;
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);