diff --git a/hw/xfree86/common/xf86AutoConfig.c b/hw/xfree86/common/xf86AutoConfig.c index bf41c4dd3..a6bfc0190 100644 --- a/hw/xfree86/common/xf86AutoConfig.c +++ b/hw/xfree86/common/xf86AutoConfig.c @@ -215,27 +215,10 @@ xf86AutoConfig(void) { const char **p; char buf[1024]; - struct pci_device_iterator *iter; - struct pci_device * info = NULL; const char *driver = NULL; ConfigStatus ret; - /* Find the primary device, and get some information about it. */ - iter = pci_slot_match_iterator_create(NULL); - while ((info = pci_device_next(iter)) != NULL) { - if (xf86IsPrimaryPci(info)) { - break; - } - } - - pci_iterator_destroy(iter); - - if (!info) { - ErrorF("Primary device is not PCI\n"); - } - - if (info) - driver = videoPtrToDriverName(info); + driver = chooseVideoDriver(); AppendToConfig(BUILTIN_MODULE_SECTION); AppendToConfig(BUILTIN_MONITOR_SECTION); @@ -301,15 +284,14 @@ xchomp(char *line) len = strlen(line); if (line[len - 1] == '\n' && len > 0) { line[len - 1] = '\0'; - return 0; } + return 0; } GDevPtr autoConfigDevice(GDevPtr preconf_device) { GDevPtr ptr = NULL; - confScreenPtr scrn = NULL; if (!xf86configptr) { return NULL; @@ -347,41 +329,20 @@ autoConfigDevice(GDevPtr preconf_device) return ptr; } -char* -chooseVideoDriver(void) +static void +matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip) { - struct pci_device * info = NULL; - struct pci_device_iterator *iter; DIR *idsdir; FILE *fp; struct dirent *direntry; char *line = NULL; - char *chosen_driver = NULL; size_t len; ssize_t read; char path_name[256], vendor_str[5], chip_str[5]; uint16_t vendor, chip; int i, j; - char *matches[20]; /* If we have more than 20 drivers we're in trouble */ - - for (i=0 ; i<20 ; i++) - matches[i] = NULL; - - /* Find the primary device, and get some information about it. */ - iter = pci_slot_match_iterator_create(NULL); - while ((info = pci_device_next(iter)) != NULL) { - if (xf86IsPrimaryPci(info)) { - break; - } - } - - pci_iterator_destroy(iter); - - if (!info) { - ErrorF("Primary device is not PCI\n"); - } - idsdir = opendir("/usr/share/xserver-xorg/pci"); + if (idsdir) { direntry = readdir(idsdir); /* Read the directory */ @@ -423,8 +384,7 @@ chooseVideoDriver(void) chip = (int)strtol(chip_str, NULL, 16); } } - if (vendor == info->vendor_id && - (chip == info->device_id || chip == -1)) { + if (vendor == match_vendor && chip == match_chip ) { i = 0; while (matches[i]) { i++; @@ -457,6 +417,38 @@ chooseVideoDriver(void) direntry = readdir(idsdir); } } + end: + xfree(line); + closedir(idsdir); +} + +char* +chooseVideoDriver(void) +{ + struct pci_device * info = NULL; + struct pci_device_iterator *iter; + char *chosen_driver = NULL; + int i; + char *matches[20]; /* If we have more than 20 drivers we're in trouble */ + + for (i=0 ; i<20 ; i++) + matches[i] = NULL; + + /* Find the primary device, and get some information about it. */ + iter = pci_slot_match_iterator_create(NULL); + while ((info = pci_device_next(iter)) != NULL) { + if (xf86IsPrimaryPci(info)) { + break; + } + } + + pci_iterator_destroy(iter); + + if (!info) { + ErrorF("Primary device is not PCI\n"); + } + + matchDriverFromFiles(matches, info->vendor_id, info->device_id); /* TODO Handle multiple drivers claiming to support the same PCI ID */ if (matches[0]) { @@ -478,7 +470,6 @@ chooseVideoDriver(void) xf86Msg(X_DEFAULT, "Matched %s for the autoconfigured driver\n", chosen_driver); - end: i = 0; while (matches[i]) { if (matches[i] != chosen_driver) { @@ -486,8 +477,6 @@ chooseVideoDriver(void) } i++; } - xfree(line); - closedir(idsdir); return chosen_driver; } diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c index 064ff1689..f589b5aac 100644 --- a/hw/xfree86/modes/xf86Crtc.c +++ b/hw/xfree86/modes/xf86Crtc.c @@ -2134,8 +2134,12 @@ _X_EXPORT xf86MonPtr xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) { ScrnInfoPtr scrn = output->scrn; + xf86MonPtr mon; - return xf86DoEDID_DDC2 (scrn->scrnIndex, pDDCBus); + mon = xf86DoEDID_DDC2 (scrn->scrnIndex, pDDCBus); + xf86DDCApplyQuirks (scrn->scrnIndex, pDDCBus); + + return mon; } static char *_xf86ConnectorNames[] = { "None", "VGA", "DVI-I", "DVI-D", diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c index 8b5e69d9a..9fa5fef9e 100644 --- a/hw/xfree86/modes/xf86EdidModes.c +++ b/hw/xfree86/modes/xf86EdidModes.c @@ -54,6 +54,16 @@ typedef enum { DDC_QUIRK_PREFER_LARGE_60 = 1 << 0, /* 135MHz clock is too high, drop a bit */ DDC_QUIRK_135_CLOCK_TOO_HIGH = 1 << 1, + /* Prefer the largest mode at 75 Hz */ + DDC_QUIRK_PREFER_LARGE_75 = 1 << 2, + /* Convert detailed timing's horizontal from units of cm to mm */ + DDC_QUIRK_DETAILED_H_IN_CM = 1 << 3, + /* Convert detailed timing's vertical from units of cm to mm */ + DDC_QUIRK_DETAILED_V_IN_CM = 1 << 4, + /* Detailed timing descriptors have bogus size values, so just take the + * maximum size and use that. + */ + DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE = 1 << 5, } ddc_quirk_t; static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC) @@ -81,6 +91,52 @@ static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC) return FALSE; } +static Bool quirk_prefer_large_75 (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #11603: Funai Electronics PM36B */ + if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && + DDC->vendor.prod_id == 13600) + return TRUE; + + return FALSE; +} + +static Bool quirk_detailed_h_in_cm (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #10304: "LGPhilipsLCD LP154W01-A5" */ + /* Bug #12784: "LGPhilipsLCD LP154W01-TLA2" */ + if (memcmp (DDC->vendor.name, "LPL", 4) == 0 && + DDC->vendor.prod_id == 0) + return TRUE; + + /* Bug #11603: Funai Electronics PM36B */ + if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && + DDC->vendor.prod_id == 13600) + return TRUE; + + return FALSE; +} + +static Bool quirk_detailed_v_in_cm (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #11603: Funai Electronics PM36B */ + if (memcmp (DDC->vendor.name, "FCM", 4) == 0 && + DDC->vendor.prod_id == 13600) + return TRUE; + + return FALSE; +} + +static Bool quirk_detailed_use_maximum_size (int scrnIndex, xf86MonPtr DDC) +{ + /* Bug #10304: LGPhilipsLCD LP154W01-A5 */ + if (memcmp (DDC->vendor.name, "LPL", 4) == 0 && + DDC->vendor.prod_id == 0) + return TRUE; + + return FALSE; +} + static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC) { /* Envision Peripherals, Inc. EN-7100e. See bug #9550. */ @@ -106,6 +162,22 @@ static const ddc_quirk_map_t ddc_quirks[] = { quirk_135_clock_too_high, DDC_QUIRK_135_CLOCK_TOO_HIGH, "Recommended 135MHz pixel clock is too high" }, + { + quirk_prefer_large_75, DDC_QUIRK_PREFER_LARGE_75, + "Detailed timing is not preferred, use largest mode at 75Hz" + }, + { + quirk_detailed_h_in_cm, DDC_QUIRK_DETAILED_H_IN_CM, + "Detailed timings give horizontal size in cm." + }, + { + quirk_detailed_v_in_cm, DDC_QUIRK_DETAILED_V_IN_CM, + "Detailed timings give vertical size in cm." + }, + { + quirk_detailed_use_maximum_size, DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE, + "Detailed timings give sizes in cm." + }, { NULL, DDC_QUIRK_NONE, "No known quirks" @@ -303,6 +375,98 @@ DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes) } } +static ddc_quirk_t +xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose) +{ + ddc_quirk_t quirks; + int i; + + quirks = DDC_QUIRK_NONE; + for (i = 0; ddc_quirks[i].detect; i++) { + if (ddc_quirks[i].detect (scrnIndex, DDC)) { + if (verbose) { + xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n", + ddc_quirks[i].description); + } + quirks |= ddc_quirks[i].quirk; + } + } + + return quirks; +} + +/** + * Applies monitor-specific quirks to the decoded EDID information. + * + * Note that some quirks applying to the mode list are still implemented in + * xf86DDCGetModes. + */ +void +xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC) +{ + ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE); + int i; + + for (i = 0; i < DET_TIMINGS; i++) { + struct detailed_monitor_section *det_mon = &DDC->det_mon[i]; + + if (det_mon->type != DT) + continue; + + if (quirks & DDC_QUIRK_DETAILED_H_IN_CM) + det_mon->section.d_timings.h_size *= 10; + + if (quirks & DDC_QUIRK_DETAILED_V_IN_CM) + det_mon->section.d_timings.v_size *= 10; + + if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) { + det_mon->section.d_timings.h_size = 10 * DDC->features.hsize; + det_mon->section.d_timings.v_size = 10 * DDC->features.vsize; + } + } +} + +/** + * Walks the modes list, finding the mode with the largest area which is + * closest to the target refresh rate, and marks it as the only preferred mode. +*/ +static void +xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes, + float target_refresh) +{ + DisplayModePtr mode, best = modes; + + for (mode = modes; mode; mode = mode->next) + { + mode->type &= ~M_T_PREFERRED; + + if (mode == best) continue; + + if (mode->HDisplay * mode->VDisplay > + best->HDisplay * best->VDisplay) + { + best = mode; + continue; + } + if (mode->HDisplay * mode->VDisplay == + best->HDisplay * best->VDisplay) + { + double mode_refresh = xf86ModeVRefresh (mode); + double best_refresh = xf86ModeVRefresh (best); + double mode_dist = fabs(mode_refresh - target_refresh); + double best_dist = fabs(best_refresh - target_refresh); + + if (mode_dist < best_dist) + { + best = mode; + continue; + } + } + } + if (best) + best->type |= M_T_PREFERRED; +} + _X_EXPORT DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) { @@ -312,15 +476,9 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n", DDC->vendor.name, DDC->vendor.prod_id); - quirks = DDC_QUIRK_NONE; - for (i = 0; ddc_quirks[i].detect; i++) - if (ddc_quirks[i].detect (scrnIndex, DDC)) - { - xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n", - ddc_quirks[i].description); - quirks |= ddc_quirks[i].quirk; - } - + + quirks = xf86DDCDetectQuirks(scrnIndex, DDC, TRUE); + preferred = PREFERRED_TIMING_MODE(DDC->features.msc); if (quirks & DDC_QUIRK_PREFER_LARGE_60) preferred = 0; @@ -357,32 +515,11 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) Modes = xf86ModesAdd(Modes, Mode); if (quirks & DDC_QUIRK_PREFER_LARGE_60) - { - DisplayModePtr best = Modes; - for (Mode = Modes; Mode; Mode = Mode->next) - { - if (Mode == best) continue; - if (Mode->HDisplay * Mode->VDisplay > best->HDisplay * best->VDisplay) - { - best = Mode; - continue; - } - if (Mode->HDisplay * Mode->VDisplay == best->HDisplay * best->VDisplay) - { - double mode_refresh = xf86ModeVRefresh (Mode); - double best_refresh = xf86ModeVRefresh (best); - double mode_dist = fabs(mode_refresh - 60.0); - double best_dist = fabs(best_refresh - 60.0); - if (mode_dist < best_dist) - { - best = Mode; - continue; - } - } - } - if (best) - best->type |= M_T_PREFERRED; - } + xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60); + + if (quirks & DDC_QUIRK_PREFER_LARGE_75) + xf86DDCSetPreferredRefresh(scrnIndex, Modes, 75); + return Modes; } diff --git a/hw/xfree86/modes/xf86Modes.h b/hw/xfree86/modes/xf86Modes.h index 2bd4edeba..3722d25a0 100644 --- a/hw/xfree86/modes/xf86Modes.h +++ b/hw/xfree86/modes/xf86Modes.h @@ -95,4 +95,7 @@ xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor); DisplayModePtr xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed); +void +xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC); + #endif /* _XF86MODES_H_ */ diff --git a/hw/xfree86/parser/Configint.h b/hw/xfree86/parser/Configint.h index c20c1958c..4d5fbcfab 100644 --- a/hw/xfree86/parser/Configint.h +++ b/hw/xfree86/parser/Configint.h @@ -186,8 +186,6 @@ else\ "The Inactive keyword must be followed by a Device name in quotes." #define UNDEFINED_SCREEN_MSG \ "Undefined Screen \"%s\" referenced by ServerLayout \"%s\"." -#define UNDEFINED_MONITOR_MSG \ -"Undefined Monitor \"%s\" referenced by Screen \"%s\"." #define UNDEFINED_MODES_MSG \ "Undefined Modes Section \"%s\" referenced by Monitor \"%s\"." #define UNDEFINED_DEVICE_MSG \ @@ -204,8 +202,6 @@ else\ "This section must have an Identifier line." #define ONLY_ONE_MSG \ "This section must have only one of either %s line." -#define UNDEFINED_DRIVER_MSG \ -"Device section \"%s\" must have a Driver line." #define UNDEFINED_INPUTDRIVER_MSG \ "InputDevice section \"%s\" must have a Driver line." #define INVALID_GAMMA_MSG \ diff --git a/hw/xfree86/parser/Device.c b/hw/xfree86/parser/Device.c index 6ad5601b5..216789fc1 100644 --- a/hw/xfree86/parser/Device.c +++ b/hw/xfree86/parser/Device.c @@ -357,26 +357,6 @@ xf86freeDeviceList (XF86ConfDevicePtr ptr) } } -int -xf86validateDevice (XF86ConfigPtr p) -{ - XF86ConfDevicePtr device = p->conf_device_lst; - - if (!device) { - xf86validationError ("At least one Device section is required."); - return (FALSE); - } - - while (device) { - if (!device->dev_driver) { - xf86validationError (UNDEFINED_DRIVER_MSG, device->dev_identifier); - return (FALSE); - } - device = device->list.next; - } - return (TRUE); -} - XF86ConfDevicePtr xf86findDevice (const char *ident, XF86ConfDevicePtr p) { diff --git a/hw/xfree86/parser/Screen.c b/hw/xfree86/parser/Screen.c index 4df2b0560..4524f17f6 100644 --- a/hw/xfree86/parser/Screen.c +++ b/hw/xfree86/parser/Screen.c @@ -498,12 +498,6 @@ xf86validateScreen (XF86ConfigPtr p) XF86ConfDevicePtr device; XF86ConfAdaptorLinkPtr adaptor; - if (!screen) - { - xf86validationError ("At least one Screen section is required."); - return (FALSE); - } - while (screen) { if (screen->scrn_obso_driver && !screen->scrn_identifier) @@ -512,13 +506,7 @@ xf86validateScreen (XF86ConfigPtr p) monitor = xf86findMonitor (screen->scrn_monitor_str, p->conf_monitor_lst); if (screen->scrn_monitor_str) { - if (!monitor) - { - xf86validationError (UNDEFINED_MONITOR_MSG, - screen->scrn_monitor_str, screen->scrn_identifier); - return (FALSE); - } - else + if (monitor) { screen->scrn_monitor = monitor; if (!xf86validateMonitor(p, screen)) diff --git a/hw/xfree86/parser/read.c b/hw/xfree86/parser/read.c index a272f5ce3..430da0a5a 100644 --- a/hw/xfree86/parser/read.c +++ b/hw/xfree86/parser/read.c @@ -80,10 +80,8 @@ static xf86ConfigSymTabRec TopLevelTab[] = static int xf86validateConfig (XF86ConfigPtr p) { - /*if (!xf86validateDevice (p)) - return FALSE;*/ - /*if (!xf86validateScreen (p)) - return FALSE;*/ + if (!xf86validateScreen (p)) + return FALSE; if (!xf86validateInput (p)) return FALSE; if (!xf86validateLayout (p)) diff --git a/xorg-server.pc.in b/xorg-server.pc.in index d3ffaa2f8..c1cdb7d2a 100644 --- a/xorg-server.pc.in +++ b/xorg-server.pc.in @@ -8,6 +8,6 @@ sdkdir=@sdkdir@ Name: xorg-server Description: Modular X.Org X Server Version: @PACKAGE_VERSION@ -Requires.private: pixman-1 +Requires: pixman-1 Cflags: -I${sdkdir} Libs: -L${libdir}