Logo Search packages:      
Sourcecode: libgphoto2 version File versions

config.c

/* config.c
 *
 * Copyright (C) 2003-2007 Marcus Meissner <marcus@jet.franken.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#define _BSD_SOURCE
#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

#include <gphoto2/gphoto2-library.h>
#include <gphoto2/gphoto2-port-log.h>
#include <gphoto2/gphoto2-setting.h>

#ifdef ENABLE_NLS
#  include <libintl.h>
#  undef _
#  define _(String) dgettext (GETTEXT_PACKAGE, String)
#  ifdef gettext_noop
#    define N_(String) gettext_noop (String)
#  else
#    define N_(String) (String)
#  endif
#else
#  define textdomain(String) (String)
#  define gettext(String) (String)
#  define dgettext(Domain,Message) (Message)
#  define dcgettext(Domain,Message,Type) (Message)
#  define bindtextdomain(Domain,Directory) (Domain)
#  define _(String) (String)
#  define N_(String) (String)
#endif

#include "ptp.h"
#include "ptp-bugs.h"
#include "ptp-private.h"

#define GP_MODULE "PTP2"

#define CPR(context,result) {short r=(result); if (r!=PTP_RC_OK) {report_result ((context), r, params->deviceinfo.VendorExtensionID); return (translate_ptp_result (r));}}

static int
camera_prepare_canon_powershot_capture(Camera *camera, GPContext *context) {
      PTPUSBEventContainer    event;
      PTPContainer            evc;
      PTPPropertyValue  propval;
      uint16_t          val16;
      int               i, ret, isevent;
      PTPParams         *params = &camera->pl->params;
      int oldtimeout;

      propval.u16 = 0;
      ret = ptp_getdevicepropvalue(params, PTP_DPC_CANON_EventEmulateMode, &propval, PTP_DTC_UINT16);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_DEBUG, "ptp", "failed get 0xd045\n");
            return GP_ERROR;
      }
      gp_log (GP_LOG_DEBUG, "ptp","prop 0xd045 value is 0x%4X\n",propval.u16);

      propval.u16=1;
      ret = ptp_setdevicepropvalue(params, PTP_DPC_CANON_EventEmulateMode, &propval, PTP_DTC_UINT16);
      ret = ptp_getdevicepropvalue(params, PTP_DPC_CANON_SizeOfOutputDataFromCamera, &propval, PTP_DTC_UINT32);
      gp_log (GP_LOG_DEBUG, "ptp", "prop PTP_DPC_CANON_SizeOfOutputDataFromCamera value is 0x%8X, ret %d\n",propval.u32, ret);
      ret = ptp_getdevicepropvalue(params, PTP_DPC_CANON_SizeOfInputDataToCamera, &propval, PTP_DTC_UINT32);
      gp_log (GP_LOG_DEBUG, "ptp", "prop PTP_DPC_CANON_SizeOfInputDataToCamera value is 0x%8X, ret %d\n",propval.u32, ret);

      ret = ptp_getdeviceinfo (params, &params->deviceinfo);
      ret = ptp_getdeviceinfo (params, &params->deviceinfo);

      ret = ptp_getdevicepropvalue(params, PTP_DPC_CANON_SizeOfOutputDataFromCamera, &propval, PTP_DTC_UINT32);
      gp_log (GP_LOG_DEBUG, "ptp", "prop PTP_DPC_CANON_SizeOfOutputDataFromCamera value is 0x%8x, ret %d\n",propval.u32, ret);
      ret = ptp_getdevicepropvalue(params, PTP_DPC_CANON_SizeOfInputDataToCamera, &propval, PTP_DTC_UINT32);
      gp_log (GP_LOG_DEBUG, "ptp", "prop PTP_DPC_CANON_SizeOfInputDataToCamera value is 0x%8X, ret %d\n",propval.u32,ret);
      ret = ptp_getdeviceinfo (params, &params->deviceinfo);
      ret = ptp_getdevicepropvalue(params, PTP_DPC_CANON_EventEmulateMode, &propval, PTP_DTC_UINT16);
      gp_log (GP_LOG_DEBUG, "ptp","prop 0xd045 value is 0x%4x, ret %d\n",propval.u16,ret);

      gp_log (GP_LOG_DEBUG, "ptp","Magic code ends.\n");

      gp_log (GP_LOG_DEBUG, "ptp","Setting prop. EventEmulateMode to 4\n");
      propval.u16=4;
      ret = ptp_setdevicepropvalue(params, PTP_DPC_CANON_EventEmulateMode, &propval, PTP_DTC_UINT16);

      CPR (context, ptp_canon_startshootingmode (params));

      gp_port_get_timeout (camera->port, &oldtimeout);
      gp_port_set_timeout (camera->port, 1000);

      /* Catch event */
      if (PTP_RC_OK==(val16=params->event_wait (params, &evc))) {
            if (evc.Code==PTP_EC_StorageInfoChanged)
                  gp_log (GP_LOG_DEBUG, "ptp", "Event: entering  shooting mode. \n");
            else 
                  gp_log (GP_LOG_DEBUG, "ptp", "Event: 0x%X\n", evc.Code);
      } else {
            printf("No event yet, we'll try later.\n");
      }

      /* Emptying event stack */
      for (i=0;i<2;i++) {
            ret = ptp_canon_checkevent (params,&event,&isevent);
            if (ret != PTP_RC_OK) {
                  gp_log (GP_LOG_DEBUG, "ptp", "error during check event: %d\n", ret);
            }
            if (isevent)
                  gp_log (GP_LOG_DEBUG, "ptp", "evdata: L=0x%X, T=0x%X, C=0x%X, trans_id=0x%X, p1=0x%X, p2=0x%X, p3=0x%X\n",
                        event.length,event.type,event.code,event.trans_id,
                        event.param1, event.param2, event.param3);
      }
      /* Catch event, attempt  2 */
      if (val16!=PTP_RC_OK) {
            if (PTP_RC_OK==params->event_wait (params, &evc)) {
                  if (evc.Code == PTP_EC_StorageInfoChanged)
                        gp_log (GP_LOG_DEBUG, "ptp","Event: entering shooting mode.\n");
                  else
                        gp_log (GP_LOG_DEBUG, "ptp","Event: 0x%X\n", evc.Code);
            } else
                  gp_log (GP_LOG_DEBUG, "ptp", "No expected mode change event.\n");
      }
      /* Reget device info, they change on the Canons. */
      ptp_getdeviceinfo(&camera->pl->params, &camera->pl->params.deviceinfo);
      gp_port_set_timeout (camera->port, oldtimeout);
      return GP_OK;
}

static int
camera_prepare_canon_eos_capture(Camera *camera, GPContext *context) {
      PTPParams         *params = &camera->pl->params;
      uint16_t          ret;
      PTPCanon_changes_entry  *entries = NULL;
      int               nrofentries = 0;
      unsigned char           startup9110[12];

      ret = ptp_canon_eos_setremotemode(params, 1);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9115 failed!");
            return GP_ERROR;
      }
      ret = ptp_canon_eos_seteventmode(params, 1);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9114 failed!");
            return GP_ERROR;
      }
      /* Get the initial bulk set of 0x9116 property data */
      while (1) {
            ret = ptp_canon_eos_getevent (params, &entries, &nrofentries);
            if (ret != PTP_RC_OK) {
                  gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9116 failed!");
                  return GP_ERROR;
            }
            if (nrofentries == 0)
                  break;
            free (entries);
            nrofentries = 0;
            entries = NULL;
      }
      ret = ptp_canon_eos_pchddcapacity(params, 0x7fffffff, 0x00001000, 0x00000001);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "911A failed!");
            return GP_ERROR;
      }
      startup9110[0] = 0x0c; startup9110[1] = 0x00; startup9110[2] = 0x00; startup9110[3] = 0x00;
      startup9110[4] = 0x1c; startup9110[5] = 0xd1; startup9110[6] = 0x00; startup9110[7] = 0x00;
      startup9110[8] = 0x01; startup9110[9] = 0x00; startup9110[10] = 0x00; startup9110[11] = 0x00;
      ret = ptp_canon_eos_setdevicepropvalueex (params, startup9110, 12);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9110 of d11c to 1 failed!");
            return GP_ERROR;
      }
      ret = ptp_getdeviceinfo(&camera->pl->params, &camera->pl->params.deviceinfo);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "getdeviceinfo failed!");
            return GP_ERROR;
      }
      ret = ptp_canon_eos_getstorageids(params);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9101 failed!");
            return GP_ERROR;
      }
      ret = ptp_canon_eos_getstorageinfo(params, 1);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9102 failed!");
            return GP_ERROR;
      }
      ret = ptp_canon_eos_getstorageids(params);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9101 failed!");
            return GP_ERROR;
      }
      ret = ptp_canon_eos_getstorageinfo(params, 1);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9102 failed!");
            return GP_ERROR;
      }
      /* just exchange the value to 4 */
      startup9110[8] = 0x04; startup9110[9] = 0x00; startup9110[10] = 0x00; startup9110[11] = 0x00;
      ret = ptp_canon_eos_setdevicepropvalueex (params, startup9110, 12);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9110 of d11c to 4 failed!");
            return GP_ERROR;
      }
      ret = ptp_canon_eos_pchddcapacity (params, 0x001dfc60, 0x1000, 0x1);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "911a to 0x001dfc60 failed!");
            return GP_ERROR;
      }

      /* FIXME: 9114 call missing here! */

      /* Get the second bulk set of 0x9116 property data */
      while (1) {
            ret = ptp_canon_eos_getevent (params, &entries, &nrofentries);
            if (ret != PTP_RC_OK) {
                  gp_log (GP_LOG_ERROR,"ptp2_prepare_eos_capture", "9116 failed!");
                  return GP_ERROR;
            }
            if (nrofentries == 0)
                  break;
            free (entries);
            nrofentries = 0;
            entries = NULL;
      }
      return GP_OK;
}

int
camera_prepare_capture (Camera *camera, GPContext *context)
{
      PTPParams         *params = &camera->pl->params;
      
      gp_log (GP_LOG_DEBUG, "ptp", "prepare_capture\n");
      switch (params->deviceinfo.VendorExtensionID) {
      case PTP_VENDOR_CANON:
            if (ptp_operation_issupported(params, PTP_OC_CANON_InitiateReleaseControl))
                  return camera_prepare_canon_powershot_capture(camera,context);

            if (ptp_operation_issupported(params, PTP_OC_CANON_EOS_RemoteRelease))
                  return camera_prepare_canon_eos_capture(camera,context);
            gp_context_error(context, _("Sorry, your Canon camera does not support Canon capture"));
            return GP_ERROR_NOT_SUPPORTED;
      default:
            /* generic capture does not need preparation */
            return GP_OK;
      }
      return GP_OK;
}

static int
camera_unprepare_canon_powershot_capture(Camera *camera, GPContext *context) {
      uint16_t    ret;

      ret = ptp_canon_endshootingmode (&camera->pl->params);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_DEBUG, "ptp", "end shooting mode error %d\n", ret);
            return GP_ERROR;
      }
      /* Reget device info, they change on the Canons. */
      ptp_getdeviceinfo(&camera->pl->params, &camera->pl->params.deviceinfo);
      return GP_OK;
}

static int
camera_unprepare_canon_eos_capture(Camera *camera, GPContext *context) {
      PTPParams         *params = &camera->pl->params;
      uint16_t          ret;
      PTPCanon_changes_entry  *entries = NULL;
      int               nrofentries = 0;
      unsigned char           startup9110[12];

      ret = ptp_canon_eos_pchddcapacity(params, 0xffffef40, 0x00001000, 0x00000001);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_unprepare_eos_capture", "911A to 0xffffef40 failed!");
            return GP_ERROR;
      }

      /* then emits 911b and 911c ... not done yet ... */

      startup9110[0] = 0x0c; startup9110[1] = 0x00; startup9110[2] = 0x00; startup9110[3] = 0x00;
      startup9110[4] = 0x1c; startup9110[5] = 0xd1; startup9110[6] = 0x00; startup9110[7] = 0x00;
      startup9110[8] = 0x01; startup9110[9] = 0x00; startup9110[10] = 0x00; startup9110[11] = 0x00;
      ret = ptp_canon_eos_setdevicepropvalueex (params, startup9110, 12);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_unprepare_eos_capture", "9110 of d11c to 1 failed!");
            return GP_ERROR;
      }

      /* Drain the rest set of the 0x9116 property data */
      while (1) {
            ret = ptp_canon_eos_getevent (params, &entries, &nrofentries);
            if (ret != PTP_RC_OK) {
                  gp_log (GP_LOG_ERROR,"ptp2_unprepare_eos_capture", "9116 failed!");
                  return GP_ERROR;
            }
            if (nrofentries == 0)
                  break;
            free (entries);
            nrofentries = 0;
            entries = NULL;
      }

      ret = ptp_canon_eos_setremotemode(params, 0);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_unprepare_eos_capture", "9115 failed!");
            return GP_ERROR;
      }
      ret = ptp_canon_eos_seteventmode(params, 0);
      if (ret != PTP_RC_OK) {
            gp_log (GP_LOG_ERROR,"ptp2_unprepare_eos_capture", "9114 failed!");
            return GP_ERROR;
      }
      return GP_OK;
}

int
camera_unprepare_capture (Camera *camera, GPContext *context)
{
      gp_log (GP_LOG_DEBUG, "ptp", "Unprepare_capture\n");
      switch (camera->pl->params.deviceinfo.VendorExtensionID) {
      case PTP_VENDOR_CANON:
            if (ptp_operation_issupported(&camera->pl->params, PTP_OC_CANON_TerminateReleaseControl))
                  return camera_unprepare_canon_powershot_capture (camera, context);

            if (ptp_operation_issupported(&camera->pl->params, PTP_OC_CANON_EOS_RemoteRelease))
                  return camera_unprepare_canon_eos_capture (camera, context);

            gp_context_error(context,
            _("Sorry, your Canon camera does not support Canon capture"));
            return GP_ERROR_NOT_SUPPORTED;
      default:
            /* generic capture does not need unpreparation */
            return GP_OK;
      }
      return GP_OK;
}


