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 > |