1 /** \file gphoto2-abilities-list.c
2 * \brief List of supported camera models including their abilities.
4 * \author Copyright 2000 Scott Fritzinger
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 #include <gphoto2/gphoto2-abilities-list.h>
32 #include <gphoto2/gphoto2_slp_support.h>
34 #include <gphoto2/gphoto2-result.h>
35 #include <gphoto2/gphoto2-port-log.h>
36 #include <gphoto2/gphoto2-library.h>
41 # define _(String) dgettext (GETTEXT_PACKAGE, String)
43 # define N_(String) gettext_noop (String)
45 # define N_(String) (String)
48 # define textdomain(String) (String)
49 # define gettext(String) (String)
50 # define dgettext(Domain,Message) (Message)
51 # define dcgettext(Domain,Message,Type) (Message)
52 # define bindtextdomain(Domain,Directory) (Domain)
53 # define bind_textdomain_codeset(Domain,Charset) (Domain)
54 # define _(String) (String)
55 # define N_(String) (String)
59 #define GP_MODULE "gphoto2-abilities-list"
62 #define CHECK_NULL(r) {if (!(r)) return (GP_ERROR_BAD_PARAMETERS);}
64 #define CHECK_RESULT(result) {int r = (result); if (r < 0) return (r);}
66 #define CHECK_MEM(m) {if (!(m)) return (GP_ERROR_NO_MEMORY);}
69 struct _CameraAbilitiesList {
71 CameraAbilities *abilities;
75 static int gp_abilities_list_lookup_id (CameraAbilitiesList *, const char *);
77 static int gp_abilities_list_sort (CameraAbilitiesList *);
80 * \brief Set the current character codeset libgphoto2 is operating in.
82 * Set the codeset for all messages returned by libgphoto2.
83 * \param codeset New codeset for the messages. For instance "utf-8".
84 * \return old codeset as returned from bind_textdomain_codeset().
86 * You would then call gp_abilities_list_load() in order to
90 gp_message_codeset (const char *codeset)
92 gp_port_message_codeset (codeset);
93 return bind_textdomain_codeset (GETTEXT_PACKAGE, codeset);
97 * \brief Allocate the memory for a new abilities list.
99 * Function to allocate the memory for a new abilities list.
100 * \param list CameraAbilitiesList object to initialize
101 * \return gphoto2 error code
103 * You would then call gp_abilities_list_load() in order to
107 gp_abilities_list_new (CameraAbilitiesList **list)
112 * We do this here because everybody needs to call this function
113 * first before accessing a camera. Pretty ugly, but I don't know
114 * an other way without introducing a global initialization
117 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
119 CHECK_MEM (*list = malloc (sizeof (CameraAbilitiesList)));
120 memset (*list, 0, sizeof (CameraAbilitiesList));
126 * \brief Free the given CameraAbilitiesList object.
128 * \param list a CameraAbilitiesList
129 * \return a gphoto2 error code
132 gp_abilities_list_free (CameraAbilitiesList *list)
136 CHECK_RESULT (gp_abilities_list_reset (list));
151 foreach_func (const char *filename, lt_ptr data)
153 foreach_data_t *fd = data;
154 CameraList *list = fd->list;
156 gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
157 "Found '%s'.", filename);
158 fd->result = gp_list_append (list, filename, NULL);
160 return ((fd->result == GP_OK)?0:1);
165 gp_abilities_list_load_dir (CameraAbilitiesList *list, const char *dir,
168 CameraLibraryIdFunc id;
169 CameraLibraryAbilitiesFunc ab;
171 int ret, x, old_count, new_count;
173 const char *filename;
178 CHECK_NULL (list && dir);
180 gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
181 "Using ltdl to load camera libraries from '%s'...", dir);
182 CHECK_RESULT (gp_list_new (&flist));
183 ret = gp_list_reset (flist);
185 gp_list_free (flist);
188 if (1) { /* a new block in which we can define a temporary variable */
190 foreach_data_t foreach_data = { NULL, GP_OK };
191 foreach_data.list = flist;
193 lt_dladdsearchdir (dir);
194 ret = lt_dlforeachfile (dir, foreach_func, &foreach_data);
197 gp_list_free (flist);
198 gp_log (GP_LOG_ERROR, "gp-abilities-list",
199 "Internal error looking for camlibs (%d)", ret);
200 gp_context_error (context,
201 _("Internal error looking for camlibs. "
202 "(path names too long?)"));
203 return (foreach_data.result!=GP_OK)?foreach_data.result:GP_ERROR;
206 count = gp_list_count (flist);
208 gp_list_free (flist);
211 gp_log (GP_LOG_DEBUG, "gp-abilities-list", "Found %i "
212 "camera drivers.", count);
214 p = gp_context_progress_start (context, count,
215 _("Loading camera drivers from '%s'..."), dir);
216 for (i = 0; i < count; i++) {
217 ret = gp_list_get_name (flist, i, &filename);
219 gp_list_free (flist);
222 lh = lt_dlopenext (filename);
224 gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
225 "Failed to load '%s': %s.", filename,
231 id = lt_dlsym (lh, "camera_id");
233 gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
234 "Library '%s' does not seem to "
235 "contain a camera_id function: %s",
236 filename, lt_dlerror ());
242 * Make sure the camera driver hasn't been
245 if (id (&text) != GP_OK) {
249 if (gp_abilities_list_lookup_id (list, text.text) >= 0) {
254 /* camera_abilities */
255 ab = lt_dlsym (lh, "camera_abilities");
257 gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
258 "Library '%s' does not seem to "
259 "contain a camera_abilities function: "
260 "%s", filename, lt_dlerror ());
265 old_count = gp_abilities_list_count (list);
271 if (ab (list) != GP_OK) {
278 new_count = gp_abilities_list_count (list);
282 /* Copy in the core-specific information */
283 for (x = old_count; x < new_count; x++) {
284 strcpy (list->abilities[x].id, text.text);
285 strcpy (list->abilities[x].library, filename);
288 gp_context_progress_update (context, p, i);
289 if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
291 gp_list_free (flist);
292 return (GP_ERROR_CANCEL);
295 gp_context_progress_stop (context, p);
297 gp_list_free (flist);
304 * \brief Scans the system for camera drivers.
306 * \param list a CameraAbilitiesList
307 * \param context a GPContext
308 * \return a gphoto2 error code
310 * All supported camera models will then be added to the list.
314 gp_abilities_list_load (CameraAbilitiesList *list, GPContext *context)
316 const char *camlib_env = getenv(CAMLIBDIR_ENV);
317 const char *camlibs = (camlib_env != NULL)?camlib_env:CAMLIBS;
320 CHECK_RESULT (gp_abilities_list_load_dir (list, camlibs, context));
321 CHECK_RESULT (gp_abilities_list_sort (list));
328 gp_abilities_list_detect_usb (CameraAbilitiesList *list,
329 int *ability, GPPort *port)
331 int i, count, res = GP_ERROR_IO_USB_FIND;
333 CHECK_RESULT (count = gp_abilities_list_count (list));
335 /* Detect USB cameras */
336 gp_log (GP_LOG_VERBOSE, __FILE__,
337 "Auto-detecting USB cameras...");
339 for (i = 0; i < count; i++) {
342 if (!(list->abilities[i].port & port->type))
345 v = list->abilities[i].usb_vendor;
346 p = list->abilities[i].usb_product;
348 res = gp_port_usb_find_device(port, v, p);
350 gp_log(GP_LOG_DEBUG, __FILE__,
351 "Found '%s' (0x%x,0x%x)",
352 list->abilities[i].model,
355 } else if (res < 0 && res != GP_ERROR_IO_USB_FIND) {
356 /* another error occurred.
357 * perhaps we should better
358 * report this to the calling
361 gp_log(GP_LOG_DEBUG, __FILE__,
362 "gp_port_usb_find_device(vendor=0x%x, "
363 "product=0x%x) returned %i, clearing "
364 "error message on port", v, p, res);
367 if (res != GP_ERROR_IO_USB_FIND)
371 c = list->abilities[i].usb_class;
372 s = list->abilities[i].usb_subclass;
373 p = list->abilities[i].usb_protocol;
375 res = gp_port_usb_find_device_by_class(port, c, s, p);
377 gp_log(GP_LOG_DEBUG, __FILE__,
378 "Found '%s' (0x%x,0x%x,0x%x)",
379 list->abilities[i].model,
382 } else if (res < 0 && res != GP_ERROR_IO_USB_FIND) {
383 /* another error occurred.
384 * perhaps we should better
385 * report this to the calling
388 gp_log(GP_LOG_DEBUG, __FILE__,
389 "gp_port_usb_find_device_by_class("
390 "class=0x%x, subclass=0x%x, "
391 "protocol=0x%x) returned %i, "
392 "clearing error message on port",
396 if (res != GP_ERROR_IO_USB_FIND)
406 * \param list a CameraAbilitiesList
407 * \param info_list the GPPortInfoList of ports to use for detection
408 * \param l a #CameraList that contains the autodetected cameras after the call
409 * \param context a #GPContext
411 * Tries to detect any camera connected to the computer using the supplied
412 * list of supported cameras and the supplied info_list of ports.
414 * \return a gphoto2 error code
417 gp_abilities_list_detect (CameraAbilitiesList *list,
418 GPPortInfoList *info_list, CameraList *l,
425 CHECK_NULL (list && info_list && l);
429 CHECK_RESULT (info_count = gp_port_info_list_count (info_list));
431 CHECK_RESULT (gp_port_new (&port));
432 for (i = 0; i < info_count; i++) {
435 CHECK_RESULT (gp_port_info_list_get_info (info_list, i, &info));
436 CHECK_RESULT (gp_port_set_info (port, info));
439 case GP_PORT_USB_SCSI:
440 case GP_PORT_USB_DISK_DIRECT: {
442 res = gp_abilities_list_detect_usb (list, &ability, port);
445 list->abilities[ability].model,
448 gp_port_set_error (port, NULL);
456 s = strchr (info.path, ':');
460 snprintf (path, sizeof(path), "%s/DCIM", s);
461 if (-1 == stat(path, &stbuf)) {
462 snprintf (path, sizeof(path), "%s/dcim", s);
463 if (-1 == stat(path, &stbuf))
466 gp_list_append (l, "Mass Storage Camera", info.path);
469 case GP_PORT_PTPIP: {
472 s = strchr (info.path, ':');
475 if (!strlen(s)) break;
476 gp_list_append (l, "PTP/IP Camera", info.path);
481 * We currently cannot detect any cameras on this
495 * \brief Remove first colon from string, if any. Replace it by a space.
496 * \param str a char * string
499 remove_colon_from_string (char *str)
502 ch = strchr(str, ':');
510 * \brief Append the abilities to the list.
511 * \param list CameraAbilitiesList
512 * \param abilities CameraAbilities
513 * \return a gphoto2 error code
515 * This function is called by a camera library on camera_abilities()
516 * in order to inform libgphoto2 about a supported camera model.
520 gp_abilities_list_append (CameraAbilitiesList *list, CameraAbilities abilities)
522 CameraAbilities *new_abilities;
527 new_abilities = malloc (sizeof (CameraAbilities));
529 new_abilities = realloc (list->abilities,
530 sizeof (CameraAbilities) * (list->count + 1));
531 CHECK_MEM (new_abilities);
532 list->abilities = new_abilities;
534 memcpy (&(list->abilities [list->count]), &abilities,
535 sizeof (CameraAbilities));
537 /* FIXME: We replace the colon by a space in the model string
538 * This keeps backward compatibility until we have
539 * thought of and implemented something better.
541 remove_colon_from_string(list->abilities[list->count].model);
550 * \brief Reset the list.
551 * \param list a CameraAbilitiesList
552 * \return a gphoto2 error code
555 gp_abilities_list_reset (CameraAbilitiesList *list)
559 if (list->abilities) {
560 free (list->abilities);
561 list->abilities = NULL;
570 * \brief Count the entries in the supplied list.
571 * \param list a #CameraAbilitiesList
572 * \returns The number of entries or a gphoto2 error code
575 gp_abilities_list_count (CameraAbilitiesList *list)
579 return (list->count);
583 cmp_abilities (const void *a, const void *b) {
584 const CameraAbilities *ca = a;
585 const CameraAbilities *cb = b;
587 return strcasecmp (ca->model, cb->model);
591 gp_abilities_list_sort (CameraAbilitiesList *list)
595 qsort (list->abilities, list->count, sizeof(CameraAbilities), cmp_abilities);
601 gp_abilities_list_lookup_id (CameraAbilitiesList *list, const char *id)
605 CHECK_NULL (list && id);
607 for (x = 0; x < list->count; x++)
608 if (!strcmp (list->abilities[x].id, id))
616 * \brief Search the list for an entry of given model name
617 * \param list a #CameraAbilitiesList
618 * \param model a camera model name
619 * \return Index of entry or gphoto2 error code
622 gp_abilities_list_lookup_model (CameraAbilitiesList *list, const char *model)
626 CHECK_NULL (list && model);
628 for (x = 0; x < list->count; x++) {
629 if (!strcasecmp (list->abilities[x].model, model))
633 gp_log (GP_LOG_ERROR, "gphoto2-abilities-list", _("Could not find "
634 "any driver for '%s'"), model);
635 return (GP_ERROR_MODEL_NOT_FOUND);
640 * \brief Retrieve the camera abilities of entry with supplied index number.
642 * \param list a CameraAbilitiesList
644 * \param abilities pointer to CameraAbilities for returned data.
645 * \return a gphoto2 error code
647 * Retrieves the camera abilities of entry with supplied
648 * index number. Typically, you would call gp_camera_set_abilities()
649 * afterwards in order to prepare the initialization of a camera.
652 gp_abilities_list_get_abilities (CameraAbilitiesList *list, int index,
653 CameraAbilities *abilities)
655 CHECK_NULL (list && abilities);
657 if (index < 0 || index >= list->count)
658 return (GP_ERROR_BAD_PARAMETERS);
660 memcpy (abilities, &list->abilities[index], sizeof (CameraAbilities));
666 #ifdef _GPHOTO2_INTERNAL_CODE
668 /* enum CameraOperation */
669 const StringFlagItem gpi_camera_operation_map[] = {
670 { "none", GP_OPERATION_NONE },
671 { "capture_image", GP_OPERATION_CAPTURE_IMAGE },
672 { "capture_video", GP_OPERATION_CAPTURE_VIDEO },
673 { "capture_audio", GP_OPERATION_CAPTURE_AUDIO },
674 { "capture_preview", GP_OPERATION_CAPTURE_PREVIEW },
675 { "config", GP_OPERATION_CONFIG },
679 /* enum CameraFileOperation */
680 const StringFlagItem gpi_file_operation_map[] = {
681 { "none", GP_FILE_OPERATION_NONE },
682 { "delete", GP_FILE_OPERATION_DELETE },
683 { "preview", GP_FILE_OPERATION_PREVIEW },
684 { "raw", GP_FILE_OPERATION_RAW },
685 { "audio", GP_FILE_OPERATION_AUDIO },
686 { "exif", GP_FILE_OPERATION_EXIF },
690 /* enum CameraFolderOperation */
691 const StringFlagItem gpi_folder_operation_map[] = {
692 { "none", GP_FOLDER_OPERATION_NONE },
693 { "delete_all", GP_FOLDER_OPERATION_DELETE_ALL },
694 { "put_file", GP_FOLDER_OPERATION_PUT_FILE },
695 { "make_dir", GP_FOLDER_OPERATION_MAKE_DIR },
696 { "remove_dir", GP_FOLDER_OPERATION_REMOVE_DIR },
700 /* enum GphotoDeviceType */
701 const StringFlagItem gpi_gphoto_device_type_map[] = {
702 { "still_camera", GP_DEVICE_STILL_CAMERA },
703 { "audio_player", GP_DEVICE_AUDIO_PLAYER },
707 /* enum CameraDriverStatus */
708 const StringFlagItem gpi_camera_driver_status_map[] = {
709 { "production", GP_DRIVER_STATUS_PRODUCTION },
710 { "testing", GP_DRIVER_STATUS_TESTING },
711 { "experimental", GP_DRIVER_STATUS_EXPERIMENTAL },
712 { "deprecated", GP_DRIVER_STATUS_DEPRECATED },
716 #endif /* _GPHOTO2_INTERNAL_CODE */
721 * c-file-style:"linux"