static int
have_prop(Camera *camera, uint16_t vendor, uint16_t prop) {
      int i;

      /* prop 0 matches */
      if (!prop && (camera->pl->params.deviceinfo.VendorExtensionID==vendor))
            return 1;

      for (i=0; i<camera->pl->params.deviceinfo.DevicePropertiesSupported_len; i++) {
            if (prop != camera->pl->params.deviceinfo.DevicePropertiesSupported[i])
                  continue;
            if ((prop & 0xf000) == 0x5000) /* generic property */
                  return 1;
            if (camera->pl->params.deviceinfo.VendorExtensionID==vendor)
                  return 1;
      }
      return 0;
}

static int
have_eos_prop(Camera *camera, uint16_t vendor, uint16_t prop) {
      int i;

      /* The special Canon EOS property set gets special treatment. */
        if ((camera->pl->params.deviceinfo.VendorExtensionID != PTP_VENDOR_CANON) ||
          (vendor != PTP_VENDOR_CANON)
      )
            return 0;
      for (i=0;i<camera->pl->params.nrofcanon_props;i++)
            if (camera->pl->params.canon_props[i].proptype == prop)
                  return 1;
      return 0;
}

struct submenu;
#define CONFIG_GET_ARGS Camera *camera, CameraWidget **widget, struct submenu* menu, PTPDevicePropDesc *dpd
#define CONFIG_GET_NAMES camera, widget, menu, dpd
typedef int (*get_func)(CONFIG_GET_ARGS);
#define CONFIG_PUT_ARGS Camera *camera, CameraWidget *widget, PTPPropertyValue *propval, PTPDevicePropDesc *dpd
#define CONFIG_PUT_NAMES camera, widget, propval, dpd
typedef int (*put_func)(CONFIG_PUT_ARGS);

struct menu;
#define CONFIG_MENU_GET_ARGS Camera *camera, CameraWidget **widget, struct menu* menu
typedef int (*get_menu_func)(CONFIG_MENU_GET_ARGS);
#define CONFIG_MENU_PUT_ARGS Camera *camera, CameraWidget *widget
typedef int (*put_menu_func)(CONFIG_MENU_PUT_ARGS);

struct submenu {
      char        *label;
      char        *name;
      uint16_t    propid;
      uint16_t    vendorid;
      uint32_t    type; /* for 32bit alignment */
      get_func    getfunc;
      put_func    putfunc;
};

struct menu {
      char        *label;
      char        *name;
      /* Either: Standard menu */
      struct      submenu     *submenus;
      /* Or: Non-standard menu with custom behaviour */
      get_menu_func     getfunc;
      put_menu_func     putfunc;
};

struct deviceproptableu8 {
      char        *label;
      uint8_t           value;
      uint16_t    vendor_id;
};

struct deviceproptableu16 {
      char        *label;
      uint16_t    value;
      uint16_t    vendor_id;
};

/* Generic helper function for:
 *
 * ENUM UINT16 propertiess, with potential vendor specific variables.
 */
static int
_get_Generic16Table(CONFIG_GET_ARGS, struct deviceproptableu16* tbl, int tblsize) {
      int i, j;

      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_UINT16)
            return (GP_ERROR);
      if (!dpd->FORM.Enum.NumberOfValues) {
            /* fill in with all values we have in the table. */
            for (j=0;j<tblsize;j++) {
                  if ((tbl[j].vendor_id == 0) ||
                      (tbl[j].vendor_id == camera->pl->params.deviceinfo.VendorExtensionID)
                  ) {
                        gp_widget_add_choice (*widget, _(tbl[j].label));
                        if (tbl[j].value == dpd->CurrentValue.u16)
                              gp_widget_set_value (*widget, _(tbl[j].label));
                  }
            }
            return GP_OK;
      }
      for (i = 0; i<dpd->FORM.Enum.NumberOfValues; i++) {
            int isset = FALSE;

            for (j=0;j<tblsize;j++) {
                  if ((tbl[j].value == dpd->FORM.Enum.SupportedValue[i].u16) &&
                      ((tbl[j].vendor_id == 0) ||
                       (tbl[j].vendor_id == camera->pl->params.deviceinfo.VendorExtensionID))
                  ) {
                        gp_widget_add_choice (*widget, _(tbl[j].label));
                        if (tbl[j].value == dpd->CurrentValue.u16)
                              gp_widget_set_value (*widget, _(tbl[j].label));
                        isset = TRUE;
                        break;
                  }
            }
            if (!isset) {
                  char buf[200];
                  sprintf(buf, _("Unknown value %04x"), dpd->FORM.Enum.SupportedValue[i].u16);
                  gp_widget_add_choice (*widget, buf);
                  if (dpd->FORM.Enum.SupportedValue[i].u16 == dpd->CurrentValue.u16)
                        gp_widget_set_value (*widget, buf);
            }
      }
      return (GP_OK);
}


static int
_put_Generic16Table(CONFIG_PUT_ARGS, struct deviceproptableu16* tbl, int tblsize) {
      char *value;
      int i, ret, intval;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;
      for (i=0;i<tblsize;i++) {
            if (!strcmp(_(tbl[i].label),value) &&
                ((tbl[i].vendor_id == 0) || (tbl[i].vendor_id == camera->pl->params.deviceinfo.VendorExtensionID))
            ) {
                  propval->u16 = tbl[i].value;
                  gp_log (GP_LOG_DEBUG, "ptp2/config:g16tbl", "returning %d for %s", propval->u16, value);
                  return GP_OK;
            }
      }
      if (!sscanf(value, _("Unknown value %04x"), &intval)) {
            gp_log (GP_LOG_ERROR, "ptp2/config", "failed to find value %s in list", value);
            return (GP_ERROR);
      }
      propval->u16 = intval;
      gp_log (GP_LOG_DEBUG, "ptp2/config:g16tbl", "returning %d for %s", propval->u16, value);
      return GP_OK;
}

#define GENERIC16TABLE(name,tbl)                \
static int                                \
_get_##name(CONFIG_GET_ARGS) {                        \
      return _get_Generic16Table(CONFIG_GET_NAMES,    \
            tbl,sizeof(tbl)/sizeof(tbl[0])            \
      );                                  \
}                                         \
                                          \
static int                                \
_put_##name(CONFIG_PUT_ARGS) {                        \
      return _put_Generic16Table(CONFIG_PUT_NAMES,    \
            tbl,sizeof(tbl)/sizeof(tbl[0])            \
      );                                  \
}

static int
_get_Generic8Table(CONFIG_GET_ARGS, struct deviceproptableu8* tbl, int tblsize) {
      int i, j;

      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (dpd->FormFlag & PTP_DPFF_Enumeration) {
            if (dpd->DataType != PTP_DTC_UINT8)
                  return (GP_ERROR);
            for (i = 0; i<dpd->FORM.Enum.NumberOfValues; i++) {
                  int isset = FALSE;

                  for (j=0;j<tblsize;j++) {
                        if ((tbl[j].value == dpd->FORM.Enum.SupportedValue[i].u8) &&
                            ((tbl[j].vendor_id == 0) ||
                             (tbl[j].vendor_id == camera->pl->params.deviceinfo.VendorExtensionID))
                        ) {
                              gp_widget_add_choice (*widget, _(tbl[j].label));
                              if (tbl[j].value == dpd->CurrentValue.u8)
                                    gp_widget_set_value (*widget, _(tbl[j].label));
                              isset = TRUE;
                              break;
                        }
                  }
                  if (!isset) {
                        char buf[200];
                        sprintf(buf, _("Unknown value %04x"), dpd->FORM.Enum.SupportedValue[i].u8);
                        gp_widget_add_choice (*widget, buf);
                        if (dpd->FORM.Enum.SupportedValue[i].u8 == dpd->CurrentValue.u8)
                              gp_widget_set_value (*widget, buf);
                  }
            }
            return (GP_OK);
      }
      if (dpd->FormFlag & PTP_DPFF_Range) {
            if (dpd->DataType != PTP_DTC_UINT8)
                  return (GP_ERROR);
            for ( i = dpd->FORM.Range.MinimumValue.u8;
                  i <= dpd->FORM.Range.MaximumValue.u8;
                  i+= dpd->FORM.Range.StepSize.u8
            ) {
                  int isset = FALSE;

                  for (j=0;j<tblsize;j++) {
                        if ((tbl[j].value == i) &&
                            ((tbl[j].vendor_id == 0) ||
                             (tbl[j].vendor_id == camera->pl->params.deviceinfo.VendorExtensionID))
                        ) {
                              gp_widget_add_choice (*widget, _(tbl[j].label));
                              if (tbl[j].value == dpd->CurrentValue.u8)
                                    gp_widget_set_value (*widget, _(tbl[j].label));
                              isset = TRUE;
                              break;
                        }
                  }
                  if (!isset) {
                        char buf[200];
                        sprintf(buf, _("Unknown value %04x"), dpd->FORM.Range.MaximumValue.u8);
                        gp_widget_add_choice (*widget, buf);
                        if (dpd->FORM.Range.MaximumValue.u8 == dpd->CurrentValue.u8)
                              gp_widget_set_value (*widget, buf);
                  }
            }
            return (GP_OK);
      }
      return (GP_ERROR);
}


static int
_put_Generic8Table(CONFIG_PUT_ARGS, struct deviceproptableu8* tbl, int tblsize) {
      char *value;
      int i, ret, intval;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;
      for (i=0;i<tblsize;i++) {
            if (!strcmp(_(tbl[i].label),value) &&
                ((tbl[i].vendor_id == 0) || (tbl[i].vendor_id == camera->pl->params.deviceinfo.VendorExtensionID))
            ) {
                  propval->u8 = tbl[i].value;
                  return GP_OK;
            }
      }
      if (!sscanf(value, _("Unknown value %04x"), &intval))
            return (GP_ERROR);
      propval->u8 = intval;
      return GP_OK;
}

#define GENERIC8TABLE(name,tbl)                 \
static int                                \
_get_##name(CONFIG_GET_ARGS) {                        \
      return _get_Generic8Table(CONFIG_GET_NAMES,     \
            tbl,sizeof(tbl)/sizeof(tbl[0])            \
      );                                  \
}                                         \
                                          \
static int                                \
_put_##name(CONFIG_PUT_ARGS) {                        \
      return _put_Generic8Table(CONFIG_PUT_NAMES,     \
            tbl,sizeof(tbl)/sizeof(tbl[0])            \
      );                                  \
}

static int
_get_AUINT8_as_CHAR_ARRAY(CONFIG_GET_ARGS) {
      int   j;
      char  value[128];

      gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (dpd->DataType != PTP_DTC_AUINT8) {
            sprintf (value,_("unexpected datatype %i"),dpd->DataType);
      } else {
            memset(value,0,sizeof(value));
            for (j=0;j<dpd->CurrentValue.a.count;j++)
                  value[j] = dpd->CurrentValue.a.v[j].u8;
      }
      gp_widget_set_value (*widget,value);
      return (GP_OK);
}

static int
_get_STR(CONFIG_GET_ARGS) {
      char value[64];

      gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (dpd->DataType != PTP_DTC_STR) {
            sprintf (value,_("unexpected datatype %i"),dpd->DataType);
            gp_widget_set_value (*widget,value);
      } else {
            gp_widget_set_value (*widget,dpd->CurrentValue.str);
      }
      return (GP_OK);
}

static int
_put_STR(CONFIG_PUT_ARGS) {
        const char *string;
        int ret;
        ret = gp_widget_get_value (widget,&string);
        if (ret != GP_OK)
                return ret;
        propval->str = strdup (string);
      if (!propval->str)
            return (GP_ERROR_NO_MEMORY);
        return (GP_OK);
}

static int
_put_AUINT8_as_CHAR_ARRAY(CONFIG_PUT_ARGS) {
      char  *value;
      int   i, ret;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;
      memset(propval,0,sizeof(PTPPropertyValue));
      /* add \0 ? */
      propval->a.v = malloc((strlen(value)+1)*sizeof(PTPPropertyValue));
      if (!propval->a.v)
            return (GP_ERROR_NO_MEMORY);
      propval->a.count = strlen(value)+1;
      for (i=0;i<strlen(value)+1;i++)
            propval->a.v[i].u8 = value[i];
      return (GP_OK);
}

#if 0
static int
_get_Range_INT8(CONFIG_GET_ARGS) {
      float CurrentValue;
      
      gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
      gp_widget_set_name ( *widget, menu->name);
      if (dpd->FormFlag != PTP_DPFF_Range)
            return (GP_ERROR_NOT_SUPPORTED);
      if (dpd->DataType != PTP_DTC_INT8)
            return (GP_ERROR_NOT_SUPPORTED);
      CurrentValue = (float) dpd->CurrentValue.i8;
      gp_widget_set_range ( *widget, (float) dpd->FORM.Range.MinimumValue.i8, (float) dpd->FORM.Range.MaximumValue.i8, (float) dpd->FORM.Range.StepSize.i8);
      gp_widget_set_value ( *widget, &CurrentValue);
      return (GP_OK);
}


static int
_put_Range_INT8(CONFIG_PUT_ARGS) {
      int ret;
      float f;
      ret = gp_widget_get_value (widget, &f);
      if (ret != GP_OK) 
            return ret;
      propval->i8 = (int) f;
      return (GP_OK);
}
#endif

static int
_get_Nikon_OnOff_UINT8(CONFIG_GET_ARGS) {
      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name ( *widget, menu->name);
      if (dpd->FormFlag != PTP_DPFF_Range)
                return (GP_ERROR_NOT_SUPPORTED);
        if (dpd->DataType != PTP_DTC_UINT8)
                return (GP_ERROR_NOT_SUPPORTED);
      gp_widget_add_choice (*widget,_("On"));
      gp_widget_add_choice (*widget,_("Off"));
      gp_widget_set_value ( *widget, (dpd->CurrentValue.u8?_("On"):_("Off")));
      return (GP_OK);
}

static int
_put_Nikon_OnOff_UINT8(CONFIG_PUT_ARGS) {
      int ret;
      char *value;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK) 
            return ret;
      if(!strcmp(value,_("On"))) {
            propval->u8 = 1;
            return (GP_OK);
      }
      if(!strcmp(value,_("Off"))) {
            propval->u8 = 0;
            return (GP_OK);
      }
      return (GP_ERROR);
}

