From 3558b9325ccfe372e1c892825be7e0e42364a2131af9f8375f8da311c6a3ccea Mon Sep 17 00:00:00 2001 From: Stefan Dirsch Date: Fri, 25 Sep 2015 12:04:06 +0000 Subject: [PATCH 1/2] Accepting request 333715 from home:eeich:branches:X11:XOrg - u_vesa-Add-VBEDPMSGetCapabilities-VBEDPMSGet.patch Add VBEDPMSGetCapabilities() and VBEDPMSGet() functions (bsc#947356, boo#947493). OBS-URL: https://build.opensuse.org/request/show/333715 OBS-URL: https://build.opensuse.org/package/show/X11:XOrg/xorg-x11-server?expand=0&rev=584 --- ...dd-VBEDPMSGetCapabilities-VBEDPMSGet.patch | 432 ++++++++++++++++++ xorg-x11-server.changes | 7 + xorg-x11-server.macros.in | 2 + xorg-x11-server.spec | 7 + 4 files changed, 448 insertions(+) create mode 100644 u_vesa-Add-VBEDPMSGetCapabilities-VBEDPMSGet.patch diff --git a/u_vesa-Add-VBEDPMSGetCapabilities-VBEDPMSGet.patch b/u_vesa-Add-VBEDPMSGetCapabilities-VBEDPMSGet.patch new file mode 100644 index 0000000..e758fb9 --- /dev/null +++ b/u_vesa-Add-VBEDPMSGetCapabilities-VBEDPMSGet.patch @@ -0,0 +1,432 @@ +From: Egbert Eich +Date: Thu Sep 24 12:38:13 2015 +0200 +Subject: [PATCH]vesa: Add VBEDPMSGetCapabilities & VBEDPMSGet() +Patch-mainline: to be upstreamed + +References: bnc#947356 +Signed-off-by: Egbert Eich + +Signed-off-by: Egbert Eich +--- + hw/xfree86/vbe/vbe.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++- + hw/xfree86/vbe/vbe.h | 3 ++ + 2 files changed, 149 insertions(+), 1 deletion(-) + +diff --git a/hw/xfree86/vbe/vbe.c b/hw/xfree86/vbe/vbe.c +index 39f0cef..179d4c6 100644 +--- a/hw/xfree86/vbe/vbe.c ++++ b/hw/xfree86/vbe/vbe.c +@@ -20,6 +20,28 @@ + #include "vbe.h" + #include + ++#ifdef DEBUG ++#define LOG_RESULT(x) { \ ++ xf86DrvMsg(x->pInt10->pScrn->scrnIndex, X_INFO, "%s () = %s\n", \ ++ __FUNCTION__, \ ++ R16(x->pInt10->ax) == 0x4f ? "success" : "failure"); } ++ ++#define LOG_SUCCESS(x) { \ ++ xf86DrvMsg(x->pInt10->pScrn->scrnIndex, X_INFO, "%s () = success\n", \ ++ __FUNCTION__); } ++#define LOG_FAILURE(x) { \ ++ xf86DrvMsg(x->pInt10->pScrn->scrnIndex, X_INFO, "%s () = failure\n", \ ++ __FUNCTION__); } ++#define LOG_VBE(x,fmt, args...) { \ ++ xf86DrvMsg(x->pInt10->pScrn->scrnIndex, X_INFO, "%s " fmt, __FUNCTION__, \ ++ ##args); } ++#else ++#define LOG_RESULT(x) {} ++#define LOG_SUCCESS(x) {} ++#define LOG_FAILURE(x) {} ++#define LOG_VBE(x,fmt, args...) {} ++#endif ++ + #define VERSION(x) VBE_VERSION_MAJOR(x),VBE_VERSION_MINOR(x) + + #if X_BYTE_ORDER == X_LITTLE_ENDIAN +@@ -187,6 +209,7 @@ vbeProbeDDC(vbeInfoPtr pVbe) + if (pVbe->ddc != DDC_UNCHECKED) + return TRUE; + ++ LOG_VBE(pVbe,"()\n"); + pVbe->pInt10->ax = 0x4F15; + pVbe->pInt10->bx = 0; + pVbe->pInt10->cx = 0; +@@ -195,6 +218,7 @@ vbeProbeDDC(vbeInfoPtr pVbe) + pVbe->pInt10->num = 0x10; + + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if ((pVbe->pInt10->ax & 0xff) != 0x4f) { + xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC not supported\n"); +@@ -285,6 +309,7 @@ vbeReadEDID(vbeInfoPtr pVbe) + memset(page, 0, sizeof(vbeInfoPtr)); + strcpy(page, vbeVersionString); + ++ LOG_VBE(pVbe, "()\n"); + pVbe->pInt10->ax = 0x4F15; + pVbe->pInt10->bx = 0x01; + pVbe->pInt10->cx = 0; +@@ -294,6 +319,7 @@ vbeReadEDID(vbeInfoPtr pVbe) + pVbe->pInt10->num = 0x10; + + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if ((pVbe->pInt10->ax & 0xff) != 0x4f) { + xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC invalid\n"); +@@ -365,11 +391,13 @@ VBEGetVBEInfo(vbeInfoPtr pVbe) + ((char *) pVbe->memory)[2] = 'E'; + ((char *) pVbe->memory)[3] = '2'; + ++ LOG_VBE(pVbe, "()\n"); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f00; + pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); + pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return NULL; +@@ -458,6 +486,7 @@ VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock * block) + Output: AX = Status + (All other registers are preserved) + */ ++ LOG_VBE(pVbe, "(mode=0x%x)\n", mode); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f02; + pVbe->pInt10->bx = mode; +@@ -471,6 +500,7 @@ VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock * block) + pVbe->pInt10->bx &= ~(1 << 11); + + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + return (R16(pVbe->pInt10->ax) == 0x4f); + } +@@ -488,10 +518,12 @@ VBEGetVBEMode(vbeInfoPtr pVbe, int *mode) + BX := Current video mode + (All other registers are preserved) + */ ++ LOG_VBE(pVbe, "()\n"); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f03; + + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) == 0x4f) { + *mode = R16(pVbe->pInt10->bx); +@@ -521,12 +553,14 @@ VBEGetModeInfo(vbeInfoPtr pVbe, int mode) + AX := status + (All other registers are preserved) + */ ++ LOG_VBE(pVbe, "(mode = 0x%x)\n",mode); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f01; + pVbe->pInt10->cx = mode; + pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); + pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + if (R16(pVbe->pInt10->ax) != 0x4f) + return NULL; + +@@ -586,6 +620,7 @@ VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function, + (All other registers are preserved) + */ + ++ LOG_VBE(pVbe, "(function = %d)", function); + if ((pVbe->version & 0xff00) > 0x100) { + int screen = pVbe->pInt10->pScrn->scrnIndex; + +@@ -597,9 +632,9 @@ VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function, + pVbe->pInt10->dx = 0; + pVbe->pInt10->cx = 0x000f; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + if (R16(pVbe->pInt10->ax) != 0x4f) + return FALSE; +- + if (function == MODE_SAVE) { + int npages = (R16(pVbe->pInt10->bx) * 64) / 4096 + 1; + +@@ -618,6 +653,7 @@ VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function, + + if (!*memory) + return FALSE; ++ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f04; + switch (function) { +@@ -635,6 +671,7 @@ VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function, + pVbe->pInt10->es = SEG_ADDR(*real_mode_pages); + pVbe->pInt10->bx = SEG_OFF(*real_mode_pages); + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + return (R16(pVbe->pInt10->ax) == 0x4f); + + } +@@ -652,11 +689,13 @@ VBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window) + + Output: + */ ++ LOG_VBE(pVbe, "(bank = %d window = %d)\n", iBank, window); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f05; + pVbe->pInt10->bx = window; + pVbe->pInt10->dx = iBank; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return FALSE; +@@ -690,12 +729,14 @@ VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, vbeScanwidthCommand command, + DX := Maximum Number of Scan Lines + */ + ++ LOG_VBE(pVbe,"(width = %i)\n",width); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f06; + pVbe->pInt10->bx = command; + if (command == SCANWID_SET || command == SCANWID_SET_BYTES) + pVbe->pInt10->cx = width; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return FALSE; +@@ -715,12 +756,15 @@ VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, vbeScanwidthCommand command, + Bool + VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace) + { ++ LOG_VBE(pVbe, "(x = %i y = %i wait_retrace = %s)\n", ++ x, y, wait_retrace ? "y" : "n"); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f07; + pVbe->pInt10->bx = wait_retrace ? 0x80 : 0x00; + pVbe->pInt10->cx = x; + pVbe->pInt10->dx = y; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return FALSE; +@@ -731,10 +775,12 @@ VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace) + Bool + VBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y) + { ++ LOG_VBE(pVbe, "()\n"); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f07; + pVbe->pInt10->bx = 0x01; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return FALSE; +@@ -761,6 +807,7 @@ VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits) + BH := Current number of bits of color per primary + */ + ++ LOG_VBE(pVbe, "(bits = %d)\n", bits); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f08; + if (!bits) +@@ -768,6 +815,7 @@ VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits) + else + pVbe->pInt10->bx = (bits & 0x00ff) << 8; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return 0; +@@ -805,6 +853,8 @@ VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num, + DS := Selector for memory mapped registers + */ + ++ LOG_VBE(pVbe,"(%s first = %i num = %i wait_retrace = %s)\n", ++ set ? "set" : "get", first, num, wait_retrace ? "y" : "n"); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f09; + if (!secondary) +@@ -818,6 +868,7 @@ VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num, + if (set) + memcpy(pVbe->memory, data, num * sizeof(CARD32)); + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return NULL; +@@ -850,11 +901,13 @@ VBEGetVBEpmi(vbeInfoPtr pVbe) + (All other registers are preserved) + */ + ++ LOG_VBE(pVbe, "()\n"); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f0a; + pVbe->pInt10->bx = 0; + pVbe->pInt10->di = 0; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return NULL; +@@ -967,6 +1020,7 @@ VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock) + AX := VBE Return Status + ECX := Closest pixel clock + */ ++ LOG_VBE(pVbe,"(mode = 0x%x clock = %d)\n", mode, clock); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f0b; +@@ -974,6 +1028,7 @@ VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock) + pVbe->pInt10->cx = clock; + pVbe->pInt10->dx = mode; + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if (R16(pVbe->pInt10->ax) != 0x4f) + return 0; +@@ -981,6 +1036,92 @@ VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock) + return pVbe->pInt10->cx; + } + ++int ++VBEDPMSGetCapabilities(vbeInfoPtr pVbe, int *cap) ++{ ++ /* ++ Input: ++ AX := 4F10h DPMS ++ BL := 00h Get VBE/PM Capabilities ++ CX := 00h ++ ES:DI := 0 ++ ++ Output: ++ AX := Status ++ BH := Power Saving State 1=supported, 0=unsupported ++ Bit 0: stand by, Bit 1: suspend, Bit 2: off Bit 3: reduced ++ */ ++ LOG_VBE(pVbe, "()\n"); ++ pVbe->pInt10->num = 0x10; ++ pVbe->pInt10->ax = 0x4f10; ++ pVbe->pInt10->bx = 0x0; ++ pVbe->pInt10->cx = 0x0; ++ pVbe->pInt10->es = pVbe->pInt10->di = 0; ++ xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); ++ ++ if ((R16(pVbe->pInt10->ax) != 0x4f)) ++ return FALSE; ++ ++ xf86DrvMsgVerb(pVbe->pInt10->pScrn->scrnIndex, X_INFO, 7, ++ "DPMSGetCapabilities: 0x%x\n,", ++ pVbe->pInt10->bx); ++ *cap = 1 << DPMSModeOn; /* always supported */ ++ if (pVbe->pInt10->bx & 0x100) ++ *cap |= 1 << DPMSModeStandby; ++ if (pVbe->pInt10->bx & 0x200) ++ *cap |= 1 << DPMSModeSuspend; ++ if (pVbe->pInt10->bx & 0x200) ++ *cap |= 1 << DPMSModeOff; ++ ++ return TRUE; ++} ++ ++int ++VBEDPMSGet(vbeInfoPtr pVbe, int *mode) ++{ ++ /* ++ Input: ++ AX := 4F10h DPMS ++ BL := 02h Get Display Power State ++ CX := 00h ++ ++ Output: ++ AX := VBE Return Status ++ BH := Power State currently set ++ */ ++ LOG_VBE(pVbe, "()\n"); ++ pVbe->pInt10->ax = 0x4f10; ++ pVbe->pInt10->bx = 0x2; ++ pVbe->pInt10->cx = 0x0; ++ xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); ++ if ((R16(pVbe->pInt10->ax) != 0x4f)) ++ return FALSE; ++ ++ xf86DrvMsgVerb(pVbe->pInt10->pScrn->scrnIndex, X_INFO, 7, ++ "DPMSGetState: 0x%x\n,", ++ pVbe->pInt10->bx); ++ switch (pVbe->pInt10->bx >> 4) { ++ case 0: ++ *mode = DPMSModeOn; ++ break; ++ case 1: ++ *mode = DPMSModeStandby; ++ break; ++ case 2: ++ *mode = DPMSModeSuspend; ++ break; ++ case 4: ++ *mode = DPMSModeOff; ++ break; ++ case 8: ++ *mode = DPMSModeOn; ++ break; ++ } ++ return TRUE; ++} ++ + Bool + VBEDPMSSet(vbeInfoPtr pVbe, int mode) + { +@@ -994,6 +1135,7 @@ VBEDPMSSet(vbeInfoPtr pVbe, int mode) + AX := VBE Return Status + */ + ++ LOG_VBE(pVbe, "(mode = %d)\n", mode); + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f10; + pVbe->pInt10->bx = 0x01; +@@ -1011,6 +1153,7 @@ VBEDPMSSet(vbeInfoPtr pVbe, int mode) + break; + } + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + return (R16(pVbe->pInt10->ax) == 0x4f); + } + +@@ -1059,6 +1202,7 @@ VBEReadPanelID(vbeInfoPtr pVbe) + void *tmp = NULL; + int screen = pVbe->pInt10->pScrn->scrnIndex; + ++ LOG_VBE(pVbe, "()\n"); + pVbe->pInt10->ax = 0x4F11; + pVbe->pInt10->bx = 0x01; + pVbe->pInt10->cx = 0; +@@ -1068,6 +1212,7 @@ VBEReadPanelID(vbeInfoPtr pVbe) + pVbe->pInt10->num = 0x10; + + xf86ExecX86int10(pVbe->pInt10); ++ LOG_RESULT(pVbe); + + if ((pVbe->pInt10->ax & 0xff) != 0x4f) { + xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE PanelID invalid\n"); +diff --git a/hw/xfree86/vbe/vbe.h b/hw/xfree86/vbe/vbe.h +index 3907c53..9b37f46 100644 +--- a/hw/xfree86/vbe/vbe.h ++++ b/hw/xfree86/vbe/vbe.h +@@ -336,6 +336,9 @@ VBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr, + + extern _X_EXPORT int VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int Clock); + extern _X_EXPORT Bool VBEDPMSSet(vbeInfoPtr pVbe, int mode); ++#define VBE_HAVE_DPMS_GET_CAPABILITIES ++extern _X_EXPORT Bool VBEDPMSGetCapabilities(vbeInfoPtr pVbe, int *cap); ++extern _X_EXPORT Bool VBEDPMSGet(vbeInfoPtr pVbe, int *mode); + + struct vbePanelID { + short hsize; diff --git a/xorg-x11-server.changes b/xorg-x11-server.changes index 9c0595b..0fef467 100644 --- a/xorg-x11-server.changes +++ b/xorg-x11-server.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Fri Sep 25 10:06:45 UTC 2015 - eich@suse.com + +- u_vesa-Add-VBEDPMSGetCapabilities-VBEDPMSGet.patch + Add VBEDPMSGetCapabilities() and VBEDPMSGet() functions + (bsc#947356, boo#947493). + ------------------------------------------------------------------- Thu Jul 30 12:10:08 CEST 2015 - tiwai@suse.de diff --git a/xorg-x11-server.macros.in b/xorg-x11-server.macros.in index 4007543..c5ea35a 100644 --- a/xorg-x11-server.macros.in +++ b/xorg-x11-server.macros.in @@ -13,3 +13,5 @@ Requires: X11_ABI_ANSIC = @abi_ansic@ %x11_abi_extension_req \ Requires: X11_ABI_EXTENSION = @abi_extension@ +%x11_abi_has_dirty_tracking2 \ + Requires: X11_ABI_HAS_DIRTYTRACKING2 diff --git a/xorg-x11-server.spec b/xorg-x11-server.spec index a5ced46..044ab8b 100644 --- a/xorg-x11-server.spec +++ b/xorg-x11-server.spec @@ -150,6 +150,9 @@ Obsoletes: glamor-egl < %{version} Provides: xf86-video-modesetting = %{version} Obsoletes: xf86-video-modesetting < %{version} + # Remove (also from depending driver(s)) when updating X11_ABI_VIDEODRV by updating the server package - NOTE: also remove from xorg-x11-server.macros.in ! +Provides: X11_ABI_HAS_DPMS_GET_CAPABILITIES + # Xvfb requires keyboard files as well (bnc#797124) Requires: xkeyboard-config @@ -178,6 +181,8 @@ Patch115: N_Force-swcursor-for-KMS-drivers-without-hw-cursor-sup.patch Patch117: xorg-x11-server-byte-order.patch +Patch160: u_vesa-Add-VBEDPMSGetCapabilities-VBEDPMSGet.patch + Patch201: U_linux-Add-linux_parse_vt_settings-and-linux_get_keep.patch Patch202: U_linux-Add-a-may_fail-paramter-to-linux_parse_vt_sett.patch Patch203: U_systemd-logind-Only-use-systemd-logind-integration-t.patch @@ -277,6 +282,8 @@ cp %{SOURCE90} . %patch117 -p1 +%patch160 -p1 + %patch201 -p1 %patch202 -p1 %patch203 -p1 From ea3cd4d1463e50e3328b9111e418701cee605c6c9c2105012fcfaa44eb30d5ef Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Fri, 25 Sep 2015 14:02:52 +0000 Subject: [PATCH 2/2] Replaced wrong marcro due to a copy-n-paste error. OBS-URL: https://build.opensuse.org/package/show/X11:XOrg/xorg-x11-server?expand=0&rev=585 --- xorg-x11-server.macros.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xorg-x11-server.macros.in b/xorg-x11-server.macros.in index c5ea35a..d3db706 100644 --- a/xorg-x11-server.macros.in +++ b/xorg-x11-server.macros.in @@ -13,5 +13,5 @@ Requires: X11_ABI_ANSIC = @abi_ansic@ %x11_abi_extension_req \ Requires: X11_ABI_EXTENSION = @abi_extension@ -%x11_abi_has_dirty_tracking2 \ - Requires: X11_ABI_HAS_DIRTYTRACKING2 +%x11_abi_has_dpms_get_capabilities \ +Requires: X11_ABI_HAS_DPMS_GET_CAPABILITIES