diff options
Diffstat (limited to 'xorg-server/hw')
-rw-r--r-- | xorg-server/hw/xfree86/common/xf86AutoConfig.c | 2 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/common/xf86pciBus.c | 24 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/common/xf86pciBus.h | 5 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/common/xf86platformBus.c | 85 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/man/xorg.conf.man | 77 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/os-support/linux/lnx_platform.c | 17 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/parser/Makefile.am | 1 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/parser/OutputClass.c | 167 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/parser/configProcs.h | 5 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/parser/read.c | 6 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/parser/write.c | 2 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/parser/xf86Parser.h | 9 | ||||
-rw-r--r-- | xorg-server/hw/xwin/Makefile.am | 2 |
13 files changed, 377 insertions, 25 deletions
diff --git a/xorg-server/hw/xfree86/common/xf86AutoConfig.c b/xorg-server/hw/xfree86/common/xf86AutoConfig.c index 4eb86de22..2b53b908a 100644 --- a/xorg-server/hw/xfree86/common/xf86AutoConfig.c +++ b/xorg-server/hw/xfree86/common/xf86AutoConfig.c @@ -265,7 +265,7 @@ listPossibleVideoDrivers(char *matches[], int nmatches) #endif #ifdef XSERVER_LIBPCIACCESS if (i < (nmatches - 1)) - i = xf86PciMatchDriver(matches, nmatches); + i += xf86PciMatchDriver(&matches[i], nmatches - i); #endif #if defined(__linux__) diff --git a/xorg-server/hw/xfree86/common/xf86pciBus.c b/xorg-server/hw/xfree86/common/xf86pciBus.c index 0f76a03ee..c06b04033 100644 --- a/xorg-server/hw/xfree86/common/xf86pciBus.c +++ b/xorg-server/hw/xfree86/common/xf86pciBus.c @@ -1320,8 +1320,9 @@ xchomp(char *line) * don't export their PCI ID's properly. If distros don't end up using this * feature it can and should be removed because the symbol-based resolution * scheme should be the primary one */ -void -xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_chip) +int +xf86MatchDriverFromFiles(uint16_t match_vendor, uint16_t match_chip, + char *matches[], int nmatches) { DIR *idsdir; FILE *fp; @@ -1331,11 +1332,11 @@ xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_c ssize_t read; char path_name[256], vendor_str[5], chip_str[5]; uint16_t vendor, chip; - int i, j; + int i = 0, j; idsdir = opendir(PCI_TXT_IDS_PATH); if (!idsdir) - return; + return 0; xf86Msg(X_INFO, "Scanning %s directory for additional PCI ID's supported by the drivers\n", @@ -1386,10 +1387,6 @@ xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_c } } if (vendor == match_vendor && chip == match_chip) { - i = 0; - while (matches[i]) { - i++; - } matches[i] = (char *) malloc(sizeof(char) * strlen(direntry->d_name) - 3); @@ -1412,6 +1409,7 @@ xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_c } xf86Msg(X_INFO, "Matched %s from file name %s\n", matches[i], direntry->d_name); + i++; } } else { @@ -1425,6 +1423,7 @@ xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_c end: free(line); closedir(idsdir); + return i; } #endif /* __linux__ */ @@ -1435,7 +1434,7 @@ xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_c int xf86PciMatchDriver(char *matches[], int nmatches) { - int i; + int i = 0; struct pci_device *info = NULL; struct pci_device_iterator *iter; @@ -1450,13 +1449,10 @@ xf86PciMatchDriver(char *matches[], int nmatches) pci_iterator_destroy(iter); #ifdef __linux__ if (info) - xf86MatchDriverFromFiles(matches, info->vendor_id, info->device_id); + i += xf86MatchDriverFromFiles(info->vendor_id, info->device_id, + matches, nmatches); #endif - for (i = 0; (i < nmatches) && (matches[i]); i++) { - /* find end of matches list */ - } - if ((info != NULL) && (i < nmatches)) { i += xf86VideoPtrToDriverList(info, &(matches[i]), nmatches - i); } diff --git a/xorg-server/hw/xfree86/common/xf86pciBus.h b/xorg-server/hw/xfree86/common/xf86pciBus.h index b497a7f2d..45b5a0fee 100644 --- a/xorg-server/hw/xfree86/common/xf86pciBus.h +++ b/xorg-server/hw/xfree86/common/xf86pciBus.h @@ -47,8 +47,9 @@ void xf86PciConfigureNewDev(void *busData, struct pci_device *pVideo, ((x)->func == (y)->func) && \ ((x)->dev == (y)->dev)) -void -xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_chip); +int +xf86MatchDriverFromFiles(uint16_t match_vendor, uint16_t match_chip, + char *matches[], int nmatches); int xf86VideoPtrToDriverList(struct pci_device *dev, char *returnList[], int returnListMax); diff --git a/xorg-server/hw/xfree86/common/xf86platformBus.c b/xorg-server/hw/xfree86/common/xf86platformBus.c index dd118a285..eb1a3fb5d 100644 --- a/xorg-server/hw/xfree86/common/xf86platformBus.c +++ b/xorg-server/hw/xfree86/common/xf86platformBus.c @@ -47,6 +47,7 @@ #include "xf86Bus.h" #include "Pci.h" #include "xf86platformBus.h" +#include "xf86Config.h" #include "randrstr.h" int platformSlotClaimed; @@ -199,6 +200,81 @@ xf86_check_platform_slot(const struct xf86_platform_device *pd) return TRUE; } +static Bool +MatchToken(const char *value, struct xorg_list *patterns, + int (*compare)(const char *, const char *)) +{ + const xf86MatchGroup *group; + + /* If there are no patterns, accept the match */ + if (xorg_list_is_empty(patterns)) + return TRUE; + + /* If there are patterns but no attribute, reject the match */ + if (!value) + return FALSE; + + /* + * Otherwise, iterate the list of patterns ensuring each entry has a + * match. Each list entry is a separate Match line of the same type. + */ + xorg_list_for_each_entry(group, patterns, entry) { + Bool match = FALSE; + char *const *cur; + + for (cur = group->values; *cur; cur++) { + if ((*compare)(value, *cur) == 0) { + match = TRUE; + break; + } + } + + if (!match) + return FALSE; + } + + /* All the entries in the list matched the attribute */ + return TRUE; +} + +static Bool +OutputClassMatches(const XF86ConfOutputClassPtr oclass, int index) +{ + char *driver = xf86_get_platform_attrib(index, ODEV_ATTRIB_DRIVER); + + if (!MatchToken(driver, &oclass->match_driver, strcmp)) + return FALSE; + + return TRUE; +} + +static int +xf86OutputClassDriverList(int index, char *matches[], int nmatches) +{ + XF86ConfOutputClassPtr cl; + int i = 0; + + if (nmatches == 0) + return 0; + + for (cl = xf86configptr->conf_outputclass_lst; cl; cl = cl->list.next) { + if (OutputClassMatches(cl, index)) { + char *path = xf86_get_platform_attrib(index, ODEV_ATTRIB_PATH); + + xf86Msg(X_INFO, "Applying OutputClass \"%s\" to %s\n", + cl->identifier, path); + xf86Msg(X_NONE, "\tloading driver: %s\n", cl->driver); + + matches[i++] = xstrdup(cl->driver); + } + + if (i >= nmatches) + break; + } + + return i; +} + /** * @return The numbers of found devices that match with the current system * drivers. @@ -218,16 +294,15 @@ xf86PlatformMatchDriver(char *matches[], int nmatches) else if (!xf86IsPrimaryPlatform(&xf86_platform_devices[i]) && (pass == 0)) continue; + j += xf86OutputClassDriverList(i, &matches[j], nmatches - j); + info = xf86_platform_devices[i].pdev; #ifdef __linux__ if (info) - xf86MatchDriverFromFiles(matches, info->vendor_id, info->device_id); + j += xf86MatchDriverFromFiles(info->vendor_id, info->device_id, + &matches[j], nmatches - j); #endif - for (j = 0; (j < nmatches) && (matches[j]); j++) { - /* find end of matches list */ - } - if ((info != NULL) && (j < nmatches)) { j += xf86VideoPtrToDriverList(info, &(matches[j]), nmatches - j); } diff --git a/xorg-server/hw/xfree86/man/xorg.conf.man b/xorg-server/hw/xfree86/man/xorg.conf.man index cadd87b7b..bc33df197 100644 --- a/xorg-server/hw/xfree86/man/xorg.conf.man +++ b/xorg-server/hw/xfree86/man/xorg.conf.man @@ -171,6 +171,7 @@ The section names are: .BR "Extensions " "Extension enabling" .BR "InputDevice " "Input device description" .BR "InputClass " "Input class description" +.BR "OutputClass " "Output class description" .BR "Device " "Graphics device description" .BR "VideoAdaptor " "Xv video adaptor description" .BR "Monitor " "Monitor description" @@ -1190,6 +1191,82 @@ entries. This optional entry specifies that the device should be ignored entirely, and not added to the server. This can be useful when the device is handled by another program and no X events should be generated. +.SH "OUTPUTCLASS SECTION" +The config file may have multiple +.B OutputClass +sections. +These sections are optional and are used to provide configuration for a +class of output devices as they are automatically added. +An output device can match more than one +.B OutputClass +section. +Each class can override settings from a previous class, so it is best to +arrange the sections with the most generic matches first. +.PP +.B OutputClass +sections have the following format: +.PP +.RS 4 +.nf +.B "Section \*qOutputClass\*q" +.BI " Identifier \*q" name \*q +.I " entries" +.I " ..." +.B "EndSection" +.fi +.RE +.PP +The +.B Identifier +entry is required in all +.B OutputClass +sections. +All other entries are optional. +.PP +The +.B Identifier +entry specifies the unique name for this output class. +The +.B Driver +entry specifies the name of the driver to use for this output device. +After all classes have been examined, the +.RI \*q outputdriver \*q +module from the first +.B Driver +entry will be enabled when using the loadable server. +.PP +When an output device is automatically added, its characteristics are +checked against all +.B OutputClass +sections. +Each section can contain optional entries to narrow the match of the class. +If none of the optional entries appear, the +.B OutputClass +section is generic and will match any output device. +If more than one of these entries appear, they all must match for the +configuration to apply. +.PP +The following list of tokens can be matched against attributes of the device. +An entry can be constructed to match attributes from different devices by +separating arguments with a '|' character. +.PP +For example: +.PP +.RS 4 +.nf +.B "Section \*qOutputClass\*q" +.B " Identifier \*qMy Class\*q" +.B " # kernel driver must be either foo or bar +.B " MatchDriver \*qfoo|bar\*q +.I " ..." +.B "EndSection" +.fi +.RE +.TP 7 +.BI "MatchDriver \*q" matchdriver \*q +Check the case-sensitive string +.RI \*q matchdriver \*q +against the kernel driver of the device. .SH "DEVICE SECTION" The config file may have multiple .B Device diff --git a/xorg-server/hw/xfree86/os-support/linux/lnx_platform.c b/xorg-server/hw/xfree86/os-support/linux/lnx_platform.c index 308275ab4..d660761c5 100644 --- a/xorg-server/hw/xfree86/os-support/linux/lnx_platform.c +++ b/xorg-server/hw/xfree86/os-support/linux/lnx_platform.c @@ -24,6 +24,7 @@ static Bool get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) { drmSetVersion sv; + drmVersionPtr v; char *buf; int major, minor, fd; int err = 0; @@ -57,8 +58,9 @@ get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) err = drmSetInterfaceVersion(fd, &sv); if (err) { - ErrorF("setversion 1.4 failed: %s\n", strerror(-err)); - goto out; + xf86Msg(X_ERROR, "%s: failed to set DRM interface version 1.4: %s\n", + path, strerror(-err)); + goto out; } /* for a delayed probe we've already added the device */ @@ -74,6 +76,17 @@ get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) xf86_add_platform_device_attrib(delayed_index, ODEV_ATTRIB_BUSID, buf); drmFreeBusid(buf); + + v = drmGetVersion(fd); + if (!v) { + xf86Msg(X_ERROR, "%s: failed to query DRM version\n", path); + goto out; + } + + xf86_add_platform_device_attrib(delayed_index, ODEV_ATTRIB_DRIVER, + v->name); + drmFreeVersion(v); + out: if (!server_fd) close(fd); diff --git a/xorg-server/hw/xfree86/parser/Makefile.am b/xorg-server/hw/xfree86/parser/Makefile.am index 3bf62e8af..4d0bb4fd8 100644 --- a/xorg-server/hw/xfree86/parser/Makefile.am +++ b/xorg-server/hw/xfree86/parser/Makefile.am @@ -14,6 +14,7 @@ INTERNAL_SOURCES= \ Flags.c \ Input.c \ InputClass.c \ + OutputClass.c \ Layout.c \ Module.c \ Video.c \ diff --git a/xorg-server/hw/xfree86/parser/OutputClass.c b/xorg-server/hw/xfree86/parser/OutputClass.c new file mode 100644 index 000000000..7e9a8ac1a --- /dev/null +++ b/xorg-server/hw/xfree86/parser/OutputClass.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2014 NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "os.h" +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +static +xf86ConfigSymTabRec OutputClassTab[] = { + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {DRIVER, "driver"}, + {MATCH_DRIVER, "matchdriver"}, + {-1, ""}, +}; + +#define CLEANUP xf86freeOutputClassList + +#define TOKEN_SEP "|" + +static void +add_group_entry(struct xorg_list *head, char **values) +{ + xf86MatchGroup *group; + + group = malloc(sizeof(*group)); + if (group) { + group->values = values; + xorg_list_add(&group->entry, head); + } +} + +XF86ConfOutputClassPtr +xf86parseOutputClassSection(void) +{ + int has_ident = FALSE; + int token; + + parsePrologue(XF86ConfOutputClassPtr, XF86ConfOutputClassRec) + + /* Initialize MatchGroup lists */ + xorg_list_init(&ptr->match_driver); + + while ((token = xf86getToken(OutputClassTab)) != ENDSECTION) { + switch (token) { + case COMMENT: + ptr->comment = xf86addComment(ptr->comment, xf86_lex_val.str); + break; + case IDENTIFIER: + if (xf86getSubToken(&(ptr->comment)) != STRING) + Error(QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error(MULTIPLE_MSG, "Identifier"); + ptr->identifier = xf86_lex_val.str; + has_ident = TRUE; + break; + case DRIVER: + if (xf86getSubToken(&(ptr->comment)) != STRING) + Error(QUOTE_MSG, "Driver"); + else + ptr->driver = xf86_lex_val.str; + break; + case MATCH_DRIVER: + if (xf86getSubToken(&(ptr->comment)) != STRING) + Error(QUOTE_MSG, "MatchDriver"); + add_group_entry(&ptr->match_driver, + xstrtokenize(xf86_lex_val.str, TOKEN_SEP)); + free(xf86_lex_val.str); + break; + case EOF_TOKEN: + Error(UNEXPECTED_EOF_MSG); + break; + default: + Error(INVALID_KEYWORD_MSG, xf86tokenString()); + break; + } + } + + if (!has_ident) + Error(NO_IDENT_MSG); + +#ifdef DEBUG + printf("OutputClass section parsed\n"); +#endif + + return ptr; +} +void +xf86printOutputClassSection(FILE * cf, XF86ConfOutputClassPtr ptr) +{ + const xf86MatchGroup *group; + char *const *cur; + + while (ptr) { + fprintf(cf, "Section \"OutputClass\"\n"); + if (ptr->comment) + fprintf(cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf(cf, "\tIdentifier \"%s\"\n", ptr->identifier); + if (ptr->driver) + fprintf(cf, "\tDriver \"%s\"\n", ptr->driver); + + xorg_list_for_each_entry(group, &ptr->match_driver, entry) { + fprintf(cf, "\tMatchDriver \""); + for (cur = group->values; *cur; cur++) + fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP, + *cur); + fprintf(cf, "\"\n"); + } + + fprintf(cf, "EndSection\n\n"); + ptr = ptr->list.next; + } +} + +void +xf86freeOutputClassList(XF86ConfOutputClassPtr ptr) +{ + XF86ConfOutputClassPtr prev; + + while (ptr) { + xf86MatchGroup *group, *next; + char **list; + + TestFree(ptr->identifier); + TestFree(ptr->comment); + TestFree(ptr->driver); + + xorg_list_for_each_entry_safe(group, next, &ptr->match_driver, entry) { + xorg_list_del(&group->entry); + for (list = group->values; *list; list++) + free(*list); + free(group); + } + + prev = ptr; + ptr = ptr->list.next; + free(prev); + } +} diff --git a/xorg-server/hw/xfree86/parser/configProcs.h b/xorg-server/hw/xfree86/parser/configProcs.h index 60509dcd8..774e2a2da 100644 --- a/xorg-server/hw/xfree86/parser/configProcs.h +++ b/xorg-server/hw/xfree86/parser/configProcs.h @@ -57,6 +57,11 @@ XF86ConfInputClassPtr xf86parseInputClassSection(void); void xf86printInputClassSection(FILE * f, XF86ConfInputClassPtr ptr); void xf86freeInputClassList(XF86ConfInputClassPtr ptr); +/* OutputClass.c */ +XF86ConfOutputClassPtr xf86parseOutputClassSection(void); +void xf86printOutputClassSection(FILE * f, XF86ConfOutputClassPtr ptr); +void xf86freeOutputClassList(XF86ConfOutputClassPtr ptr); + /* Layout.c */ XF86ConfLayoutPtr xf86parseLayoutSection(void); void xf86printLayoutSection(FILE * cf, XF86ConfLayoutPtr ptr); diff --git a/xorg-server/hw/xfree86/parser/read.c b/xorg-server/hw/xfree86/parser/read.c index 2478b074b..22f6e6af4 100644 --- a/xorg-server/hw/xfree86/parser/read.c +++ b/xorg-server/hw/xfree86/parser/read.c @@ -165,6 +165,12 @@ xf86readConfigFile(void) HANDLE_LIST(conf_inputclass_lst, xf86parseInputClassSection, XF86ConfInputClassPtr); } + else if (xf86nameCompare(xf86_lex_val.str, "outputclass") == 0) { + free(xf86_lex_val.str); + xf86_lex_val.str = NULL; + HANDLE_LIST(conf_outputclass_lst, xf86parseOutputClassSection, + XF86ConfOutputClassPtr); + } else if (xf86nameCompare(xf86_lex_val.str, "module") == 0) { free(xf86_lex_val.str); xf86_lex_val.str = NULL; diff --git a/xorg-server/hw/xfree86/parser/write.c b/xorg-server/hw/xfree86/parser/write.c index 26739b933..472b27ba1 100644 --- a/xorg-server/hw/xfree86/parser/write.c +++ b/xorg-server/hw/xfree86/parser/write.c @@ -114,6 +114,8 @@ doWriteConfigFile(const char *filename, XF86ConfigPtr cptr) xf86printInputClassSection(cf, cptr->conf_inputclass_lst); + xf86printOutputClassSection(cf, cptr->conf_outputclass_lst); + xf86printVideoAdaptorSection(cf, cptr->conf_videoadaptor_lst); xf86printModesSection(cf, cptr->conf_modes_lst); diff --git a/xorg-server/hw/xfree86/parser/xf86Parser.h b/xorg-server/hw/xfree86/parser/xf86Parser.h index c95423a1f..3fa5b716d 100644 --- a/xorg-server/hw/xfree86/parser/xf86Parser.h +++ b/xorg-server/hw/xfree86/parser/xf86Parser.h @@ -327,6 +327,14 @@ typedef struct { char *comment; } XF86ConfInputClassRec, *XF86ConfInputClassPtr; +typedef struct { + GenericListRec list; + char *identifier; + char *driver; + struct xorg_list match_driver; + char *comment; +} XF86ConfOutputClassRec, *XF86ConfOutputClassPtr; + /* Values for adj_where */ #define CONF_ADJ_OBSOLETE -1 #define CONF_ADJ_ABSOLUTE 0 @@ -411,6 +419,7 @@ typedef struct { XF86ConfScreenPtr conf_screen_lst; XF86ConfInputPtr conf_input_lst; XF86ConfInputClassPtr conf_inputclass_lst; + XF86ConfOutputClassPtr conf_outputclass_lst; XF86ConfLayoutPtr conf_layout_lst; XF86ConfVendorPtr conf_vendor_lst; XF86ConfDRIPtr conf_dri; diff --git a/xorg-server/hw/xwin/Makefile.am b/xorg-server/hw/xwin/Makefile.am index cf42cfd2d..4ee963227 100644 --- a/xorg-server/hw/xwin/Makefile.am +++ b/xorg-server/hw/xwin/Makefile.am @@ -155,7 +155,7 @@ XWIN_LIBS += $(top_builddir)/pseudoramiX/libPseudoramiX.la \ $(top_builddir)/Xi/libXistubs.la XWin_DEPENDENCIES = $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_LIBS) $(XSERVER_LIBS) XWin_LDADD = $(MULTIWINDOW_LIBS) $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_GLX_LINK_FLAGS) $(XWIN_LIBS) $(MAIN_LIB) $(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XWIN_SYS_LIBS) -XWin_LDFLAGS = -mwindows -static -Wl,--disable-stdcall-fixup +XWin_LDFLAGS = -mwindows -Wl,--disable-stdcall-fixup $(LD_EXPORT_SYMBOLS_FLAG) .rc.o: |