static int
_get_CANON_FirmwareVersion(CONFIG_GET_ARGS) {
      char value[64];

      gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (dpd->DataType != PTP_DTC_UINT32) {
            sprintf (value,_("unexpected datatype %i"),dpd->DataType);
      } else {
            uint32_t x = dpd->CurrentValue.u32;
            sprintf (value,"%d.%d.%d.%d",((x&0xff000000)>>24),((x&0xff0000)>>16),((x&0xff00)>>8),x&0xff);
      }
      gp_widget_set_value (*widget,value);
      return (GP_OK);
}

static struct deviceproptableu16 whitebalance[] = {
      { N_("Manual"),               0x0001, 0 },
      { N_("Automatic"),            0x0002, 0 },
      { N_("One-push Automatic"),   0x0003, 0 },
      { N_("Daylight"),       0x0004, 0 },
      { N_("Fluorescent"),          0x0005, 0 },
      { N_("Tungsten"),       0x0006, 0 },
      { N_("Flash"),                0x0007, 0 },
      { N_("Cloudy"),               0x8010, PTP_VENDOR_NIKON },
      { N_("Shade"),                0x8011, PTP_VENDOR_NIKON },
      { N_("Color Temperature"),    0x8012, PTP_VENDOR_NIKON },
      { N_("Preset"),               0x8013, PTP_VENDOR_NIKON },
};
GENERIC16TABLE(WhiteBalance,whitebalance)


/* Everything is camera specific. */
static struct deviceproptableu8 compression[] = {
      { N_("JPEG Basic"),     0x00, PTP_VENDOR_NIKON },
      { N_("JPEG Normal"),    0x01, PTP_VENDOR_NIKON },
      { N_("JPEG Fine"),      0x02, PTP_VENDOR_NIKON },
      { N_("NEF (Raw)"),      0x03, PTP_VENDOR_NIKON },
      { N_("NEF+Basic"),      0x04, PTP_VENDOR_NIKON },
      { N_("NEF+Normal"),     0x05, PTP_VENDOR_NIKON },
      { N_("NEF+Fine"), 0x06, PTP_VENDOR_NIKON },
};
GENERIC8TABLE(Compression,compression)


static int
_get_ImageSize(CONFIG_GET_ARGS) {
        int j;

        gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
        gp_widget_set_name (*widget, menu->name);
        if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
                return(GP_ERROR);
        if (dpd->DataType != PTP_DTC_STR)
                return(GP_ERROR);
        for (j=0;j<dpd->FORM.Enum.NumberOfValues; j++) {
                gp_widget_add_choice (*widget,dpd->FORM.Enum.SupportedValue[j].str);
        }
        gp_widget_set_value (*widget,dpd->CurrentValue.str);
        return GP_OK;
}

static int
_put_ImageSize(CONFIG_PUT_ARGS) {
        char *value;
        int ret;

        ret = gp_widget_get_value (widget,&value);
        if(ret != GP_OK)
                return ret;
        propval->str = strdup (value);
      if (!propval->str)
            return (GP_ERROR_NO_MEMORY);
        return(GP_OK);
}


static int
_get_ExpCompensation(CONFIG_GET_ARGS) {
        int j;
      char buf[10];

        gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
        gp_widget_set_name (*widget, menu->name);
        if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
                return(GP_ERROR);
        if (dpd->DataType != PTP_DTC_INT16)
                return(GP_ERROR);
        for (j=0;j<dpd->FORM.Enum.NumberOfValues; j++) {
            sprintf(buf, "%d", dpd->FORM.Enum.SupportedValue[j].i16);
                gp_widget_add_choice (*widget,buf);
        }
      sprintf(buf, "%d", dpd->CurrentValue.i16);
        gp_widget_set_value (*widget,buf);
        return GP_OK;
}

static int
_put_ExpCompensation(CONFIG_PUT_ARGS) {
        char *value;
        int ret, x;

        ret = gp_widget_get_value (widget,&value);
        if(ret != GP_OK)
                return ret;
      if (1 != sscanf(value,"%d", &x))
            return (GP_ERROR);
        propval->i16 = x;
        return(GP_OK);
}


static int
_get_Canon_AssistLight(CONFIG_GET_ARGS) {
      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_UINT16)
            return (GP_ERROR);
      gp_widget_add_choice (*widget,_("On"));
      gp_widget_add_choice (*widget,_("Off"));
      gp_widget_set_value (*widget,(dpd->CurrentValue.u16?_("On"):_("Off")));
      return (GP_OK);
}

static int
_put_Canon_AssistLight(CONFIG_PUT_ARGS) {
      char *value;
      int ret;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;
      if (!strcmp (value, _("On"))) {
            propval->u16 = 1;
            return (GP_OK);
      }
      if (!strcmp (value, _("Off"))) {
            propval->u16 = 0;
            return (GP_OK);
      }
      return (GP_ERROR);
}

static int
_get_Canon_BeepMode(CONFIG_GET_ARGS) {
      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_UINT8)
            return (GP_ERROR);
      gp_widget_add_choice (*widget,_("On"));
      gp_widget_add_choice (*widget,_("Off"));
      gp_widget_set_value (*widget,(dpd->CurrentValue.u8?_("On"):_("Off")));
      return (GP_OK);
}

static int
_put_Canon_BeepMode(CONFIG_PUT_ARGS) {
      char *value;
      int ret;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;
      if (!strcmp (value, _("On"))) {
            propval->u8 = 1;
            return (GP_OK);
      }
      if (!strcmp (value, _("Off"))) {
            propval->u8 = 0;
            return (GP_OK);
      }
      return (GP_ERROR);
}

static int
_get_Canon_ZoomRange(CONFIG_GET_ARGS) {
      float f, t, b, s;

      gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
      gp_widget_set_name (*widget,menu->name);
      f = (float)dpd->CurrentValue.u16;
      if (!(dpd->FormFlag & PTP_DPFF_Range))
            return (GP_ERROR);
      b = (float)dpd->FORM.Range.MinimumValue.u16;
      t = (float)dpd->FORM.Range.MaximumValue.u16;
      s = (float)dpd->FORM.Range.StepSize.u16;
      gp_widget_set_range (*widget, b, t, s);
      gp_widget_set_value (*widget, &f);
      return (GP_OK);
}

static int
_put_Canon_ZoomRange(CONFIG_PUT_ARGS)
{
      float f;
      int   ret;

      f = 0.0;
      ret = gp_widget_get_value (widget,&f);
      if (ret != GP_OK) return ret;
      propval->u16 = (unsigned short)f;
      return (GP_OK);
}

static int
_get_Nikon_WBBias(CONFIG_GET_ARGS) {
      float f, t, b, s;

      if (dpd->DataType != PTP_DTC_INT8)
            return (GP_ERROR);
      if (!(dpd->FormFlag & PTP_DPFF_Range))
            return (GP_ERROR);
      gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
      gp_widget_set_name (*widget,menu->name);
      f = (float)dpd->CurrentValue.i8;
      b = (float)dpd->FORM.Range.MinimumValue.i8;
      t = (float)dpd->FORM.Range.MaximumValue.i8;
      s = (float)dpd->FORM.Range.StepSize.i8;
      gp_widget_set_range (*widget, b, t, s);
      gp_widget_set_value (*widget, &f);
      return (GP_OK);
}

static int
_put_Nikon_WBBias(CONFIG_PUT_ARGS)
{
      float f;
      int   ret;

      f = 0.0;
      ret = gp_widget_get_value (widget,&f);
      if (ret != GP_OK) return ret;
      propval->i8 = (signed char)f;
      return (GP_OK);
}

static int
_get_Nikon_HueAdjustment(CONFIG_GET_ARGS) {
      float f, t, b, s;

      if (dpd->DataType != PTP_DTC_INT8)
            return (GP_ERROR);
      if (dpd->FormFlag & PTP_DPFF_Range) {
            gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
            gp_widget_set_name (*widget,menu->name);
            f = (float)dpd->CurrentValue.i8;
            b = (float)dpd->FORM.Range.MinimumValue.i8;
            t = (float)dpd->FORM.Range.MaximumValue.i8;
            s = (float)dpd->FORM.Range.StepSize.i8;
            gp_widget_set_range (*widget, b, t, s);
            gp_widget_set_value (*widget, &f);
            return (GP_OK);
      }
      if (dpd->FormFlag & PTP_DPFF_Enumeration) {
            char buf[20];
            int i, isset = FALSE;

            gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
            gp_widget_set_name (*widget,menu->name);
            for (i = 0; i<dpd->FORM.Enum.NumberOfValues; i++) {

                  sprintf (buf, "%d", dpd->FORM.Enum.SupportedValue[i].i8);
                  gp_widget_add_choice (*widget, buf);
                  if (dpd->FORM.Enum.SupportedValue[i].i8 == dpd->CurrentValue.i8) {
                        gp_widget_set_value (*widget, buf);
                        isset = TRUE;
                  }
            }
            if (!isset) {
                  sprintf (buf, "%d", dpd->FORM.Enum.SupportedValue[0].i8);
                  gp_widget_set_value (*widget, buf);
            }
            return (GP_OK);
      }
      return (GP_ERROR);
}

static int
_put_Nikon_HueAdjustment(CONFIG_PUT_ARGS)
{
      int   ret;

      if (dpd->FormFlag & PTP_DPFF_Range) {
            float f = 0.0;
            ret = gp_widget_get_value (widget,&f);
            if (ret != GP_OK) return ret;
            propval->i8 = (signed char)f;
            return (GP_OK);
      }
      if (dpd->FormFlag & PTP_DPFF_Enumeration) {
            char *val;
            int ival;
            
            ret = gp_widget_get_value (widget, &val);
            if (ret != GP_OK) return ret;
            sscanf (val, "%d", &ival);
            propval->i8 = ival;
            return (GP_OK);
      }
      return (GP_ERROR);
}


static struct deviceproptableu8 canon_quality[] = {
      { N_("normal"),         0x02, 0 },
      { N_("fine"),           0x03, 0 },
      { N_("super fine"),     0x05, 0 },
};
GENERIC8TABLE(Canon_Quality,canon_quality)

static struct deviceproptableu8 canon_shootmode[] = {
      { N_("Auto"),           0x01, 0 },
      { N_("Tv"),       0x02, 0 },
      { N_("Av"),       0x03, 0 },
      { N_("Manual"),         0x04, 0 },
};
GENERIC8TABLE(Canon_ShootMode,canon_shootmode)

static struct deviceproptableu8 canon_flash[] = {
      { N_("off"),      0, 0 },
      { N_("auto"),     1, 0 },
      { N_("on"), 2, 0 },
      { N_("auto red eye"), 5, 0 },
      { N_("on red eye"), 6, 0 },
};
GENERIC8TABLE(Canon_FlashMode,canon_flash)

static struct deviceproptableu8 nikon_flashmode[] = {
      { N_("iTTL"),           0, 0 },
      { N_("Manual"),         1, 0 },
      { N_("Commander"),      2, 0 },
};
GENERIC8TABLE(Nikon_FlashMode,nikon_flashmode)

static struct deviceproptableu8 flash_modemanualpower[] = {
      { N_("Full"),     0x00, 0 },
      { "1/2",    0x01, 0 },
      { "1/4",    0x02, 0 },
      { "1/8",    0x03, 0 },
      { "1/16",   0x04, 0 },
};
GENERIC8TABLE(Nikon_FlashModeManualPower,flash_modemanualpower)

static struct deviceproptableu8 canon_meteringmode[] = {
      { "center weighted(?)", 0, 0 },
      { N_("spot"),           1, 0 },
      { "integral(?)",  3, 0 },
};
GENERIC8TABLE(Canon_MeteringMode,canon_meteringmode)

static struct deviceproptableu8 canon_eos_meteringmode[] = {
      { N_("Evaluative metering"),              3, 0 },
      { N_("Partial metering"),                 4, 0 },
      { N_("Center Weighted average metering"), 5, 0 },
};
GENERIC8TABLE(Canon_EOS_MeteringMode,canon_eos_meteringmode)

static struct deviceproptableu8 canon_eos_picturestyle[] = {
      { N_("Standard"), 0x81, 0 },
      { N_("Portrait"), 0x82, 0 },
      { N_("Landscape"),      0x83, 0 },
      { N_("Neutral"),  0x84, 0 },
      { N_("Faithful"), 0x85, 0 },
      { N_("Monochrome"),     0x86, 0 },
      { N_("User defined 1"), 0x21, 0 },
      { N_("User defined 2"), 0x22, 0 },
      { N_("User defined 3"), 0x23, 0 },
};
GENERIC8TABLE(Canon_EOS_PictureStyle,canon_eos_picturestyle)

static struct deviceproptableu16 canon_shutterspeed[] = {
      {  "auto",0x0000,0 },
      {  "30\"",0x0010,0 },
      {  "25\"",0x0013,0 },
      {  "20\"",0x0015,0 },
      {  "15\"",0x0018,0 },
      {  "13\"",0x001b,0 },
      {  "10\"",0x001d,0 },
      {  "8\"",0x0020,0 },
      {  "6\"",0x0023,0 },
      {  "5\"",0x0025,0 },
      {  "4\"",0x0028,0 },
      {  "3\"2",0x002b,0 },
      {  "2\"5",0x002d,0 },
      {  "2\"",0x0030,0 },
      {  "1\"6",0x0033,0 },
      {  "1\"3",0x0035,0 },
      {  "1\"",0x0038,0 },
      {  "0\"8",0x003b,0 },
      {  "0\"6",0x003d,0 },
      {  "0\"5",0x0040,0 },
      {  "0\"4",0x0043,0 },
      {  "0\"3",0x0045,0 },
      {  "1/4",0x0048,0 },
      {  "1/5",0x004b,0 },
      {  "1/6",0x004d,0 },
      {  "1/8",0x0050,0 },
      {  "1/10",0x0053,0 },
      {  "1/13",0x0055,0 },
      {  "1/15",0x0058,0 },
      {  "1/20",0x005b,0 },
      {  "1/25",0x005d,0 },
      {  "1/30",0x0060,0 },
      {  "1/40",0x0063,0 },
      {  "1/50",0x0065,0 },
      {  "1/60",0x0068,0 },
      {  "1/80",0x006b,0 },
      {  "1/100",0x006d,0 },
      {  "1/125",0x0070,0 },
      {  "1/160",0x0073,0 },
      {  "1/200",0x0075,0 },
      {  "1/250",0x0078,0 },
      {  "1/320",0x007b,0 },
      {  "1/400",0x007d,0 },
      {  "1/500",0x0080,0 },
      {  "1/640",0x0083,0 },
      {  "1/800",0x0085,0 },
      {  "1/1000",0x0088,0 },
      {  "1/1250",0x008b,0 },
      {  "1/1600",0x008d,0 },
      {  "1/2000",0x0090,0 },
      {  "1/2500",0x0093,0 },
      {  "1/3200",0x0095,0 },
      {  "1/4000",0x0098,0 },
};
GENERIC16TABLE(Canon_ShutterSpeed,canon_shutterspeed)


