2 * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * Except as contained in this notice, the name of Conectiva Linux shall
23 * not be used in advertising or otherwise to promote the sale, use or other
24 * dealings in this Software without prior written authorization from
27 * Author: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
34 #undef SERVER /* defined in config.h, but of no use here */
36 /* return values from ReadCardsLine. */
48 #define NOCLOCKPROBE 8
56 static int ReadCardsLine(FILE*, char*); /* must have 256 bytes */
57 static int CompareCards(_Xconst
void *left
, _Xconst
void *right
);
58 static int BCompareCards(_Xconst
void *left
, _Xconst
void *right
);
59 static void DoReadCardsDatabase(void);
60 static char **DoFilterCardNames(char *pattern
, int *result
);
66 unsigned short vendor
;
67 unsigned short valid_vendor
;
76 static int linenum
= 0;
77 static char *Cards
= "lib/X11/Cards";
85 const pciVendorInfo
*xf86PCIVendorInfo
;
90 InitializePciInfo(void)
92 xf86PCIVendorInfo
= pciVendorInfoList
;
96 CheckChipsets(xf86cfgModuleOptions
*opts
, int *err
)
98 int i
, j
, ichk
, ivnd
= 0, vendor
= -1, device
;
99 const pciDeviceInfo
**pDev
;
100 SymTabPtr chips
= opts
->chipsets
;
101 chipset_check
*check
= NULL
;
105 CheckMsg(CHECKER_NO_CHIPSETS
, "WARNING No chipsets specified.\n");
110 while (chips
->name
) {
111 device
= chips
->token
& 0xffff;
112 vendor
= (chips
->token
& 0xffff0000) >> 16;
114 vendor
= opts
->vendor
;
116 for (ichk
= 0; ichk
< num_check
; ichk
++)
117 if (check
[ichk
].vendor
== vendor
)
119 if (ichk
>= num_check
) {
120 check
= (chipset_check
*)
121 XtRealloc((XtPointer
)check
,
122 sizeof(chipset_check
) * (num_check
+ 1));
123 check
[num_check
].vendor
= vendor
;
124 memset(&check
[num_check
], 0, sizeof(chipset_check
));
128 /* Search for vendor in xf86PCIVendorInfo */
129 if (xf86PCIVendorInfo
) {
130 for (ivnd
= 0; xf86PCIVendorInfo
[ivnd
].VendorID
; ivnd
++)
131 if (vendor
== xf86PCIVendorInfo
[ivnd
].VendorID
)
134 if (xf86PCIVendorInfo
&& xf86PCIVendorInfo
[ivnd
].VendorID
) {
135 check
[ichk
].valid_vendor
= 1;
136 check
[ichk
].ivendor
= ivnd
;
139 CheckMsg(CHECKER_CANNOT_VERIFY_CHIPSET
,
140 "WARNING Cannot verify chipset \"%s\" (0x%x)\n",
141 chips
->name
, device
);
147 if (xf86PCIVendorInfo
&&
148 (pDev
= xf86PCIVendorInfo
[ivnd
].Device
) != NULL
) {
149 if (check
[ichk
].chipsets
== NULL
) {
150 for (j
= 0; pDev
[j
]; j
++)
152 check
[ichk
].chipsets
= (char*)XtCalloc(1, j
);
154 for (j
= 0; pDev
[j
]; j
++) {
155 if (device
== pDev
[j
]->DeviceID
) {
156 if (strcmp(chips
->name
, pDev
[j
]->DeviceName
)) {
157 CheckMsg(CHECKER_NOMATCH_CHIPSET_STRINGS
,
158 "WARNING chipset strings don't match: \"%s\" \"%s\" (0x%x)\n",
159 chips
->name
, xf86PCIVendorInfo
[ivnd
].Device
[j
]->DeviceName
,
167 CheckMsg(CHECKER_CHIPSET_NOT_LISTED
,
168 "WARNING chipset \"%s\" (0x%x) not in list.\n", chips
->name
, device
);
172 check
[ichk
].chipsets
[j
] = 1;
177 for (i
= 0; i
< num_check
; i
++) {
178 if (!check
[i
].valid_vendor
) {
179 CheckMsg(CHECKER_CHIPSET_NO_VENDOR
,
180 "WARNING No such vendor 0x%x\n", vendor
);
183 for (j
= 0; j
< check
[i
].num_chipsets
; j
++) {
184 if (xf86PCIVendorInfo
&& !check
[i
].chipsets
[j
]) {
185 CheckMsg(CHECKER_CHIPSET_NOT_SUPPORTED
,
186 "NOTICE chipset \"%s\" (0x%x) not listed as supported.\n",
187 xf86PCIVendorInfo
[check
[i
].ivendor
].Device
[j
]->DeviceName
,
188 xf86PCIVendorInfo
[check
[i
].ivendor
].Device
[j
]->DeviceID
);
191 XtFree(check
[i
].chipsets
);
194 XtFree((XtPointer
)check
);
199 ReadCardsDatabase(void)
203 int i
, j
, ivendor
, idevice
;
205 _Xconst
char *vendor
, *device
;
206 CardsEntry
*entry
= NULL
, *tmp
;
207 xf86cfgModuleOptions
*opts
= module_options
;
208 const pciDeviceInfo
**pDev
;
210 /* Only list cards that have a driver installed */
212 if (opts
->chipsets
) {
213 SymTabPtr chips
= opts
->chipsets
;
215 while (chips
->name
) {
217 device
= chips
->name
;
218 ivendor
= (chips
->token
& 0xffff0000) >> 16;
219 idevice
= chips
->token
& 0xffff0;
221 ivendor
= opts
->vendor
;
223 if (xf86PCIVendorInfo
) {
224 for (i
= 0; xf86PCIVendorInfo
[i
].VendorName
; i
++)
225 if (ivendor
== xf86PCIVendorInfo
[i
].VendorID
) {
226 vendor
= xf86PCIVendorInfo
[i
].VendorName
;
229 if (xf86PCIVendorInfo
[i
].VendorName
) {
230 if ((pDev
= xf86PCIVendorInfo
[i
].Device
)) {
231 for (j
= 0; pDev
[j
]; j
++)
232 if (idevice
== pDev
[j
]->DeviceID
) {
233 device
= pDev
[j
]->DeviceName
;
240 /* Since frequently there is more than one driver for a
241 * single vendor, it is required to avoid duplicates.
243 XmuSnprintf(name
, sizeof(name
), "%s %s", vendor
, device
);
244 tmp
= LookupCard(name
);
246 if (tmp
== NULL
|| strcmp(tmp
->chipset
, chips
->name
) ||
247 strcmp(tmp
->driver
, opts
->name
)) {
248 entry
= (CardsEntry
*)XtCalloc(1, sizeof(CardsEntry
));
249 if (NumCardsEntry
% 16 == 0) {
250 CardsDB
= (CardsEntry
**)XtRealloc((XtPointer
)CardsDB
,
251 sizeof(CardsEntry
*) * (NumCardsEntry
+ 16));
253 CardsDB
[NumCardsEntry
++] = entry
;
254 entry
->name
= XtNewString(name
);
256 /* XXX no private copy of strings */
257 entry
->chipset
= (char*)chips
->name
;
258 entry
->driver
= opts
->name
;
260 /* better than linear searchs to find duplicates */
261 qsort(CardsDB
, NumCardsEntry
, sizeof(CardsEntry
*),
270 /* fix entries with the same name */
271 for (i
= 0; i
< NumCardsEntry
- 2;) {
272 for (j
= i
+ 1; j
< NumCardsEntry
- 1 &&
273 strcmp(CardsDB
[i
]->name
, CardsDB
[j
]->name
) == 0; j
++)
280 if (strcmp(CardsDB
[i
]->chipset
, CardsDB
[j
]->chipset
))
281 str
= CardsDB
[i
]->chipset
;
283 str
= CardsDB
[i
]->driver
;
285 XmuSnprintf(name
, sizeof(name
), "%s (%s)",
286 CardsDB
[i
]->name
, str
);
287 XtFree(CardsDB
[i
]->name
);
288 CardsDB
[i
]->name
= XtNewString(name
);
297 /* make sure data is valid to bsearch in */
298 qsort(CardsDB
, NumCardsEntry
, sizeof(CardsEntry
*), CompareCards
);
302 DoReadCardsDatabase();
306 DoReadCardsDatabase(void)
309 FILE *fp
= fopen(Cards
, "r");
311 CardsEntry
*entry
= NULL
;
312 static char *CardsError
= "Error reading Cards database, at line %d (%s).\n";
315 fprintf(stderr
, "Cannot open Cards database.\n");
319 while ((result
= ReadCardsLine(fp
, buffer
)) != END
) {
322 fprintf(stderr
, CardsError
, linenum
, buffer
);
326 "Unknown field type in Cards database, at line %d (%s).\n",
330 entry
= calloc(1, sizeof(CardsEntry
));
331 if (NumCardsEntry
% 16 == 0) {
332 CardsDB
= realloc(CardsDB
, sizeof(CardsEntry
*) *
333 (NumCardsEntry
+ 16));
334 if (CardsDB
== NULL
) {
335 fprintf(stderr
, "Out of memory reading Cards database.\n");
339 CardsDB
[NumCardsEntry
++] = entry
;
340 entry
->name
= strdup(buffer
);
343 if (entry
== NULL
|| entry
->chipset
!= NULL
) {
344 fprintf(stderr
, CardsError
, linenum
, buffer
);
348 entry
->chipset
= strdup(buffer
);
352 if (entry
== NULL
|| entry
->server
!= NULL
) {
353 fprintf(stderr
, CardsError
, linenum
, buffer
);
356 entry
->server
= strdup(buffer
);
359 if (entry
== NULL
|| entry
->driver
!= NULL
) {
360 fprintf(stderr
, CardsError
, linenum
, buffer
);
363 entry
->driver
= strdup(buffer
);
366 if (entry
== NULL
|| entry
->ramdac
!= NULL
) {
367 fprintf(stderr
, CardsError
, linenum
, buffer
);
370 entry
->ramdac
= strdup(buffer
);
373 if (entry
== NULL
|| entry
->clockchip
!= NULL
) {
374 fprintf(stderr
, CardsError
, linenum
, buffer
);
377 entry
->clockchip
= strdup(buffer
);
380 if (entry
== NULL
|| entry
->dacspeed
!= NULL
) {
381 fprintf(stderr
, CardsError
, linenum
, buffer
);
384 entry
->dacspeed
= strdup(buffer
);
388 fprintf(stderr
, CardsError
, linenum
, buffer
);
391 entry
->flags
|= F_NOCLOCKPROBE
;
395 fprintf(stderr
, CardsError
, linenum
, buffer
);
398 entry
->flags
|= F_UNSUPPORTED
;
401 if (entry
== NULL
|| entry
->see
!= NULL
) {
402 fprintf(stderr
, CardsError
, linenum
, buffer
);
405 entry
->see
= strdup(buffer
);
409 fprintf(stderr
, CardsError
, linenum
, buffer
);
411 else if (entry
->lines
== NULL
)
412 entry
->lines
= strdup(buffer
);
414 char *str
= malloc(strlen(entry
->lines
) + strlen(buffer
) + 2);
416 sprintf(str
, "%s\n%s", entry
->lines
, buffer
);
426 qsort(CardsDB
, NumCardsEntry
, sizeof(CardsEntry
*), CompareCards
);
429 for (i
= 0; i
< NumCardsEntry
- 1; i
++) {
430 if (strcmp(CardsDB
[i
]->name
, CardsDB
[i
+1]->name
) == 0)
431 fprintf(stderr
, "Duplicate entry in Cards database: (%s).\n",
436 for (i
= 0; i
< NumCardsEntry
- 1; i
++) {
437 if (CardsDB
[i
]->see
!= NULL
) {
438 if ((entry
= LookupCard(CardsDB
[i
]->see
)) == NULL
) {
439 fprintf(stderr
, "Cannot find card '%s' for filling defaults.\n",
443 if (CardsDB
[i
]->chipset
== NULL
&& entry
->chipset
!= NULL
)
444 CardsDB
[i
]->chipset
= strdup(entry
->chipset
);
445 if (CardsDB
[i
]->server
== NULL
&& entry
->server
!= NULL
)
446 CardsDB
[i
]->server
= strdup(entry
->server
);
447 if (CardsDB
[i
]->driver
== NULL
&& entry
->driver
!= NULL
)
448 CardsDB
[i
]->driver
= strdup(entry
->driver
);
449 if (CardsDB
[i
]->ramdac
== NULL
&& entry
->ramdac
!= NULL
)
450 CardsDB
[i
]->ramdac
= strdup(entry
->ramdac
);
451 if (CardsDB
[i
]->clockchip
== NULL
&& entry
->clockchip
!= NULL
)
452 CardsDB
[i
]->clockchip
= strdup(entry
->clockchip
);
453 if (CardsDB
[i
]->dacspeed
== NULL
&& entry
->dacspeed
!= NULL
)
454 CardsDB
[i
]->dacspeed
= strdup(entry
->dacspeed
);
455 if (CardsDB
[i
]->flags
& F_NOCLOCKPROBE
)
456 CardsDB
[i
]->flags
|= F_NOCLOCKPROBE
;
457 if (CardsDB
[i
]->flags
& F_UNSUPPORTED
)
458 CardsDB
[i
]->flags
|= F_UNSUPPORTED
;
459 if (entry
->lines
!= NULL
) {
460 if (CardsDB
[i
]->lines
== NULL
)
461 CardsDB
[i
]->lines
= strdup(entry
->lines
);
463 char *str
= malloc(strlen(entry
->lines
) +
464 strlen(CardsDB
[i
]->lines
) + 2);
466 sprintf(str
, "%s\n%s", CardsDB
[i
]->lines
, entry
->lines
);
467 free(CardsDB
[i
]->lines
);
468 CardsDB
[i
]->lines
= str
;
471 if (entry
->see
!= NULL
) {
473 fprintf(stderr
, "Nested SEE entry: %s -> %s -> %s\n",
474 CardsDB
[i
]->name
, CardsDB
[i
]->see
, entry
->see
);
476 CardsDB
[i
]->see
= strdup(entry
->see
);
480 free(CardsDB
[i
]->see
);
481 CardsDB
[i
]->see
= NULL
;
487 LookupCard(char *name
)
491 if (NumCardsEntry
== 0 || CardsDB
== 0)
494 ptr
= (CardsEntry
**)bsearch(name
, CardsDB
, NumCardsEntry
,
495 sizeof(CardsEntry
*), BCompareCards
);
497 return (ptr
!= NULL
? *ptr
: NULL
);
501 GetCardNames(int *result
)
506 for (ncards
= 0; ncards
< NumCardsEntry
; ncards
++) {
507 if (ncards
% 16 == 0) {
508 if ((cards
= (char**)realloc(cards
, sizeof(char*) *
509 (ncards
+ 16))) == NULL
) {
510 fprintf(stderr
, "Out of memory.\n");
514 cards
[ncards
] = strdup(CardsDB
[ncards
]->name
);
523 FilterCardNames(char *pattern
, int *result
)
530 for (i
= 0; i
< NumCardsEntry
; i
++) {
531 if (strstr(CardsDB
[i
]->name
, pattern
) == NULL
)
533 if (ncards
% 16 == 0) {
534 if ((cards
= (char**)realloc(cards
, sizeof(char*) *
535 (ncards
+ 16))) == NULL
) {
536 fprintf(stderr
, "Out of memory.\n");
540 cards
[ncards
] = strdup(CardsDB
[i
]->name
);
549 return (DoFilterCardNames(pattern
, result
));
553 DoFilterCardNames(char *pattern
, int *result
)
558 char *cmd
, *ptr
, buffer
[256];
560 cmd
= malloc(32 + (strlen(pattern
) * 2) + strlen(Cards
));
562 strcpy(cmd
, "egrep -i '^NAME\\ .*");
566 if (!isalnum(*ptr
)) {
572 strcat(cmd
, ".*$' ");
574 strcat(cmd
, " | sort");
575 /*sprintf(cmd, "egrep -i '^NAME\\ .*%s.*$' %s | sort", pattern, Cards);*/
577 if ((fp
= popen(cmd
, "r")) == NULL
) {
578 fprintf(stderr
, "Cannot read Cards database.\n");
581 while (fgets(buffer
, sizeof(buffer
), fp
) != NULL
) {
582 ptr
= buffer
+ strlen(buffer
) - 1;
583 while (isspace(*ptr
) && ptr
> buffer
)
585 if (!isspace(*ptr
) && ptr
> buffer
)
588 while (!isspace(*ptr
) && *ptr
) /* skip NAME */
590 while (isspace(*ptr
) && *ptr
)
592 if (ncards
% 16 == 0) {
593 if ((cards
= (char**)realloc(cards
, sizeof(char*) *
594 (ncards
+ 16))) == NULL
) {
595 fprintf(stderr
, "Out of memory.\n");
599 cards
[ncards
++] = strdup(ptr
);
609 ReadCardsLine(FILE *fp
, char *value
)
611 char name
[32], buffer
[256], *ptr
, *end
;
612 int result
= NOTUSEFUL
;
616 if (fgets(buffer
, sizeof(buffer
), fp
) == NULL
)
620 /* skip initial spaces; should'nt bother about this.. */
621 while (isspace(*ptr
) && *ptr
)
624 if (*ptr
== '#' || *ptr
== '\0')
628 while (!isspace(*end
) && *end
)
630 if (end
- ptr
> sizeof(buffer
) - 1) {
631 strncpy(value
, buffer
, 255);
635 strncpy(name
, ptr
, end
- ptr
);
636 name
[end
- ptr
] = '\0';
638 /* read the optional arguments */
640 while (isspace(*ptr
) && *ptr
)
643 end
= ptr
+ strlen(ptr
) - 1;
644 while (isspace(*end
) && end
> ptr
)
650 if (strcmp(name
, "NAME") == 0)
652 else if (strcmp(name
, "CHIPSET") == 0)
654 else if (strcmp(name
, "SERVER") == 0)
656 else if (strcmp(name
, "DRIVER") == 0)
658 else if (strcmp(name
, "RAMDAC") == 0)
660 else if (strcmp(name
, "CLOCKCHIP") == 0)
662 else if (strcmp(name
, "DACSPEED") == 0)
664 else if (strcmp(name
, "NOCLOCKPROBE") == 0)
665 result
= NOCLOCKPROBE
;
666 else if (strcmp(name
, "UNSUPPORTED") == 0)
667 result
= UNSUPPORTED
;
668 else if (strcmp(name
, "SEE") == 0)
670 else if (strcmp(name
, "LINE") == 0)
672 else if (strcmp(name
, "END") == 0)
679 /* value *must* have at least 256 bytes */
686 CompareCards(_Xconst
void *left
, _Xconst
void *right
)
688 return strcasecmp((*(CardsEntry
**)left
)->name
, (*(CardsEntry
**)right
)->name
);
692 BCompareCards(_Xconst
void *name
, _Xconst
void *card
)
694 return (strcasecmp((char*)name
, (*(CardsEntry
**)card
)->name
));