|
From: Lars T. Skjong-B. <li...@sn...> - 2013-01-08 12:22:25
|
Hi Vitaly,
Thanks for your patches! I'll review and apply the patches soon and
release a new version.
--
Regards, Lars Tobias
On 12/8/12 12:30 PM, Vitaly V. Bursov wrote:
> Hello!
>
> AMD ADL is a part of the proprietary AMD Catalyst driver that is capable to
> provide access to displays' DDC interface. And it looks like there is no
> other way to implement DDC/CI on a Catalyst (direct PCI access for
> newer adapters is broken, no /dev/i2c either).
>
> Patch provides adapter and display enumeration (probing) and access to the
> corresponding i2c bus functionality (EDID, DDC/CI).
>
> Device naming scheme is like this: "adl:<adapter>:<display>".
>
> Please note that for unknown reason ADL thinks that there's multiple
> active adapters and yet they're the same.
>
>
> diff --git a/src/lib/amd_adl.c b/src/lib/amd_adl.c
> new file mode 100644
> index 0000000..40ca909
> --- /dev/null
> +++ b/src/lib/amd_adl.c
> @@ -0,0 +1,306 @@
> +/*
> + ddc/ci interface functions header
> + Copyright(c) 2012 Vitaly V. Bursov (vi...@bu...)
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 2 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, write to the Free Software
> + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> +*/
> +
> +#include "config.h"
> +
> +#ifdef HAVE_AMDADL
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <stdint.h>
> +#include <dlfcn.h>
> +
> +#define MAX_DISPLAYS (64)
> +
> +#ifndef LINUX
> +#define LINUX /* not Windows */
> +#endif
> +#include <ADL/adl_sdk.h>
> +
> +#include "amd_adl.h"
> +#include "ddcci.h"
> +
> +#if 1
> +# define D(x)
> +#else
> +# define D(x) x
> +#endif
> +
> +struct adl_state {
> + int initialized;
> +
> + void *lib;
> +
> + int (*ADL_Main_Control_Create)(ADL_MAIN_MALLOC_CALLBACK, int );
> + int (*ADL_Main_Control_Destroy)();
> +
> + int (*ADL_Adapter_NumberOfAdapters_Get)(int *lpNumAdapters);
> + int (*ADL_Adapter_AdapterInfo_Get)(LPAdapterInfo lpInfo, int iInputSize);
> + int (*ADL_Display_NumberOfDisplays_Get)(int iAdapterIndex, int *lpNumDisplays);
> + int (*ADL_Display_DisplayInfo_Get)(int iAdapterIndex, int *lpNumDisplays, ADLDisplayInfo **lppInfo, int iForceDetect);
> + int (*ADL_Display_DDCBlockAccess_Get)(int iAdapterIndex, int iDisplayIndex, int iOption, int iCommandIndex, int iSendMsgLen, char *lpucSendMsgBuf, int *lpulRecvMsgLen, char *lpucRecvMsgBuf);
> +
> + struct _displays {
> + int adapter_index;
> + int display_index;
> + } displays[MAX_DISPLAYS];
> + int displays_count;
> +};
> +
> +static struct adl_state *adl;
> +
> +static void* __stdcall adl_malloc (int size)
> +{
> + void* buffer = malloc (size);
> + if (buffer)
> + memset(buffer, 0, size);
> + return buffer;
> +}
> +
> +static void __stdcall adl_free ( void **buffer )
> +{
> + if (*buffer != NULL) {
> + free (*buffer);
> + *buffer = NULL;
> + }
> +}
> +
> +int amd_adl_get_displays_count()
> +{
> + if (!adl->initialized)
> + return -1;
> +
> + return adl->displays_count;
> +}
> +
> +int amd_adl_get_display(int idx, int *adapter, int *display)
> +{
> + if (!adl->initialized)
> + return -1;
> +
> + if (idx < 0 || idx >= adl->displays_count)
> + return -1;
> +
> + if (adapter)
> + *adapter = adl->displays[idx].adapter_index;
> + if (display)
> + *display = adl->displays[idx].display_index;
> +
> + return 0;
> +}
> +
> +int amd_adl_check_display(int adapter, int display)
> +{
> + int i;
> +
> + if (!adl->initialized)
> + return -1;
> +
> + for (i=0;i<adl->displays_count;i++){
> + if (adl->displays[i].adapter_index == adapter &&
> + adl->displays[i].display_index == display)
> + return 0;
> + }
> + return -1;
> +}
> +
> +int amd_adl_i2c_read(int adapter, int display, unsigned int addr, unsigned char *buf, unsigned int len)
> +{
> + int res;
> + char wbuf = addr << 1 | 1;
> +
> + res = adl->ADL_Display_DDCBlockAccess_Get(adapter, display, 0, 0, 1, &wbuf, (int*)&len, (char*)buf);
> +
> + D(fprintf(stderr, " >>>>>>>> adl i2c r on %d:%d a %x l %d err %d\n", adapter, display, addr, len, res));
> +
> + if (res != ADL_OK){
> + return -1;
> + }
> +
> + return len;
> +}
> +
> +int amd_adl_i2c_write(int adapter, int display, unsigned int addr, unsigned char *buf, unsigned int len)
> +{
> + int res, rlen;
> + char *wbuf = alloca(len+1);
> +
> + wbuf[0] = addr << 1;
> + memcpy(&wbuf[1], buf, len);
> +
> + rlen = 0;
> + res = adl->ADL_Display_DDCBlockAccess_Get(adapter, display, 0, 0, len+1, wbuf, &rlen, NULL);
> +
> + D(fprintf(stderr, " >>>>>>>> adl i2c w on %d:%d a %x l %d err %d\n", adapter, display, addr, len, res));
> +
> + if (res != ADL_OK){
> + return -1;
> + }
> +
> + return len;
> +}
> +
> +
> +int amd_adl_init()
> +{
> + int i;
> + int res;
> + int adapters_count;
> + AdapterInfo *adapter_info;
> +
> + adl = adl_malloc(sizeof(struct adl_state));
> +
> + if (!adl){
> + fprintf(stderr, "ADL error: malloc failed\n");
> + return 0;
> + }
> +
> + adl->lib = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
> + if (!adl->lib){
> + if (get_verbosity())
> + perror("ADL error: dlopen() failed\n");
> + return 0;
> + }
> +#define LOADFUNC(_n_) \
> + do { \
> + adl->_n_ = dlsym(adl->lib, #_n_); \
> + if (!adl->_n_) { \
> + fprintf(stderr, "ADL error: loading symbol %s\n", #_n_); \
> + return 0; \
> + } \
> + } while (0)
> +
> + LOADFUNC(ADL_Main_Control_Create);
> + LOADFUNC(ADL_Main_Control_Destroy);
> +
> + LOADFUNC(ADL_Adapter_NumberOfAdapters_Get);
> + LOADFUNC(ADL_Adapter_AdapterInfo_Get);
> + LOADFUNC(ADL_Display_NumberOfDisplays_Get);
> + LOADFUNC(ADL_Display_DisplayInfo_Get);
> + LOADFUNC(ADL_Display_DDCBlockAccess_Get);
> +
> +#undef LOADFUNC
> +
> + res = adl->ADL_Main_Control_Create(adl_malloc, 1); // retrieve adapter information only for adapters that are physically present and enabled
> +
> + if (res != ADL_OK){
> + if (get_verbosity())
> + fprintf(stderr, "Failed to initialize ADL: %d\n", res);
> + return 0;
> + }
> +
> + res = adl->ADL_Adapter_NumberOfAdapters_Get(&adapters_count);
> + if (res != ADL_OK){
> + if (get_verbosity())
> + fprintf(stderr, "Failed to get number of ADL adapters: %d\n", res);
> + return 0;
> + }
> +
> + if (adapters_count < 1){
> + if (get_verbosity())
> + fprintf(stderr, "No ADL adapters found.\n");
> + return 0;
> + }
> +
> + adapter_info = adl_malloc(sizeof(AdapterInfo) * adapters_count);
> + if (!adapter_info){
> + fprintf(stderr, "ADL error: malloc failed\n");
> + return 0;
> + }
> +
> + res = adl->ADL_Adapter_AdapterInfo_Get(adapter_info, sizeof(AdapterInfo) * adapters_count);
> + if (res != ADL_OK){
> + fprintf(stderr, "Failed to get ADL adapters info: %d\n", res);
> + return 0;
> + }
> +
> + for (i=0;i<adapters_count;i++){
> + int aidx = adapter_info[i].iAdapterIndex;
> + int numdisplays;
> + int j;
> + ADLDisplayInfo *display_info;
> +
> + if (adl->ADL_Display_DisplayInfo_Get(aidx, &numdisplays, &display_info, 0) != ADL_OK)
> + continue;
> +
> + D(printf("\t ================================\n"));
> + D(printf("\t %d: %s - %s %d %x:%x.%x %s\n", adapter_info[i].iAdapterIndex, adapter_info[i].strAdapterName, adapter_info[i].strDisplayName,
> + adapter_info[i].iPresent,
> + adapter_info[i].iBusNumber,
> + adapter_info[i].iDeviceNumber,
> + adapter_info[i].iFunctionNumber,
> + adapter_info[i].strUDID));
> +
> + for (j=0;j<numdisplays;j++){
> + int didx;
> +
> + if ((display_info[j].iDisplayInfoValue & ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED) &&
> + (display_info[j].iDisplayInfoValue & ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED)){
> +
> + didx = display_info[j].displayID.iDisplayLogicalIndex;
> +
> + D(printf("\t\t found display %s at %d:%d\n",
> + display_info[j].strDisplayName, aidx, didx));
> +
> + adl->displays[adl->displays_count].adapter_index = aidx;
> + adl->displays[adl->displays_count].display_index = didx;
> + adl->displays_count++;
> + if (adl->displays_count >= MAX_DISPLAYS){
> + break;
> + }
> + }
> + }
> +
> + adl_free((void**)&display_info);
> +
> + if (adl->displays_count >= MAX_DISPLAYS){
> + break;
> + }
> + }
> +
> + adl_free((void**)&adapter_info);
> +
> + D(fprintf(stderr, "adl initialized, %d displays\n", adl->displays_count));
> +
> + adl->initialized = 1;
> + return 1;
> +}
> +
> +void amd_adl_free()
> +{
> + if (!adl)
> + return;
> +
> + adl->ADL_Main_Control_Destroy();
> +
> + if (adl->lib){
> + dlclose(adl->lib);
> + adl->lib = NULL;
> + }
> +
> + adl_free((void**)&adl);
> +}
> +
> +#endif /* HAVE_AMDADL */
> +
> diff --git a/src/lib/amd_adl.h b/src/lib/amd_adl.h
> new file mode 100644
> index 0000000..d6c7bc1
> --- /dev/null
> +++ b/src/lib/amd_adl.h
> @@ -0,0 +1,33 @@
> +/*
> + ddc/ci interface functions header
> + Copyright(c) 2012 Vitaly V. Bursov (vi...@bu...)
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 2 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, write to the Free Software
> + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> +*/
> +
> +#ifndef AMD_ADL_H
> +#define AMD_ADL_H
> +
> +int amd_adl_init();
> +void amd_adl_free();
> +
> +int amd_adl_get_displays_count();
> +int amd_adl_get_display(int idx, int *adapter, int *display);
> +int amd_adl_check_display(int adapter, int display);
> +
> +int amd_adl_i2c_read(int adapter, int display, unsigned int addr, unsigned char *buf, unsigned int len);
> +int amd_adl_i2c_write(int adapter, int display, unsigned int addr, unsigned char *buf, unsigned int len);
> +
> +#endif /* AMD_ADL_H */
> diff --git a/src/lib/ddcci.c b/src/lib/ddcci.c
> index 4492df5..186d597 100644
> --- a/src/lib/ddcci.c
> +++ b/src/lib/ddcci.c
> @@ -38,6 +38,7 @@
> #include <sys/stat.h>
>
> #include "ddcci.h"
> +#include "amd_adl.h"
>
> #include "conf.h"
>
> @@ -239,12 +240,22 @@ int ddcci_init(char* usedatadir)
> printf(_("Failed to initialize ddccontrol database...\n"));
> return 0;
> }
> +#ifdef HAVE_AMDADL
> + if (!amd_adl_init()){
> + if (verbosity) {
> + printf(_("Failed to initialize ADL...\n"));
> + }
> + }
> +#endif
> return ddcpci_init();
> }
>
> void ddcci_release() {
> ddcpci_release();
> ddcci_release_db();
> +#ifdef HAVE_AMDADL
> + amd_adl_free();
> +#endif
> }
>
> /* write len bytes (stored in buf) to i2c address addr */
> @@ -318,6 +329,12 @@ static int i2c_write(struct monitor* mon, unsigned int addr, unsigned char *buf,
> return adata.status;
> }
> #endif
> +#ifdef HAVE_AMDADL
> + case type_adl:
> + {
> + return amd_adl_i2c_write(mon->adl_adapter, mon->adl_display, addr, buf, len);
> + }
> +#endif
> default:
> return -1;
> }
> @@ -396,6 +413,12 @@ static int i2c_read(struct monitor* mon, unsigned int addr, unsigned char *buf,
> return ret - ANSWER_SIZE;
> }
> #endif
> +#ifdef HAVE_AMDADL
> + case type_adl:
> + {
> + return amd_adl_i2c_read(mon->adl_adapter, mon->adl_display, addr, buf, len);
> + }
> +#endif
> default:
> return -1;
> }
> @@ -929,6 +952,23 @@ static int ddcci_open_with_addr(struct monitor* mon, const char* filename, int a
> mon->type = pci;
> }
> #endif
> +#ifdef HAVE_AMDADL
> + else if (strncmp(filename, "adl:", 4) == 0) {
> + mon->adl_adapter = -1;
> + mon->adl_display = -1;
> + if (sscanf(filename, "adl:%d:%d", &mon->adl_adapter, &mon->adl_display) != 2){
> + fprintf(stderr, _("Invalid filename (%s).\n"), filename);
> + return -3;
> + }
> +
> + if (amd_adl_check_display(mon->adl_adapter, mon->adl_display)){
> + fprintf(stderr, _("ADL display not found (%s).\n"), filename);
> + return -3;
> + }
> +
> + mon->type = type_adl;
> + }
> +#endif
> else {
> fprintf(stderr, _("Invalid filename (%s).\n"), filename);
> return -3;
> @@ -1167,6 +1207,28 @@ struct monitorlist* ddcci_probe() {
>
> closedir(dirp);
>
> +#ifdef HAVE_AMDADL
> + /* ADL probe */
> + int adl_disp;
> +
> + for (adl_disp=0; adl_disp<amd_adl_get_displays_count(); adl_disp++){
> + int adapter, display;
> + if (amd_adl_get_display(adl_disp, &adapter, &display))
> + break;
> +
> + filename = malloc(64);
> + snprintf(filename, 64, "adl:%d:%d", adapter, display);
> + if (verbosity) {
> + printf(_("Found ADL display (%s)\n"), filename);
> + }
> + ddcci_probe_device(filename, ¤t, &last);
> + if (!verbosity) {
> + printf(".");
> + fflush(stdout);
> + }
> + }
> +#endif
> +
> if (!verbosity)
> printf("\n");
>
> diff --git a/src/lib/ddcci.h b/src/lib/ddcci.h
> index c058051..cac907b 100644
> --- a/src/lib/ddcci.h
> +++ b/src/lib/ddcci.h
> @@ -63,6 +63,9 @@ struct caps {
> struct monitor {
> int fd;
> unsigned int addr;
> +#ifdef HAVE_AMDADL
> + int adl_adapter, adl_display;
> +#endif
> char pnpid[8];
> unsigned char digital; /* 0 - digital, 1 - analog */
> struct timeval last;
> @@ -76,6 +79,9 @@ struct monitor {
> #ifdef HAVE_DDCPCI
> ,pci
> #endif
> +#ifdef HAVE_AMDADL
> + ,type_adl
> +#endif
> } type;
> int probing; /* are we probing? */
>
>
> ------------------------------------------------------------------------------
> LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
> Remotely access PCs and mobile devices and provide instant support
> Improve your efficiency, and focus on delivering more value-add services
> Discover what IT Professionals Know. Rescue delivers
> http://p.sf.net/sfu/logmein_12329d2d
> _______________________________________________
> ddccontrol-devel mailing list
> ddc...@li...
> https://lists.sourceforge.net/lists/listinfo/ddccontrol-devel
>
|