static struct deviceproptableu16 canon_focuspoints[] = {
      { N_("Center"),   0x3003, 0 },
      { N_("Auto"),     0x3001, 0 },
};
GENERIC16TABLE(Canon_FocusingPoint,canon_focuspoints)


static struct deviceproptableu8 canon_size[] = {
      { N_("large"),          0x00, 0 },
      { N_("medium 1"), 0x01, 0 },
      { N_("medium 2"), 0x03, 0 },
      { N_("medium 3"), 0x07, 0 },
      { N_("small"),          0x02, 0 },
};
GENERIC8TABLE(Canon_Size,canon_size)


static struct deviceproptableu16 canon_isospeed[] = {
      { N_("Factory Default"),0xffff, 0 },
      { "50",                 0x0040, 0 },
      { "100",          0x0048, 0 },
      { "200",          0x0050, 0 },
      { "400",          0x0058, 0 },
      { "800",          0x0060, 0 },
      { "1600",         0x0068, 0 },
      { N_("Auto"),           0x0000, 0 },
};
GENERIC16TABLE(Canon_ISO,canon_isospeed)

static int
_get_ISO(CONFIG_GET_ARGS) {
      int i;

      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_UINT16)
            return (GP_ERROR);

        for (i=0;i<dpd->FORM.Enum.NumberOfValues; i++) {
            char  buf[20];

            sprintf(buf,"%d",dpd->FORM.Enum.SupportedValue[i].u16);
                gp_widget_add_choice (*widget,buf);
            if (dpd->FORM.Enum.SupportedValue[i].u16 == dpd->CurrentValue.u16)
                  gp_widget_set_value (*widget,buf);
        }
      return (GP_OK);
}

static int
_put_ISO(CONFIG_PUT_ARGS)
{
      int ret;
      char *value;
      unsigned int      u;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;

      if (sscanf(value, "%ud", &u)) {
            propval->u16 = u;
            return GP_OK;
      }
      return GP_ERROR;
}

static int
_get_FNumber(CONFIG_GET_ARGS) {
      int i;

      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_UINT16)
            return (GP_ERROR);

        for (i=0;i<dpd->FORM.Enum.NumberOfValues; i++) {
            char  buf[20];

            sprintf(buf,"f/%g",(dpd->FORM.Enum.SupportedValue[i].u16*1.0)/100.0);
                gp_widget_add_choice (*widget,buf);
            if (dpd->FORM.Enum.SupportedValue[i].u16 == dpd->CurrentValue.u16)
                  gp_widget_set_value (*widget,buf);
        }
      return (GP_OK);
}

static int
_put_FNumber(CONFIG_PUT_ARGS)
{
      int   ret;
      char  *value;
      float f;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;

      if (sscanf(value, "f/%g", &f)) {
            propval->u16 = f*100;
            return GP_OK;
      }
      return GP_ERROR;
}

static int
_get_ExpTime(CONFIG_GET_ARGS) {
      int i;

      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!(dpd->FormFlag & PTP_DPFF_Enumeration))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_UINT32)
            return (GP_ERROR);

        for (i=0;i<dpd->FORM.Enum.NumberOfValues; i++) {
            char  buf[20];

            if (dpd->FORM.Enum.SupportedValue[i].u32%1000)
                  sprintf (buf,"%d.%03d",
                        dpd->FORM.Enum.SupportedValue[i].u32/1000,
                        dpd->FORM.Enum.SupportedValue[i].u32%1000
                  );
            else
                  sprintf (buf,"%d",dpd->FORM.Enum.SupportedValue[i].u32/1000);
                gp_widget_add_choice (*widget,buf);
            if (dpd->FORM.Enum.SupportedValue[i].u32 == dpd->CurrentValue.u32)
                  gp_widget_set_value (*widget,buf);
        }
      return (GP_OK);
}

static int
_put_ExpTime(CONFIG_PUT_ARGS)
{
      int   ret, val;
      char  *value;

      ret = gp_widget_get_value (widget, &value);
      if (ret != GP_OK)
            return ret;

      if (strchr(value,'.')) {
            int val2;

            if (!sscanf(value,"%d.%d",&val,&val2))
                  return (GP_ERROR);
            propval->u32 = val*1000+val2;
            return (GP_OK);
      }
      if (!sscanf(value,"%d",&val))
            return (GP_ERROR);
      propval->u32 = val*1000;
      return (GP_OK);
}

static struct deviceproptableu16 exposure_program_modes[] = {
      { "M",                  0x0001, 0 },
      { "P",                  0x0002, 0 },
      { "A",                  0x0003, 0 },
      { "S",                  0x0004, 0 },
      { N_("Creative"), 0x0005, 0 },
      { N_("Action"),         0x0006, 0 },
      { N_("Portrait"), 0x0007, 0 },
      { N_("Auto"),           0x8010, PTP_VENDOR_NIKON},
      { N_("Portrait"), 0x8011, PTP_VENDOR_NIKON},
      { N_("Landscape"),      0x8012, PTP_VENDOR_NIKON},
      { N_("Macro"),          0x8013, PTP_VENDOR_NIKON},
      { N_("Sports"),         0x8014, PTP_VENDOR_NIKON},
      { N_("Night Portrait"), 0x8015, PTP_VENDOR_NIKON},
      { N_("Night Landscape"),0x8016, PTP_VENDOR_NIKON},
};
GENERIC16TABLE(ExposureProgram,exposure_program_modes)


static struct deviceproptableu16 capture_mode[] = {
      { N_("Single Shot"),          0x0001, 0 },
      { N_("Burst"),                0x0002, 0 },
      { N_("Timelapse"),            0x0003, 0 },
      { N_("Continuous Low Speed"), 0x8010, PTP_VENDOR_NIKON},
      { N_("Timer"),                0x8011, PTP_VENDOR_NIKON},
      { N_("Mirror Up"),            0x8012, PTP_VENDOR_NIKON},
      { N_("Remote"),               0x8013, PTP_VENDOR_NIKON},
      { N_("Timer + Remote"),       0x8014, PTP_VENDOR_NIKON},
};
GENERIC16TABLE(CaptureMode,capture_mode)


static struct deviceproptableu16 focus_metering[] = {
      { N_("Dynamic Area"),   0x0002, 0 },
      { N_("Single Area"),    0x8010, PTP_VENDOR_NIKON},
      { N_("Closest Subject"),0x8011, PTP_VENDOR_NIKON},
      { N_("Group Dynamic"),  0x8012, PTP_VENDOR_NIKON},
};
GENERIC16TABLE(FocusMetering,focus_metering)


static struct deviceproptableu8 nikon_colormodel[] = {
      { N_("sRGB (portrait)"), 0x00, 0 },
      { N_("AdobeRGB"),        0x01, 0 },
      { N_("sRGB (nature)"),   0x02, 0 },
};
GENERIC8TABLE(Nikon_ColorModel,nikon_colormodel)


static struct deviceproptableu8 nikon_afsensor[] = {
      { N_("Centre"),   0x00, 0 },
      { N_("Top"),      0x01, 0 },
      { N_("Bottom"),   0x02, 0 },
      { N_("Left"),     0x03, 0 },
      { N_("Right"),    0x04, 0 },
};
GENERIC8TABLE(Nikon_AutofocusArea,nikon_afsensor)


static struct deviceproptableu16 exposure_metering[] = {
      { N_("Average"),  0x0001, 0 },
      { N_("Center Weighted"),0x0002, 0 },
      { N_("Multi Spot"),     0x0003, 0 },
      { N_("Center Spot"),    0x0004, 0 },
};
GENERIC16TABLE(ExposureMetering,exposure_metering)


static struct deviceproptableu16 flash_mode[] = {
      { N_("Automatic Flash"),            0x0001, 0 },
      { N_("Flash off"),                  0x0002, 0 },
      { N_("Fill flash"),                 0x0003, 0 },
      { N_("Red-eye automatic"),          0x0004, 0 },
      { N_("Red-eye fill"),               0x0005, 0 },
      { N_("External sync"),              0x0006, 0 },
      { N_("Default"),              0x8010, PTP_VENDOR_NIKON},
      { N_("Slow Sync"),                  0x8011, PTP_VENDOR_NIKON},
      { N_("Rear Curtain Sync + Slow Sync"),    0x8012, PTP_VENDOR_NIKON},
      { N_("Red-eye Reduction + Slow Sync"),    0x8013, PTP_VENDOR_NIKON},
};
GENERIC16TABLE(FlashMode,flash_mode)

static struct deviceproptableu16 effect_modes[] = {
      { N_("Standard"), 0x0001, 0 },
      { N_("Black & White"),  0x0002, 0 },
      { N_("Sepia"),          0x0003, 0 },
};
GENERIC16TABLE(EffectMode,effect_modes)


static int
_get_FocalLength(CONFIG_GET_ARGS) {
      float value_float , start=0.0, end=0.0, step=0.0;
      int i;

      gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);

      if (!(dpd->FormFlag & (PTP_DPFF_Range|PTP_DPFF_Enumeration)))
            return (GP_ERROR);

      if (dpd->DataType != PTP_DTC_UINT32)
            return (GP_ERROR);

      if (dpd->FormFlag & PTP_DPFF_Enumeration) {
            /* Find the range we need. */
            start = 10000.0;
            end = 0.0;
            for (i = 0; i<dpd->FORM.Enum.NumberOfValues; i++) {
                  float cur = dpd->FORM.Enum.SupportedValue[i].u32 / 100.0;

                  if (cur < start) start = cur;
                  if (cur > end)   end = cur;
            }
            step = 1.0;
      }
      if (dpd->FormFlag & PTP_DPFF_Range) {
            start = dpd->FORM.Range.MinimumValue.u32/100.0;
            end = dpd->FORM.Range.MaximumValue.u32/100.0;
            step = dpd->FORM.Range.StepSize.u32/100.0;
      }
      gp_widget_set_range (*widget, start, end, step);
      value_float = dpd->CurrentValue.u32/100.0;
      gp_widget_set_value (*widget, &value_float);
      return (GP_OK);
}

static int
_put_FocalLength(CONFIG_PUT_ARGS) {
      int ret, i;
      float value_float;
      uint32_t curdiff, newval;

      ret = gp_widget_get_value (widget, &value_float);
      if (ret != GP_OK)
            return ret;
      propval->u32 = 100*value_float;
      if (dpd->FormFlag & PTP_DPFF_Range)
            return GP_OK;
      /* If FocalLength is enumerated, we need to hit the 
       * values exactly, otherwise nothing will happen.
       * (problem encountered on my Nikon P2)
       */
      curdiff = 10000;
      newval = propval->u32;
      for (i = 0; i<dpd->FORM.Enum.NumberOfValues; i++) {
            uint32_t diff = abs(dpd->FORM.Enum.SupportedValue[i].u32  - propval->u32);

            if (diff < curdiff) {
                  newval = dpd->FORM.Enum.SupportedValue[i].u32;
                  curdiff = diff;
            }
      }
      propval->u32 = newval;
      return GP_OK;
}

static int
_get_Nikon_FlashExposureCompensation(CONFIG_GET_ARGS) {
      float value_float;

      gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!(dpd->FormFlag & PTP_DPFF_Range))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_INT8)
            return (GP_ERROR);
      gp_widget_set_range (*widget,
            dpd->FORM.Range.MinimumValue.i8/6.0,
            dpd->FORM.Range.MaximumValue.i8/6.0,
            dpd->FORM.Range.StepSize.i8/6.0
      );
      value_float = dpd->CurrentValue.i8/6.0;
      gp_widget_set_value (*widget, &value_float);
      return (GP_OK);
}

static int
_put_Nikon_FlashExposureCompensation(CONFIG_PUT_ARGS) {
      int ret;
      float value_float;

      ret = gp_widget_get_value (widget, &value_float);
      if (ret != GP_OK)
            return ret;
      propval->i8 = 6.0*value_float;
      return GP_OK;

}

static struct deviceproptableu8 nikon_afareaillum[] = {
      { N_("Auto"),           0, 0 },
      { N_("Off"),            1, 0 },
      { N_("On"),       2, 0 },
};
GENERIC8TABLE(Nikon_AFAreaIllum,nikon_afareaillum)


static struct deviceproptableu8 nikon_aelaflmode[] = {
      { N_("AE/AF Lock"),     0x00, 0 },
      { N_("AE Lock only"),   0x01, 0 },
      { N_("AF Lock Only"),   0x02, 0 },
      { N_("AF Lock Hold"),   0x03, 0 },
      { N_("AF On"),          0x04, 0 },
      { N_("Flash Level Lock"),0x05, 0 },
};
GENERIC8TABLE(Nikon_AELAFLMode,nikon_aelaflmode)

static struct deviceproptableu8 nikon_lcdofftime[] = {
      { N_("10 seconds"),     0x00, 0 },
      { N_("20 seconds"),     0x01, 0 },
      { N_("1 minute"), 0x02, 0 },
      { N_("5 minutes"),      0x03, 0 },
      { N_("10 minutes"),     0x04, 0 },
};
GENERIC8TABLE(Nikon_LCDOffTime,nikon_lcdofftime)

static struct deviceproptableu8 nikon_meterofftime[] = {
      { N_("4 seconds"),      0x00, 0 },
      { N_("6 seconds"),      0x01, 0 },
      { N_("8 seconds"),      0x02, 0 },
      { N_("16 seconds"),     0x03, 0 },
      { N_("30 minutes"),     0x04, 0 },
};
GENERIC8TABLE(Nikon_MeterOffTime,nikon_meterofftime)

static struct deviceproptableu8 nikon_selftimerdelay[] = {
      { N_("2 seconds"),      0x00, 0 },
      { N_("5 seconds"),      0x01, 0 },
      { N_("10 seconds"),     0x02, 0 },
      { N_("20 seconds"),     0x03, 0 },
};
GENERIC8TABLE(Nikon_SelfTimerDelay,nikon_selftimerdelay)

static struct deviceproptableu8 nikon_centerweight[] = {
      { N_("6 mm"),     0x00, 0 },
      { N_("8 mm"),     0x01, 0 },
      { N_("10 mm"),    0x02, 0 },
      { N_("20 mm"),    0x03, 0 },
};
GENERIC8TABLE(Nikon_CenterWeight,nikon_centerweight)

static struct deviceproptableu8 nikon_flashshutterspeed[] = {
      { N_("1/60"),     0x00, 0 },
      { N_("1/30"),     0x01, 0 },
      { N_("1/15"),     0x02, 0 },
      { N_("1/8"),      0x03, 0 },
      { N_("1/4"),      0x04, 0 },
      { N_("1/2"),      0x05, 0 },
      { N_("1"),  0x06, 0 },
      { N_("2"),  0x07, 0 },
      { N_("4"),  0x08, 0 },
      { N_("8"),  0x09, 0 },
      { N_("15"), 0x0a, 0 },
      { N_("30"), 0x0b, 0 },
};
GENERIC8TABLE(Nikon_FlashShutterSpeed,nikon_flashshutterspeed)

static struct deviceproptableu8 nikon_remotetimeout[] = {
      { N_("1 minute"), 0x00, 0 },
      { N_("5 minutes"),      0x01, 0 },
      { N_("10 minutes"),     0x02, 0 },
      { N_("15 minutes"),     0x03, 0 },
};
GENERIC8TABLE(Nikon_RemoteTimeout,nikon_remotetimeout)

static struct deviceproptableu8 nikon_optimizeimage[] = {
      { N_("Normal"),         0x00, 0 },
      { N_("Vivid"),          0x01, 0 },
      { N_("Sharper"),  0x02, 0 },
      { N_("Softer"),         0x03, 0 },
      { N_("Direct Print"),   0x04, 0 },
      { N_("Portrait"), 0x05, 0 },
      { N_("Landscape"),      0x06, 0 },
      { N_("Custom"),         0x07, 0 },
};
GENERIC8TABLE(Nikon_OptimizeImage,nikon_optimizeimage)

static struct deviceproptableu8 nikon_sharpening[] = {
      { N_("Auto"),           0x00, 0 },
      { N_("Normal"),         0x01, 0 },
      { N_("Low"),            0x02, 0 },
      { N_("Medium Low"),     0x03, 0 },
      { N_("Medium high"),    0x04, 0 },
      { N_("High"),           0x05, 0 },
      { N_("None"),           0x06, 0 },
};
GENERIC8TABLE(Nikon_Sharpening,nikon_sharpening)

static struct deviceproptableu8 nikon_tonecompensation[] = {
      { N_("Auto"),           0x00, 0 },
      { N_("Normal"),         0x01, 0 },
      { N_("Low contrast"),   0x02, 0 },
      { N_("Medium low"),     0x03, 0 },
      { N_("Medium high"),    0x04, 0 },
      { N_("High control"),   0x05, 0 },
      { N_("Custom"),         0x06, 0 },
};
GENERIC8TABLE(Nikon_ToneCompensation,nikon_tonecompensation)

static struct deviceproptableu8 canon_afdistance[] = {
      { N_("Off"),            0x01, 0 },
      { N_("Macro"),          0x03, 0 },
      { N_("Long distance"),  0x07, 0 }, /* Unchecked. */
};
GENERIC8TABLE(Canon_AFDistance,canon_afdistance)


/* Focus Modes as per PTP standard. |0x8000 means vendor specific. */
static struct deviceproptableu16 focusmodes[] = {
      { N_("Undefined"),      0x0000, 0 },
      { N_("Manual"),         0x0001, 0 },
      { N_("Automatic"),      0x0002, 0 },
      { N_("Automatic Macro"),0x0003, 0 },
      { N_("AF-S"),           0x8010, PTP_VENDOR_NIKON },
      { N_("AF-C"),           0x8011, PTP_VENDOR_NIKON },
      { N_("AF-A"),           0x8012, PTP_VENDOR_NIKON },
};
GENERIC16TABLE(FocusMode,focusmodes)


static struct deviceproptableu8 canon_whitebalance[] = {
      { N_("Auto"),           0, 0 },
      { N_("Daylight"),       1, 0 },
      { N_("Cloudy"),         2, 0 },
      { N_("Tungsten"),       3, 0 },
      { N_("Fluorescent"),    4, 0 },
      { N_("Fluorescent H"),  7, 0 },
      { N_("Custom"),         6, 0 },
};
GENERIC8TABLE(Canon_WhiteBalance,canon_whitebalance)

static struct deviceproptableu8 canon_eos_whitebalance[] = {
      { N_("Auto"),           0, 0 },
      { N_("Daylight"),       1, 0 },
      { N_("Shade"),          2, 0 },
      { N_("Cloudy"),         3, 0 },
      { N_("Tungsten"),       4, 0 },
      { N_("Fluorescent"),    5, 0 },
      { N_("Flash"),          6, 0 },
      { N_("Custom"),         8, 0 },
};
GENERIC8TABLE(Canon_EOS_WhiteBalance,canon_eos_whitebalance)


static struct deviceproptableu8 canon_expcompensation[] = {
      { N_("Factory Default"),      0xff, 0 },
      { "+2",                 0x08, 0 },
      { "+1 2/3",       0x0b, 0 },
      { "+1 1/3",       0x0d, 0 },
      { "+1",                 0x10, 0 },
      { "+2/3",               0x13, 0 },
      { "+1/3",               0x15, 0 },
      { "0",                  0x18, 0 },
      { "-1/3",               0x1b, 0 },
      { "-2/3",               0x1d, 0 },
      { "-1",                 0x20, 0 },
      { "-1 1/3",       0x23, 0 },
      { "-1 2/3",       0x25, 0 },
      { "-2",                 0x28, 0 },
};
GENERIC8TABLE(Canon_ExpCompensation,canon_expcompensation)

static struct deviceproptableu8 canon_expcompensation2[] = {
      { "0",      0x00, 0 },
      { "0.3",    0x03, 0 },
      { "0.6",    0x05, 0 },
      { "1.0",    0x08, 0 },
      { "1.3",    0x0b, 0 },
      { "1.6",    0x0d, 0 },
      { "2",      0x10, 0 },
      { "-0.3",   0xfd, 0 },
      { "-0.6",   0xfb, 0 },
      { "-1.0",   0xf8, 0 },
      { "-1.3",   0xf5, 0 },
      { "-1.6",   0xf3, 0 },
      { "-2",     0xf0, 0 },
};
GENERIC8TABLE(Canon_ExpCompensation2,canon_expcompensation2)


static struct deviceproptableu16 canon_photoeffect[] = {
      { N_("Off"),            0, 0 },
      { N_("Vivid"),          1, 0 },
      { N_("Neutral"),        2, 0 },
      { N_("Low sharpening"), 3, 0 },
      { N_("Sepia"),          4, 0 },
      { N_("Black & white"),  5, 0 },
};
GENERIC16TABLE(Canon_PhotoEffect,canon_photoeffect)


static struct deviceproptableu16 canon_aperture[] = {
      { N_("auto"),     0xffff, 0 },
      { "1.8",          0x0015, 0 },
      { "2.0",          0x0018, 0 },
      { "2.2",          0x001b, 0 },
      { "2.5",          0x001d, 0 },
      { "2.8",          0x0020, 0 },
      { "3.2",          0x0023, 0 },
      { "3.5",          0x0025, 0 },
      { "4.0",          0x0028, 0 },
      { "4.5",          0x002b, 0 },
      { "5",            0x002d, 0 },
      { "5.6",          0x0030, 0 },
      { "6.3",          0x0033, 0 },
      { "7.1",          0x0035, 0 },
      { "8.0",          0x0038, 0 },
      { "9.0",          0x003b, 0 },
      { "10",           0x003d, 0 },
      { "11",           0x0040, 0 },
      { "13",           0x0043, 0 },
      { "14",           0x0045, 0 },
      { "16",           0x0048, 0 },
      { "18",           0x004b, 0 },
      { "20",           0x004d, 0 },
      { "22",           0x0050, 0 },
};
GENERIC16TABLE(Canon_Aperture,canon_aperture)


static struct deviceproptableu8 nikon_bracketset[] = {
      { N_("AE & Flash"),     0, 0 },
      { N_("AE only"),        1, 0 },
      { N_("Flash only"),     2, 0 },
      { N_("WB bracketing"),  3, 0 },
};
GENERIC8TABLE(Nikon_BracketSet,nikon_bracketset)

static struct deviceproptableu8 nikon_saturation[] = {
      { N_("Normal"),   0, 0 },
      { N_("Moderate"), 1, 0 },
      { N_("Enhanced"), 2, 0 },
};
GENERIC8TABLE(Nikon_Saturation,nikon_saturation)


static struct deviceproptableu8 nikon_bracketorder[] = {
      { N_("MTR > Under"),    0, 0 },
      { N_("Under > MTR"),    1, 0 },
};
GENERIC8TABLE(Nikon_BracketOrder,nikon_bracketorder)

static int
_get_BurstNumber(CONFIG_GET_ARGS) {
      float value_float , start=0.0, end=0.0, step=0.0;

      gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);

      if (!(dpd->FormFlag & PTP_DPFF_Range))
            return (GP_ERROR);

      if (dpd->DataType != PTP_DTC_UINT16)
            return (GP_ERROR);

      start = dpd->FORM.Range.MinimumValue.u16;
      end = dpd->FORM.Range.MaximumValue.u16;
      step = dpd->FORM.Range.StepSize.u16;
      gp_widget_set_range (*widget, start, end, step);
      value_float = dpd->CurrentValue.u16;
      gp_widget_set_value (*widget, &value_float);
      return (GP_OK);
}

static int
_put_BurstNumber(CONFIG_PUT_ARGS) {
      int ret;
      float value_float;

      ret = gp_widget_get_value (widget, &value_float);
      if (ret != GP_OK)
            return ret;
      propval->u16 = value_float;
      return GP_OK;
}

static int
_get_BatteryLevel(CONFIG_GET_ARGS) {
      unsigned char value_float , start, end;
      char  buffer[20];

      gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);

      if (!(dpd->FormFlag & PTP_DPFF_Range))
            return (GP_ERROR);
      if (dpd->DataType != PTP_DTC_UINT8)
            return (GP_ERROR);
      start = dpd->FORM.Range.MinimumValue.u8;
      end = dpd->FORM.Range.MaximumValue.u8;
      value_float = dpd->CurrentValue.u8;
      sprintf (buffer, "%d%%", (int)((value_float-start+1)*100/(end-start+1)));
      gp_widget_set_value(*widget, buffer);
      return (GP_OK);
}


static int
_get_UINT32_as_time(CONFIG_GET_ARGS) {
      time_t      camtime;

      gp_widget_new (GP_WIDGET_DATE, _(menu->label), widget);
      gp_widget_set_name (*widget,menu->name);
      camtime = dpd->CurrentValue.u32;
      gp_widget_set_value (*widget,&camtime);
      return (GP_OK);
}

static int
_put_UINT32_as_time(CONFIG_PUT_ARGS) {
      time_t      camtime;
      int   ret;

      camtime = 0;
      ret = gp_widget_get_value (widget,&camtime);
      if (ret != GP_OK)
            return ret;
      propval->u32 = camtime;
      return (GP_OK);
}

static int
_get_STR_as_time(CONFIG_GET_ARGS) {
      time_t            camtime;
      struct tm   tm;
      char        capture_date[64],tmp[5];

      /* strptime() is not widely accepted enough to use yet */
      memset(&tm,0,sizeof(tm));
      gp_widget_new (GP_WIDGET_DATE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (!dpd->CurrentValue.str)
            return (GP_ERROR);
      strncpy(capture_date,dpd->CurrentValue.str,sizeof(capture_date));
      strncpy (tmp, capture_date, 4);
      tmp[4] = 0;
      tm.tm_year=atoi (tmp) - 1900;
      strncpy (tmp, capture_date + 4, 2);
      tmp[2] = 0;
      tm.tm_mon = atoi (tmp) - 1;
      strncpy (tmp, capture_date + 6, 2);
      tmp[2] = 0;
      tm.tm_mday = atoi (tmp);
      strncpy (tmp, capture_date + 9, 2);
      tmp[2] = 0;
      tm.tm_hour = atoi (tmp);
      strncpy (tmp, capture_date + 11, 2);
      tmp[2] = 0;
      tm.tm_min = atoi (tmp);
      strncpy (tmp, capture_date + 13, 2);
      tmp[2] = 0;
      tm.tm_sec = atoi (tmp);
      camtime = mktime(&tm);
      gp_widget_set_value (*widget,&camtime);
      return (GP_OK);
}

static int
_put_STR_as_time(CONFIG_PUT_ARGS) {
      time_t            camtime;
#ifdef HAVE_GMTIME_R
      struct tm   xtm;
#endif
      struct tm   *pxtm;
      int         ret;
      char        asctime[64];

      camtime = 0;
      ret = gp_widget_get_value (widget,&camtime);
      if (ret != GP_OK)
            return ret;
#ifdef HAVE_GMTIME_R
      pxtm = gmtime_r (&camtime, &xtm);
#else
      pxtm = gmtime (&camtime);
#endif
      /* 20020101T123400.0 is returned by the HP Photosmart */
      sprintf(asctime,"%04d%02d%02dT%02d%02d%02d.0",pxtm->tm_year+1900,pxtm->tm_mon+1,pxtm->tm_mday,pxtm->tm_hour,pxtm->tm_min,pxtm->tm_sec);
      propval->str = strdup(asctime);
      if (!propval->str)
            return (GP_ERROR_NO_MEMORY);
      return (GP_OK);
}

static int
_put_None(CONFIG_PUT_ARGS) {
      return (GP_ERROR_NOT_SUPPORTED);
}

static int
_get_Canon_CaptureMode(CONFIG_GET_ARGS) {
      int val;

      gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      val = 0;
      gp_widget_set_value  (*widget, &val);
      return (GP_OK);
}

static int
_put_Canon_CaptureMode(CONFIG_PUT_ARGS) {
      int val, ret;

      ret = gp_widget_get_value (widget, &val);
      if (ret != GP_OK)
            return ret;
      if (val)
            return camera_prepare_capture (camera, NULL);
      else
            return camera_unprepare_capture (camera, NULL);
}

static int
_get_Canon_FocusLock(CONFIG_GET_ARGS) {
      int val;

      gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget);
      gp_widget_set_name (*widget,menu->name);
      val = 2; /* always changed */
      gp_widget_set_value  (*widget, &val);
      return (GP_OK);
}

static int
_put_Canon_FocusLock(CONFIG_PUT_ARGS)
{
      PTPParams *params = &(camera->pl->params);
      int val, ret;

      ret = gp_widget_get_value (widget, &val);
      if (ret != GP_OK)
            return ret;
      if (val)
            ret = ptp_canon_focuslock (params);
      else
            ret = ptp_canon_focusunlock (params);
      if (ret == PTP_RC_OK)
            return (GP_OK);
      return (GP_ERROR);
}


static int
_get_Nikon_BeepMode(CONFIG_GET_ARGS) {
      int val;

      gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      val = !dpd->CurrentValue.u8;
      gp_widget_set_value  (*widget, &val);
      return (GP_OK);
}

static int
_put_Nikon_BeepMode(CONFIG_PUT_ARGS) {
      int val, ret;

      ret = gp_widget_get_value (widget, &val);
      if (ret != GP_OK)
            return ret;

      propval->u8 = !val;
      return GP_OK;
}

static int
_get_Nikon_FastFS(CONFIG_GET_ARGS) {
      int val;
      char buf[1024];

      gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      val = 1; /* default is fast fs */
      if (GP_OK == gp_setting_get("ptp2","nikon.fastfilesystem", buf))
            val = atoi(buf);
      gp_widget_set_value  (*widget, &val);
      return (GP_OK);
}

static int
_put_Nikon_FastFS(CONFIG_PUT_ARGS) {
      int val, ret;
      char buf[20];

      ret = gp_widget_get_value (widget, &val);
      if (ret != GP_OK)
            return ret;
      sprintf(buf,"%d",val);
      gp_setting_set("ptp2","nikon.fastfilesystem",buf);
      return GP_OK;
}

static struct {
      char  *name;
      char  *label;
} capturetargets[] = {
      {"sdram", N_("Internal RAM") },
      {"card", N_("Memory card") },
};

static int
_get_CaptureTarget(CONFIG_GET_ARGS) {
      int i;
      char buf[1024];

      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      if (GP_OK != gp_setting_get("ptp2","capturetarget", buf))
            strcpy(buf,"sdram");
      for (i=0;i<sizeof (capturetargets)/sizeof (capturetargets[i]);i++) {
            gp_widget_add_choice (*widget, _(capturetargets[i].label));
            if (!strcmp (buf,capturetargets[i].name))
                  gp_widget_set_value (*widget, _(capturetargets[i].label));
      }
      return (GP_OK);
}

static int
_put_CaptureTarget(CONFIG_PUT_ARGS) {
      int i, ret;
      char *val;

      ret = gp_widget_get_value (widget, &val);
      if (ret != GP_OK)
            return ret;
      for (i=0;i<sizeof(capturetargets)/sizeof(capturetargets[i]);i++) {
            if (!strcmp( val, _(capturetargets[i].label))) {
                  gp_setting_set("ptp2","capturetarget",capturetargets[i].name);
                  break;
            }
      }
      return GP_OK;
}
/* Wifi profiles functions */

static int
_put_nikon_list_wifi_profiles (CONFIG_PUT_ARGS)
{
      int i;
      CameraWidget *child, *child2;
      const char *name;
      int value;
      char* endptr;
      long val;
      int deleted = 0;

      if (camera->pl->params.deviceinfo.VendorExtensionID != PTP_VENDOR_NIKON)
            return (GP_ERROR_NOT_SUPPORTED);

      for (i = 0; i < gp_widget_count_children(widget); i++) {
            gp_widget_get_child(widget, i, &child);
            gp_widget_get_child_by_name(child, "delete", &child2);
            
            gp_widget_get_value(child2, &value);
            if (value) {
                  gp_widget_get_name(child, &name);
                  /* FIXME: far from elegant way to get ID back... */
                  val = strtol(name, &endptr, 0);
                  if (!*endptr) {
                        ptp_nikon_deletewifiprofile(&(camera->pl->params), val);
                        gp_widget_set_value(child2, 0);
                        deleted = 1;
                  }
            }
      }

      /* FIXME: deleted entry still exists, rebuild tree if deleted = 1 ? */
      
      return GP_OK;
}

static int
_get_nikon_list_wifi_profiles (CONFIG_GET_ARGS)
{
      CameraWidget *child;
      int ret;
      char buffer[4096];
      int i;
      PTPParams *params = &(camera->pl->params);

      gp_widget_new (GP_WIDGET_SECTION, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);

      if (params->deviceinfo.VendorExtensionID != PTP_VENDOR_NIKON)
            return (GP_ERROR_NOT_SUPPORTED);

      if (!ptp_operation_issupported(&camera->pl->params, PTP_OC_NIKON_GetProfileAllData)) 
            return (GP_ERROR_NOT_SUPPORTED);

      ret = ptp_nikon_getwifiprofilelist(params);
      if (ret != PTP_RC_OK)
            return (GP_ERROR_NOT_SUPPORTED);

      gp_widget_new (GP_WIDGET_TEXT, "Version", &child);
      snprintf(buffer, 4096, "%d", params->wifi_profiles_version);
      gp_widget_set_value(child, buffer);
      gp_widget_append(*widget, child);

      for (i = 0; i < params->wifi_profiles_number; i++) {
            CameraWidget *child2;
            if (params->wifi_profiles[i].valid) {
                  gp_widget_new (GP_WIDGET_SECTION, params->wifi_profiles[i].profile_name, &child);
                  snprintf(buffer, 4096, "%d", params->wifi_profiles[i].id);
                  gp_widget_set_name(child, buffer);
                  gp_widget_append(*widget, child);

                  gp_widget_new (GP_WIDGET_TEXT, _("ID"), &child2);
                  snprintf (buffer, 4096, "%d", params->wifi_profiles[i].id);
                  gp_widget_set_value(child2, buffer);
                  gp_widget_append(child, child2);

                  gp_widget_new (GP_WIDGET_TEXT, _("ESSID"), &child2);
                  snprintf (buffer, 4096, "%s", params->wifi_profiles[i].essid);
                  gp_widget_set_value(child2, buffer);
                  gp_widget_append(child, child2);

                  gp_widget_new (GP_WIDGET_TEXT, _("Display"), &child2);
                  snprintf (buffer, 4096, "Order: %d, Icon: %d, Device type: %d",
                            params->wifi_profiles[i].display_order,
                            params->wifi_profiles[i].icon_type,
                            params->wifi_profiles[i].device_type);
                  gp_widget_set_value(child2, buffer);
                  gp_widget_append(child, child2);
                  
                  gp_widget_new (GP_WIDGET_TEXT, "Dates", &child2);
                  snprintf (buffer, 4096,
                        _("Creation date: %s, Last usage date: %s"),
                        params->wifi_profiles[i].creation_date,
                        params->wifi_profiles[i].lastusage_date);
                  gp_widget_set_value(child2, buffer);
                  gp_widget_append(child, child2);

                  gp_widget_new (GP_WIDGET_TOGGLE, _("Delete"), &child2);
                  gp_widget_set_value(child2, 0);
                  gp_widget_set_name(child2, "delete");
                  gp_widget_append(child, child2);
            }
      }

      return GP_OK;
}

static int
_get_nikon_wifi_profile_prop(CONFIG_GET_ARGS) {
      char buffer[1024];
      
      gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      gp_setting_get("ptp2_wifi",menu->name,buffer);
      gp_widget_set_value(*widget,buffer);
      return (GP_OK);
}

static int
_put_nikon_wifi_profile_prop(CONFIG_PUT_ARGS) {
      char *string, *name;
      int ret;
      ret = gp_widget_get_value(widget,&string);
      if (ret != GP_OK)
            return ret;
      gp_widget_get_name(widget,(const char**)&name);
      gp_setting_set("ptp2_wifi",name,string);
      return (GP_OK);
}

static int
_get_nikon_wifi_profile_channel(CONFIG_GET_ARGS) {
      char buffer[1024];
      float val;
      
      gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      gp_setting_get("ptp2_wifi", menu->name, buffer);
      val = (float)atoi(buffer);
      gp_widget_set_range(*widget, 1.0, 11.0, 1.0);
      if (!val)
            val = 1.0;
      gp_widget_set_value(*widget, &val);
      
      return (GP_OK);
}

static int
_put_nikon_wifi_profile_channel(CONFIG_PUT_ARGS) {
      char *string, *name;
      int ret;
      float val;
      char buffer[16];
      ret = gp_widget_get_value(widget,&string);
      if (ret != GP_OK)
            return ret;
      gp_widget_get_name(widget,(const char**)&name);
      gp_widget_get_value(widget, &val);

      snprintf(buffer, 16, "%d", (int)val);
      gp_setting_set("ptp2_wifi",name,buffer);
      return GP_OK;
}

static char* encryption_values[] = {
N_("None"),
N_("WEP 64-bit"),
N_("WEP 128-bit"),
NULL
};

static int
_get_nikon_wifi_profile_encryption(CONFIG_GET_ARGS) {
      char buffer[1024];
      int i;
      int val;
      
      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      gp_setting_get("ptp2_wifi", menu->name, buffer);
      val = atoi(buffer);
      
      for (i = 0; encryption_values[i]; i++) {
            gp_widget_add_choice(*widget, _(encryption_values[i]));
            if (i == val)
                  gp_widget_set_value(*widget, _(encryption_values[i]));
      }
      
      return (GP_OK);
}

static int
_put_nikon_wifi_profile_encryption(CONFIG_PUT_ARGS) {
      char *string, *name;
      int ret;
      int i;
      char buffer[16];
      ret = gp_widget_get_value(widget,&string);
      if (ret != GP_OK)
            return ret;
      gp_widget_get_name(widget,(const char**)&name);

      for (i = 0; encryption_values[i]; i++) {
            if (!strcmp(_(encryption_values[i]), string)) {
                  snprintf(buffer, 16, "%d", i);
                  gp_setting_set("ptp2_wifi",name,buffer);
                  return GP_OK;
            }
      }

      return GP_ERROR_BAD_PARAMETERS;
}

static char* accessmode_values[] = {
N_("Managed"),
N_("Ad-hoc"),
NULL
};

static int
_get_nikon_wifi_profile_accessmode(CONFIG_GET_ARGS) {
      char buffer[1024];
      int i;
      int val;
      
      gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      gp_setting_get("ptp2_wifi", menu->name, buffer);
      val = atoi(buffer);
      
      for (i = 0; accessmode_values[i]; i++) {
            gp_widget_add_choice(*widget, _(accessmode_values[i]));
            if (i == val)
                  gp_widget_set_value(*widget, _(accessmode_values[i]));
      }
      
      return (GP_OK);
}

static int
_put_nikon_wifi_profile_accessmode(CONFIG_PUT_ARGS) {
      char *string, *name;
      int ret;
      int i;
      char buffer[16];
      ret = gp_widget_get_value(widget,&string);
      if (ret != GP_OK)
            return ret;
      gp_widget_get_name(widget,(const char**)&name);

      for (i = 0; accessmode_values[i]; i++) {
            if (!strcmp(_(accessmode_values[i]), string)) {
                  snprintf(buffer, 16, "%d", i);
                  gp_setting_set("ptp2_wifi",name,buffer);
                  return GP_OK;
            }
      }

      return GP_ERROR_BAD_PARAMETERS;
}

static int
_get_nikon_wifi_profile_write(CONFIG_GET_ARGS) {
      gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);
      gp_widget_set_value(*widget, 0);
      return (GP_OK);
}

static int
_put_nikon_wifi_profile_write(CONFIG_PUT_ARGS) {
      char buffer[1024];
      char keypart[3];
      char* pos, *endptr;
      int value, i;
      int ret;
      ret = gp_widget_get_value(widget,&value);
      if (ret != GP_OK)
            return ret;
      if (value) {
            struct in_addr inp;
            PTPNIKONWifiProfile profile;
            memset(&profile, 0, sizeof(PTPNIKONWifiProfile));
            profile.icon_type = 1;
            profile.key_nr = 1;

            gp_setting_get("ptp2_wifi","name",buffer);
            strncpy(profile.profile_name, buffer, 16);
            gp_setting_get("ptp2_wifi","essid",buffer);
            strncpy(profile.essid, buffer, 32);

            gp_setting_get("ptp2_wifi","accessmode",buffer);
            profile.access_mode = atoi(buffer);

            gp_setting_get("ptp2_wifi","ipaddr",buffer);
            if (buffer[0] != 0) { /* No DHCP */
                  if (!inet_aton (buffer, &inp)) {
                        fprintf(stderr,"failed to scan for addr in %s\n", buffer);
                        return GP_ERROR_BAD_PARAMETERS;
                  }
                  profile.ip_address = inp.s_addr;
                  gp_setting_get("ptp2_wifi","netmask",buffer);
                  if (!inet_aton (buffer, &inp)) {
                        fprintf(stderr,"failed to scan for netmask in %s\n", buffer);
                        return GP_ERROR_BAD_PARAMETERS;
                  }
                  inp.s_addr = be32toh(inp.s_addr); /* Reverse bytes so we can use the code below. */
                  profile.subnet_mask = 32;
                  while (((inp.s_addr >> (32-profile.subnet_mask)) & 0x01) == 0) {
                        profile.subnet_mask--;
                        if (profile.subnet_mask <= 0) {
                              fprintf(stderr,"Invalid subnet mask %s: no zeros\n", buffer);
                              return GP_ERROR_BAD_PARAMETERS;
                        }
                  }
                  /* Check there is only ones left */
                  if ((inp.s_addr | ((0x01 << (32-profile.subnet_mask)) - 1)) != 0xFFFFFFFF) {
                        fprintf(stderr,"Invalid subnet mask %s: misplaced zeros\n", buffer);
                        return GP_ERROR_BAD_PARAMETERS;
                  }

                  /* Gateway (never tested) */
                  gp_setting_get("ptp2_wifi","gw",buffer);
                  if (*buffer) {
                        if (!inet_aton (buffer, &inp)) {
                              fprintf(stderr,"failed to scan for gw in %s\n", buffer);
                              return GP_ERROR_BAD_PARAMETERS;
                        }
                        profile.gateway_address = inp.s_addr;
                  }
            }
            else { /* DHCP */
                  /* Never use mode 2, as mode 3 switches to mode 2
                   * if it gets no DHCP answer. */
                  profile.address_mode = 3;
            }

            gp_setting_get("ptp2_wifi","channel",buffer);
            profile.wifi_channel = atoi(buffer);

            /* Encryption */
            gp_setting_get("ptp2_wifi","encryption",buffer);
            profile.encryption = atoi(buffer);
            
            if (profile.encryption != 0) {
                  gp_setting_get("ptp2_wifi","key",buffer);
                  i = 0;
                  pos = buffer;
                  keypart[2] = 0;
                  while (*pos) {
                        if (!*(pos+1)) {
                              fprintf(stderr,"Bad key: '%s'\n", buffer);
                              return GP_ERROR_BAD_PARAMETERS;     
                        }
                        keypart[0] = *(pos++);
                        keypart[1] = *(pos++);
                        profile.key[i++] = strtol(keypart, &endptr, 16);
                        if (endptr != keypart+2) {
                              fprintf(stderr,"Bad key: '%s', '%s' is not a number\n", buffer, keypart);
                              return GP_ERROR_BAD_PARAMETERS;     
                        }
                        if (*pos == ':')
                              pos++;
                  }
                  if (profile.encryption == 1) { /* WEP 64-bit */
                        if (i != 5) { /* 5*8 = 40 bit + 24 bit (IV) = 64 bit */
                              fprintf(stderr,"Bad key: '%s', %d bit length, should be 40 bit.\n", buffer, i*8);
                              return GP_ERROR_BAD_PARAMETERS;     
                        }
                  }
                  else if (profile.encryption == 2) { /* WEP 128-bit */
                        if (i != 13) { /* 13*8 = 104 bit + 24 bit (IV) = 128 bit */
                              fprintf(stderr,"Bad key: '%s', %d bit length, should be 104 bit.\n", buffer, i*8);
                              return GP_ERROR_BAD_PARAMETERS;     
                        }
                  }
            }

            ptp_nikon_writewifiprofile(&(camera->pl->params), &profile);
      }
      return (GP_OK);
}

static struct submenu create_wifi_profile_submenu[] = {
      { N_("Profile name"), "name", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_prop, _put_nikon_wifi_profile_prop },
      { N_("Wifi essid"), "essid", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_prop, _put_nikon_wifi_profile_prop },
      { N_("IP address (empty for DHCP)"), "ipaddr", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_prop, _put_nikon_wifi_profile_prop },
      { N_("Network mask"), "netmask", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_prop, _put_nikon_wifi_profile_prop },
      { N_("Default gateway"), "gw", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_prop, _put_nikon_wifi_profile_prop },
      { N_("Access mode"), "accessmode", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_accessmode, _put_nikon_wifi_profile_accessmode },
      { N_("Wifi channel"), "channel", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_channel, _put_nikon_wifi_profile_channel },
      { N_("Encryption"), "encryption", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_encryption, _put_nikon_wifi_profile_encryption },
      { N_("Encryption key (hex)"), "key", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_prop, _put_nikon_wifi_profile_prop },
      { N_("Write"), "write", 0, PTP_VENDOR_NIKON, 0, _get_nikon_wifi_profile_write, _put_nikon_wifi_profile_write },
      { 0,0,0,0,0,0,0 },
};

static int
_get_nikon_create_wifi_profile (CONFIG_GET_ARGS)
{
      int submenuno;
      CameraWidget *subwidget;
      
      gp_widget_new (GP_WIDGET_SECTION, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);

      for (submenuno = 0; create_wifi_profile_submenu[submenuno].name ; submenuno++ ) {
            struct submenu *cursub = create_wifi_profile_submenu+submenuno;

            cursub->getfunc (camera, &subwidget, cursub, NULL);
            gp_widget_append (*widget, subwidget);
      }
      
      return GP_OK;
}

static int
_put_nikon_create_wifi_profile (CONFIG_PUT_ARGS)
{
      int submenuno, ret;
      CameraWidget *subwidget;
      
      for (submenuno = 0; create_wifi_profile_submenu[submenuno].name ; submenuno++ ) {
            struct submenu *cursub = create_wifi_profile_submenu+submenuno;

            ret = gp_widget_get_child_by_label (widget, _(cursub->label), &subwidget);
            if (ret != GP_OK)
                  continue;

            if (!gp_widget_changed (subwidget))
                  continue;

            ret = cursub->putfunc (camera, subwidget, NULL, NULL);
      }

      return GP_OK;
}

static struct submenu wifi_profiles_menu[] = {
      /* wifi */
      { N_("List Wifi profiles"), "list", 0, PTP_VENDOR_NIKON, 0, _get_nikon_list_wifi_profiles, _put_nikon_list_wifi_profiles },
      { N_("Create Wifi profile"), "new", 0, PTP_VENDOR_NIKON, 0, _get_nikon_create_wifi_profile, _put_nikon_create_wifi_profile },
      { 0,0,0,0,0,0,0 },
};

/* Wifi profiles menu is a non-standard menu, because putfunc is always
 * called on each submenu, whether or not the value has been changed. */
static int
_get_wifi_profiles_menu (CONFIG_MENU_GET_ARGS)
{
      CameraWidget *subwidget;
      int submenuno;

      gp_widget_new (GP_WIDGET_SECTION, _(menu->label), widget);
      gp_widget_set_name (*widget, menu->name);

      if (camera->pl->params.deviceinfo.VendorExtensionID != PTP_VENDOR_NIKON)
            return (GP_ERROR_NOT_SUPPORTED);

      for (submenuno = 0; wifi_profiles_menu[submenuno].name ; submenuno++ ) {
            struct submenu *cursub = wifi_profiles_menu+submenuno;

            cursub->getfunc (camera, &subwidget, cursub, NULL);
            gp_widget_append (*widget, subwidget);
      }

      return GP_OK;
}

static int
_put_wifi_profiles_menu (CONFIG_MENU_PUT_ARGS)
{
      int submenuno, ret;
      CameraWidget *subwidget;
      
      for (submenuno = 0; wifi_profiles_menu[submenuno].name ; submenuno++ ) {
            struct submenu *cursub = wifi_profiles_menu+submenuno;

            ret = gp_widget_get_child_by_label (widget, _(cursub->label), &subwidget);
            if (ret != GP_OK)
                  continue;

            ret = cursub->putfunc (camera, subwidget, NULL, NULL);
      }

      return GP_OK;
}

static struct submenu camera_settings_menu[] = {
      { N_("Camera Owner"), "owner", PTP_DPC_CANON_CameraOwner, PTP_VENDOR_CANON, PTP_DTC_AUINT8, _get_AUINT8_as_CHAR_ARRAY, _put_AUINT8_as_CHAR_ARRAY },
      { N_("Camera Model"), "model", PTP_DPC_CANON_CameraModel, PTP_VENDOR_CANON, PTP_DTC_STR, _get_STR, _put_None },
      { N_("Firmware Version"), "firmwareversion", PTP_DPC_CANON_FirmwareVersion, PTP_VENDOR_CANON, PTP_DTC_UINT32, _get_CANON_FirmwareVersion, _put_None },
      { N_("Camera Time"),  "time", PTP_DPC_CANON_UnixTime,     PTP_VENDOR_CANON, PTP_DTC_UINT32, _get_UINT32_as_time, _put_UINT32_as_time },
      { N_("Camera Time"),  "eos-time", PTP_DPC_CANON_EOS_CameraTime,     PTP_VENDOR_CANON, PTP_DTC_UINT32, _get_UINT32_as_time, _put_UINT32_as_time },
      { N_("Camera Time"),  "time", PTP_DPC_DateTime,           0,                PTP_DTC_STR, _get_STR_as_time, _put_STR_as_time },
      { N_("Beep Mode"),  "beep",   PTP_DPC_CANON_BeepMode,     PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_BeepMode, _put_Canon_BeepMode },
        { N_("Image Comment"), "imgcomment", PTP_DPC_NIKON_ImageCommentString, PTP_VENDOR_NIKON, PTP_DTC_STR, _get_STR, _put_STR },
        { N_("LCD Off Time"), "lcdofftime", PTP_DPC_NIKON_MonitorOff, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_LCDOffTime, _put_Nikon_LCDOffTime },
        { N_("Meter Off Time"), "meterofftime", PTP_DPC_NIKON_MeterOff, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_MeterOffTime, _put_Nikon_MeterOffTime },
        { N_("CSM Menu"), "csmmenu", PTP_DPC_NIKON_CSMMenu, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8 },
        { N_("Battery Level"), "battery", PTP_DPC_BatteryLevel, 0, PTP_DTC_UINT8, _get_BatteryLevel, _put_None },

/* virtual */
      { N_("Fast Filesystem"), "fastfs", 0, PTP_VENDOR_NIKON, 0, _get_Nikon_FastFS, _put_Nikon_FastFS },
      { N_("Capture Target"), "capturetarget", 0, PTP_VENDOR_NIKON, 0, _get_CaptureTarget, _put_CaptureTarget },
      { N_("Capture Target"), "capturetarget", 0, PTP_VENDOR_CANON, 0, _get_CaptureTarget, _put_CaptureTarget },
      { N_("Capture"), "capture", 0, PTP_VENDOR_CANON, 0, _get_Canon_CaptureMode, _put_Canon_CaptureMode},
      { 0,0,0,0,0,0,0 },
};

/* think of this as properties of the "film" */
static struct submenu image_settings_menu[] = {
        { N_("Image Quality"), "imgquality", PTP_DPC_CompressionSetting, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Compression, _put_Compression},
        { N_("Image Quality"), "imgquality", PTP_DPC_CANON_ImageQuality, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_Quality, _put_Canon_Quality},
        { N_("Image Size"), "imgsize", PTP_DPC_ImageSize, 0, PTP_DTC_STR, _get_ImageSize, _put_ImageSize},
        { N_("Image Size"), "imgsize", PTP_DPC_CANON_ImageSize, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_Size, _put_Canon_Size},
        { N_("ISO Speed"), "iso", PTP_DPC_CANON_ISOSpeed, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_ISO, _put_Canon_ISO},
        { N_("EOS ISO Speed"), "eos-iso", PTP_DPC_CANON_EOS_ISOSpeed, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_ISO, _put_Canon_ISO},
      { N_("WhiteBalance"), "whitebalance", PTP_DPC_CANON_WhiteBalance, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_WhiteBalance, _put_Canon_WhiteBalance},
      { N_("EOS WhiteBalance"), "eos-whitebalance", PTP_DPC_CANON_EOS_WhiteBalance, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_EOS_WhiteBalance, _put_Canon_EOS_WhiteBalance},
      { N_("WhiteBalance"), "whitebalance", PTP_DPC_WhiteBalance, 0, PTP_DTC_UINT16, _get_WhiteBalance, _put_WhiteBalance},
      { N_("Photo Effect"), "photoeffect", PTP_DPC_CANON_PhotoEffect, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_PhotoEffect, _put_Canon_PhotoEffect},
      { N_("Color Model"), "colormodel", PTP_DPC_NIKON_ColorModel, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_ColorModel, _put_Nikon_ColorModel},
      { N_("Auto ISO"), "autoiso", PTP_DPC_NIKON_ISOAuto, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
        { 0,0,0,0,0,0,0 },
};

static struct submenu capture_settings_menu[] = {
        { N_("Long Exp Noise Reduction"), "longexpnr", PTP_DPC_NIKON_LongExposureNoiseReduction, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
        { N_("Auto Focus Mode"), "autofocusmode", PTP_DPC_NIKON_AutofocusMode, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Auto Focus Mode 2"), "autofocusmode2", PTP_DPC_NIKON_A4AFActivation, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Zoom"), "zoom", PTP_DPC_CANON_Zoom, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_ZoomRange, _put_Canon_ZoomRange},
      { N_("Assist Light"), "assistlight", PTP_DPC_CANON_AssistLight, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_AssistLight, _put_Canon_AssistLight},
      { N_("Assist Light"), "assistlight", PTP_DPC_NIKON_AFAssist, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Exposure Compensation"), "exposurecompensation", PTP_DPC_CANON_ExpCompensation, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_ExpCompensation, _put_Canon_ExpCompensation},
      { N_("EOS Exposure Compensation"), "eos-exposurecompensation", PTP_DPC_CANON_EOS_ExpCompensation, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_ExpCompensation2, _put_Canon_ExpCompensation2},
      { N_("Flash Mode"), "canonflashmode", PTP_DPC_CANON_FlashMode, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_FlashMode, _put_Canon_FlashMode},
      { N_("Flash Mode"), "nikonflashmode", PTP_DPC_NIKON_FlashMode, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_FlashMode, _put_Nikon_FlashMode},
      { N_("AF Area Illumination"), "af-area-illumination", PTP_DPC_NIKON_AFAreaIllumination, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_AFAreaIllum, _put_Nikon_AFAreaIllum},
      { N_("AF Beep Mode"), "afbeep", PTP_DPC_NIKON_BeepOff, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_BeepMode, _put_Nikon_BeepMode},
        { N_("F Number"), "f-number", PTP_DPC_FNumber, 0, PTP_DTC_UINT16, _get_FNumber, _put_FNumber},
        { N_("Focal Length"), "focallength", PTP_DPC_FocalLength, 0, PTP_DTC_UINT32, _get_FocalLength, _put_FocalLength},
        { N_("Focus Mode"), "focusmode", PTP_DPC_FocusMode, 0, PTP_DTC_UINT16, _get_FocusMode, _put_FocusMode},
        { N_("ISO Speed"), "iso", PTP_DPC_ExposureIndex, 0, PTP_DTC_UINT16, _get_ISO, _put_ISO},
        { N_("Exposure Bias Compensation"), "exposurebiascompensation", PTP_DPC_ExposureBiasCompensation, 0, PTP_DTC_INT16, _get_ExpCompensation, _put_ExpCompensation},
        { N_("Exposure Time"), "exptime", PTP_DPC_ExposureTime, 0, PTP_DTC_UINT32, _get_ExpTime, _put_ExpTime},
        { N_("Effect Mode"), "effectmode", PTP_DPC_EffectMode, 0, PTP_DTC_UINT16, _get_EffectMode, _put_EffectMode},
        { N_("Exposure Program"), "expprogram", PTP_DPC_ExposureProgramMode, 0, PTP_DTC_UINT16, _get_ExposureProgram, _put_ExposureProgram},
        { N_("Still Capture Mode"), "capturemode", PTP_DPC_StillCaptureMode, 0, PTP_DTC_UINT16, _get_CaptureMode, _put_CaptureMode},
        { N_("Canon Shooting Mode"), "shootingmode", PTP_DPC_CANON_ShootingMode, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_ShootMode, _put_Canon_ShootMode},
        { N_("Picture Style"), "picturestyle", PTP_DPC_CANON_EOS_PictureStyle, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_EOS_PictureStyle, _put_Canon_EOS_PictureStyle},
        { N_("Focus Metering Mode"), "focusmetermode", PTP_DPC_FocusMeteringMode, 0, PTP_DTC_UINT16, _get_FocusMetering, _put_FocusMetering},
        { N_("Exposure Metering Mode"), "exposuremetermode", PTP_DPC_ExposureMeteringMode, 0, PTP_DTC_UINT16, _get_ExposureMetering, _put_ExposureMetering},
        { N_("Flash Mode"), "flashmode", PTP_DPC_FlashMode, 0, PTP_DTC_UINT16, _get_FlashMode, _put_FlashMode},
      { N_("Aperture"), "aperture", PTP_DPC_CANON_Aperture, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_Aperture, _put_Canon_Aperture},
      { N_("EOS Aperture"), "eos-aperture", PTP_DPC_CANON_EOS_Aperture, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_Aperture, _put_Canon_Aperture},
      { N_("Focusing Point"), "focusingpoint", PTP_DPC_CANON_FocusingPoint, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_FocusingPoint, _put_Canon_FocusingPoint},
      { N_("Shutter Speed"), "shutterspeed", PTP_DPC_CANON_ShutterSpeed, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_ShutterSpeed, _put_Canon_ShutterSpeed},
      { N_("EOS Shutter Speed"), "eos-shutterspeed", PTP_DPC_CANON_EOS_ShutterSpeed, PTP_VENDOR_CANON, PTP_DTC_UINT16, _get_Canon_ShutterSpeed, _put_Canon_ShutterSpeed},
      { N_("Metering Mode"), "meteringmode", PTP_DPC_CANON_MeteringMode, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_MeteringMode, _put_Canon_MeteringMode},
      { N_("EOS Metering Mode"), "eos-meteringmode", PTP_DPC_CANON_EOS_MeteringMode, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_EOS_MeteringMode, _put_Canon_EOS_MeteringMode},
        { N_("AF Distance"), "afdistance", PTP_DPC_CANON_AFDistance, PTP_VENDOR_CANON, PTP_DTC_UINT8, _get_Canon_AFDistance, _put_Canon_AFDistance},
      { N_("Focus Area Wrap"), "focusareawrap", PTP_DPC_NIKON_FocusAreaWrap, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Exposure Lock"), "exposurelock", PTP_DPC_NIKON_AELockMode, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("AE-L/AF-L Mode"), "aelaflmode", PTP_DPC_NIKON_AELAFLMode, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_AELAFLMode, _put_Nikon_AELAFLMode},
      { N_("File Number Sequencing"), "filenrsequencing", PTP_DPC_NIKON_FileNumberSequence, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Flash Sign"), "flashsign", PTP_DPC_NIKON_FlashSign, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Viewfinder Grid"), "viewfindergrid", PTP_DPC_NIKON_GridDisplay, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Image Review"), "imagereview", PTP_DPC_NIKON_ImageReview, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Image Rotation Flag"), "imagerotationflag", PTP_DPC_NIKON_ImageRotation, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Release without CF card"), "nocfcardrelease", PTP_DPC_NIKON_NoCFCard, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OnOff_UINT8, _put_Nikon_OnOff_UINT8},
      { N_("Flash Mode Manual Power"), "flashmodemanualpower", PTP_DPC_NIKON_FlashModeManualPower, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_FlashModeManualPower, _put_Nikon_FlashModeManualPower},
      { N_("Auto Focus Area"), "autofocusarea", PTP_DPC_NIKON_AutofocusArea, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_AutofocusArea, _put_Nikon_AutofocusArea},
      { N_("Flash Exposure Compensation"), "flashexposurecompensation", PTP_DPC_NIKON_FlashExposureCompensation, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_FlashExposureCompensation, _put_Nikon_FlashExposureCompensation},
      { N_("Bracket Set"), "bracketset", PTP_DPC_NIKON_BracketSet, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_BracketSet, _put_Nikon_BracketSet},
      { N_("Bracket Order"), "bracketorder", PTP_DPC_NIKON_BracketOrder, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_BracketOrder, _put_Nikon_BracketOrder},
      { N_("Burst Number"), "burstnumber", PTP_DPC_BurstNumber, 0, PTP_DTC_UINT16, _get_BurstNumber, _put_BurstNumber},
      { N_("Auto Whitebalance Bias"), "autowhitebias", PTP_DPC_NIKON_WhiteBalanceAutoBias, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_WBBias, _put_Nikon_WBBias},
      { N_("Tungsten Whitebalance Bias"), "tungstenwhitebias", PTP_DPC_NIKON_WhiteBalanceTungstenBias, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_WBBias, _put_Nikon_WBBias},
      { N_("Fluorescent Whitebalance Bias"), "flourescentwhitebias", PTP_DPC_NIKON_WhiteBalanceFluorescentBias, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_WBBias, _put_Nikon_WBBias},
      { N_("Daylight Whitebalance Bias"), "daylightwhitebias", PTP_DPC_NIKON_WhiteBalanceDaylightBias, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_WBBias, _put_Nikon_WBBias},
      { N_("Flash Whitebalance Bias"), "flashwhitebias", PTP_DPC_NIKON_WhiteBalanceFlashBias, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_WBBias, _put_Nikon_WBBias},
      { N_("Cloudy Whitebalance Bias"), "cloudywhitebias", PTP_DPC_NIKON_WhiteBalanceCloudyBias, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_WBBias, _put_Nikon_WBBias},
      { N_("Shade Whitebalance Bias"), "shadewhitebias", PTP_DPC_NIKON_WhiteBalanceShadeBias, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_WBBias, _put_Nikon_WBBias},
        { N_("Selftimer Delay"), "selftimerdelay", PTP_DPC_NIKON_SelfTimer, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_SelfTimerDelay, _put_Nikon_SelfTimerDelay },
        { N_("Center Weight Area"), "centerweightsize", PTP_DPC_NIKON_CenterWeightArea, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_CenterWeight, _put_Nikon_CenterWeight },
        { N_("Flash Shutter Speed"), "flashshutterspeed", PTP_DPC_NIKON_FlashShutterSpeed, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_FlashShutterSpeed, _put_Nikon_FlashShutterSpeed },
        { N_("Remote Timeout"), "remotetimeout", PTP_DPC_NIKON_RemoteTimeout, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_RemoteTimeout, _put_Nikon_RemoteTimeout },
        { N_("Optimize Image"), "optimizeimage", PTP_DPC_NIKON_OptimizeImage, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_OptimizeImage, _put_Nikon_OptimizeImage },
        { N_("Sharpening"), "sharpening", PTP_DPC_NIKON_ImageSharpening, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_Sharpening, _put_Nikon_Sharpening },
        { N_("Tone Compensation"), "tonecompensation", PTP_DPC_NIKON_ToneCompensation, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_ToneCompensation, _put_Nikon_ToneCompensation },
        { N_("Saturation"), "saturation", PTP_DPC_NIKON_Saturation, PTP_VENDOR_NIKON, PTP_DTC_UINT8, _get_Nikon_Saturation, _put_Nikon_Saturation },
        { N_("Hue Adjustment"), "hueadjustment", PTP_DPC_NIKON_HueAdjustment, PTP_VENDOR_NIKON, PTP_DTC_INT8, _get_Nikon_HueAdjustment, _put_Nikon_HueAdjustment },
      /* { N_("Viewfinder Mode"), "viewfinder", PTP_DPC_CANON_ViewFinderMode, PTP_VENDOR_CANON, PTP_DTC_UINT32, _get_Canon_ViewFinderMode, _put_Canon_ViewFinderMode}, */
      { N_("Focus Lock"), "focuslock", 0, PTP_VENDOR_CANON, 0, _get_Canon_FocusLock, _put_Canon_FocusLock},
      { 0,0,0,0,0,0,0 },
};

static struct menu menus[] = {
      { N_("Camera Settings"), "settings", camera_settings_menu, NULL, NULL },
      { N_("Image Settings"), "imgsettings", image_settings_menu, NULL, NULL },
      { N_("Capture Settings"), "capturesettings", capture_settings_menu, NULL, NULL },
      { N_("Wifi profiles"), "wifiprofiles", NULL, _get_wifi_profiles_menu, _put_wifi_profiles_menu },
};

int
camera_get_config (Camera *camera, CameraWidget **window, GPContext *context)
{
      CameraWidget *section, *widget;
      int menuno, submenuno, ret;

      gp_widget_new (GP_WIDGET_WINDOW, _("Camera and Driver Configuration"), window);
      gp_widget_set_name (*window, "main");
      for (menuno = 0; menuno < sizeof(menus)/sizeof(menus[0]) ; menuno++ ) {
            if (!menus[menuno].submenus) { /* Custom menu */
                  struct menu *cur = menus+menuno;
                  cur->getfunc(camera, &section, cur);
                  gp_widget_append(*window, section);
                  continue;
            }
            
            /* Standard menu with submenus */
            gp_widget_new (GP_WIDGET_SECTION, _(menus[menuno].label), &section);
            gp_widget_set_name (section, menus[menuno].name);
            gp_widget_append (*window, section);

            for (submenuno = 0; menus[menuno].submenus[submenuno].name ; submenuno++ ) {
                  struct submenu *cursub = menus[menuno].submenus+submenuno;
                  widget = NULL;

                  if (have_prop(camera,cursub->vendorid,cursub->propid)) {
                        if (cursub->propid) {
                              PTPDevicePropDesc dpd;

                              memset(&dpd,0,sizeof(dpd));
                              ptp_getdevicepropdesc(&camera->pl->params,cursub->propid,&dpd);
                              ret = cursub->getfunc (camera, &widget, cursub, &dpd);
                              ptp_free_devicepropdesc(&dpd);
                        } else {
                              ret = cursub->getfunc (camera, &widget, cursub, NULL);
                        }
                        if (ret != GP_OK)
                              continue;
                        gp_widget_append (section, widget);
                        continue;
                  }
                  if (have_eos_prop(camera,cursub->vendorid,cursub->propid)) {
                        PTPDevicePropDesc dpd;

                        gp_log (GP_LOG_DEBUG, "camera_get_config", "Found and adding EOS Property %04x (%s)", cursub->propid, cursub->label);
                        memset(&dpd,0,sizeof(dpd));
                        ptp_canon_eos_getdevicepropdesc (&camera->pl->params,cursub->propid, &dpd);
                        ret = cursub->getfunc (camera, &widget, cursub, &dpd);
                        ptp_free_devicepropdesc(&dpd);
                        if (ret != GP_OK)
                              continue;
                        gp_widget_append (section, widget);
                        continue;
                  }
            }
      }
      return GP_OK;
}

int
camera_set_config (Camera *camera, CameraWidget *window, GPContext *context)
{
      CameraWidget *section, *widget, *subwindow;
      int menuno, submenuno, ret;

      ret = gp_widget_get_child_by_label (window, _("Camera and Driver Configuration"), &subwindow);
      if (ret != GP_OK)
            return ret;
      for (menuno = 0; menuno < sizeof(menus)/sizeof(menus[0]) ; menuno++ ) {
            ret = gp_widget_get_child_by_label (subwindow, _(menus[menuno].label), &section);
            if (ret != GP_OK)
                  continue;

            if (!menus[menuno].submenus) { /* Custom menu */
                  struct menu *cur = menus+menuno;
                  cur->putfunc(camera, section);
                  continue;
            }
            
            /* Standard menu with submenus */

            for (submenuno = 0; menus[menuno].submenus[submenuno].label ; submenuno++ ) {
                  PTPPropertyValue  propval;

                  struct submenu *cursub = menus[menuno].submenus+submenuno;
                  ret = gp_widget_get_child_by_label (section, _(cursub->label), &widget);
                  if (ret != GP_OK)
                        continue;

                  gp_log (GP_LOG_DEBUG, "camera_set_config", "Checking Property %04x (%s)", cursub->propid, cursub->label);
                  if (!gp_widget_changed (widget))
                        continue;

                  gp_log (GP_LOG_DEBUG, "camera_set_config", "Found and setting Property %04x (%s)", cursub->propid, cursub->label);
                  if (have_prop(camera,cursub->vendorid,cursub->propid)) {
                        if (cursub->propid) {
                              PTPDevicePropDesc dpd;

                              memset(&dpd,0,sizeof(dpd));
                              ptp_getdevicepropdesc(&camera->pl->params,cursub->propid,&dpd);
                              ret = cursub->putfunc (camera, widget, &propval, &dpd);
                              if (ret == GP_OK)
                                    ptp_setdevicepropvalue (&camera->pl->params, cursub->propid, &propval, cursub->type);
                              ptp_free_devicepropvalue (cursub->type, &propval);
                              ptp_free_devicepropdesc(&dpd);
                        } else {
                              ret = cursub->putfunc (camera, widget, NULL, NULL);
                        }
                  }
                  if (have_eos_prop(camera,cursub->vendorid,cursub->propid)) {
                        PTPDevicePropDesc dpd;

                        gp_log (GP_LOG_DEBUG, "camera_set_config", "Found and setting EOS Property %04x (%s)", cursub->propid, cursub->label);
                        memset(&dpd,0,sizeof(dpd));
                        ptp_canon_eos_getdevicepropdesc (&camera->pl->params,cursub->propid, &dpd);
                        ret = cursub->putfunc (camera, widget, &propval, &dpd);
                        if (ret == GP_OK)
                              ptp_canon_eos_setdevicepropvalue (&camera->pl->params, cursub->propid, &propval, cursub->type);
                        ptp_free_devicepropdesc(&dpd);
                        ptp_free_devicepropvalue(cursub->type, &propval);
                  }
            }
      }
      return GP_OK;
}

Generated by  Doxygen 1.6.0   Back to index