Files
libgphoto2/camlibs/gsmart/library.c
2003-01-10 19:24:33 +00:00

445 lines
12 KiB
C

/****************************************************************/
/* library.c - Gphoto2 library for the Mustek gSmart mini 2 */
/* */
/* Copyright © 2002 Till Adam */
/* */
/* Author: Till Adam <till@adam-lilienthal.de> */
/* */
/* This library is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU Library 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 Library General Public License for */
/* more details. */
/* */
/* You should have received a copy of the GNU Library 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. */
/****************************************************************/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gphoto2.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 _(String) (String)
# define N_(String) (String)
#endif
#include "gsmart.h"
#define GP_MODULE "gsmartmini"
#define TIMEOUT 5000
#define GSMART_VERSION "0.3"
#define GSMART_LAST_MOD "08/09/02 - 23:14:11"
/* forward declarations */
static int file_list_func (CameraFilesystem *fs, const char *folder,
CameraList *list, void *data, GPContext *context);
static int get_file_func (CameraFilesystem *fs, const char *folder,
const char *filename, CameraFileType type,
CameraFile *file, void *user_data,
GPContext *context);
static int delete_file_func (CameraFilesystem *fs, const char *folder,
const char *filename, void *data,
GPContext *context);
static int delete_all_func (CameraFilesystem *fs, const char *folder,
void *data, GPContext *context);
static int get_info_func (CameraFilesystem *fs, const char *folder,
const char *filename, CameraFileInfo *info,
void *data, GPContext *context);
/* define what cameras we support */
static struct
{
char *model;
int usb_vendor;
int usb_product;
GsmartBridgeChip bridge;
}
models[] =
{
{
"Mustek:gSmart mini", 0x055f, 0xc220, GSMART_BRIDGE_SPCA500}
, {
"Mustek:gSmart mini 2", 0x055f, 0xc420, GSMART_BRIDGE_SPCA504A}
, {
"Mustek:gSmart mini 3", 0x055f, 0xc520, GSMART_BRIDGE_SPCA504A}
, {
"So. Show 301", 0x0ec7, 0x1008, GSMART_BRIDGE_SPCA504A}
, {
NULL, 0, 0}
};
int
camera_id (CameraText *id)
{
strcpy (id->text, "gsmartmini");
return (GP_OK);
}
int
camera_abilities (CameraAbilitiesList *list)
{
int x = 0;
char *ptr;
CameraAbilities a;
ptr = models[x].model;
while (ptr) {
memset (&a, 0, sizeof (a));
strcpy (a.model, ptr);
a.port = GP_PORT_USB;
a.speed[0] = 0;
if (models[x].bridge == GSMART_BRIDGE_SPCA504A) {
a.operations = GP_OPERATION_CAPTURE_IMAGE;
a.status = GP_DRIVER_STATUS_TESTING;
} else {
a.status = GP_DRIVER_STATUS_EXPERIMENTAL;
}
a.file_operations =
GP_FILE_OPERATION_PREVIEW | GP_FILE_OPERATION_DELETE;
a.folder_operations = GP_FOLDER_OPERATION_DELETE_ALL;
a.usb_vendor = models[x].usb_vendor;
a.usb_product = models[x].usb_product;
gp_abilities_list_append (list, a);
ptr = models[++x].model;
}
return (GP_OK);
}
static int
camera_capture (Camera *camera, CameraCaptureType type,
CameraFilePath * path, GPContext *context)
{
struct GsmartFile *file;
CameraAbilities a;
/* Not all our cameras support capture */
gp_camera_get_abilities (camera, &a);
if (!a.operations & GP_OPERATION_CAPTURE_IMAGE)
return GP_ERROR_NOT_SUPPORTED;
CHECK (gsmart_capture (camera->pl));
CHECK (gsmart_get_info (camera->pl));
CHECK (gsmart_get_file_info
(camera->pl, camera->pl->num_files - 1, &file));
/* Now tell the frontend where to look for the image */
strncpy (path->folder, "/", sizeof (path->folder) - 1);
path->folder[sizeof (path->folder) - 1] = '\0';
strncpy (path->name, file->name, sizeof (path->name) - 1);
path->name[sizeof (path->name) - 1] = '\0';
CHECK (gp_filesystem_append
(camera->fs, path->folder, path->name, context));
return GP_OK;
}
static int
camera_exit (Camera *camera, GPContext *context)
{
if (camera->pl) {
if (camera->pl->fats) {
free (camera->pl->fats);
camera->pl->fats = NULL;
}
if (camera->pl->files) {
free (camera->pl->files);
camera->pl->files = NULL;
}
free (camera->pl);
camera->pl = NULL;
}
return (GP_OK);
}
static int
camera_summary (Camera *camera, CameraText *summary, GPContext *context)
{
char tmp[1024];
/* possibly get # pics, mem free, etc. if needed */
if (camera->pl->dirty)
CHECK (gsmart_get_info (camera->pl));
snprintf (tmp, sizeof (tmp),
"Files: %d\n Images: %4d\n Movies: %4d\nSpace used: %8d\nSpace free: %8d\n",
camera->pl->num_files, camera->pl->num_images,
camera->pl->num_movies, camera->pl->size_used,
camera->pl->size_free);
strcat (summary->text, tmp);
return (GP_OK);
}
static int
camera_about (Camera *camera, CameraText *about, GPContext *context)
{
strcpy (about->text,
_("gsmart library v" GSMART_VERSION
" " GSMART_LAST_MOD "\n"
"Till Adam <till@adam-lilienthal.de>\n"
"Support for the Mustek gSmart mini series of digital "
"cameras based on several other gphoto2 camlib modules and "
"the windows driver source kindly provided by Mustek.\n"
"\n"));
return (GP_OK);
}
int
camera_init (Camera *camera, GPContext *context)
{
int ret;
int x = 0;
char *model;
GPPortSettings settings;
CameraAbilities abilities;
/* First, set up all the function pointers */
camera->functions->exit = camera_exit;
camera->functions->summary = camera_summary;
camera->functions->about = camera_about;
camera->functions->capture = camera_capture;
CHECK (gp_port_get_settings (camera->port, &settings));
switch (camera->port->type) {
case GP_PORT_USB:
settings.usb.inep = 0x82;
settings.usb.outep = 0x03;
settings.usb.config = 1;
settings.usb.interface = 0;
settings.usb.altsetting = 0;
CHECK (gp_port_set_settings (camera->port, settings));
CHECK (gp_port_set_timeout (camera->port, TIMEOUT));
break;
default:
gp_context_error (context,
_("Unsupported port type: %d. "
"This driver only works with USB "
"cameras.\n"), camera->port->type);
return (GP_ERROR);
break;
}
camera->pl = malloc (sizeof (CameraPrivateLibrary));
if (!camera->pl)
return (GP_ERROR_NO_MEMORY);
memset (camera->pl, 0, sizeof (CameraPrivateLibrary));
camera->pl->gpdev = camera->port;
camera->pl->dirty = 1;
/* What bridge chip is inside the camera? The Gsmart mini is spca500
* based, while the others have a spca504a */
gp_camera_get_abilities (camera, &abilities);
model = models[x].model;
while (model) {
if (!strcmp (model, abilities.model)) {
camera->pl->bridge = models[x].bridge;
break;
}
model = models[++x].model;
}
ret = gsmart_reset (camera->pl);
if (ret < 0) {
gp_context_error (context, _("Could not reset camera.\n"));
free (camera->pl);
camera->pl = NULL;
return (ret);
}
/* Set up the CameraFilesystem */
CHECK (gp_filesystem_set_list_funcs
(camera->fs, file_list_func, NULL, camera));
CHECK (gp_filesystem_set_file_funcs
(camera->fs, get_file_func, delete_file_func, camera));
CHECK (gp_filesystem_set_info_funcs
(camera->fs, get_info_func, NULL, camera));
CHECK (gp_filesystem_set_folder_funcs
(camera->fs, NULL, delete_all_func, NULL, NULL, camera));
return (GP_OK);
}
static int
file_list_func (CameraFilesystem *fs, const char *folder,
CameraList *list, void *data, GPContext *context)
{
Camera *camera = data;
int i;
char temp_file[14];
if (camera->pl->dirty)
CHECK (gsmart_get_info (camera->pl));
for (i = 0; i < camera->pl->num_files; i++) {
strncpy (temp_file, camera->pl->files[i].name, 12);
temp_file[12] = 0;
gp_list_append (list, temp_file, NULL);
}
return GP_OK;
}
static int
get_file_func (CameraFilesystem *fs, const char *folder,
const char *filename, CameraFileType type,
CameraFile *file, void *user_data, GPContext *context)
{
Camera *camera = user_data;
unsigned char *data = NULL;
int size, number, filetype;
CHECK (number =
gp_filesystem_number (camera->fs, folder, filename, context));
switch (type) {
case GP_FILE_TYPE_NORMAL:
CHECK (gsmart_request_file
(camera->pl, &data, &size, number, &filetype));
if (filetype == GSMART_FILE_TYPE_IMAGE) {
CHECK (gp_file_set_mime_type
(file, GP_MIME_JPEG));
} else if (filetype == GSMART_FILE_TYPE_AVI) {
CHECK (gp_file_set_mime_type
(file, GP_MIME_AVI));
}
break;
case GP_FILE_TYPE_PREVIEW:
CHECK (gsmart_request_thumbnail
(camera->pl, &data, &size, number, &filetype));
if (filetype == GSMART_FILE_TYPE_IMAGE) {
CHECK (gp_file_set_mime_type
(file, GP_MIME_BMP));
} else if (filetype == GSMART_FILE_TYPE_AVI) {
CHECK (gp_file_set_mime_type
(file, GP_MIME_JPEG));
}
break;
default:
return GP_ERROR_NOT_SUPPORTED;
}
if (!data)
return GP_ERROR;
CHECK (gp_file_set_data_and_size (file, data, size));
CHECK (gp_file_set_name (file, filename));
return GP_OK;
}
static int
get_info_func (CameraFilesystem *fs, const char *folder,
const char *filename, CameraFileInfo *info, void *data,
GPContext *context)
{
Camera *camera = data;
int n;
struct GsmartFile *file;
/* Get the file number from the CameraFileSystem */
CHECK (n =
gp_filesystem_number (camera->fs, folder, filename, context));
CHECK (gsmart_get_file_info (camera->pl, n, &file));
info->file.fields =
GP_FILE_INFO_NAME | GP_FILE_INFO_TYPE | GP_FILE_INFO_WIDTH |
GP_FILE_INFO_HEIGHT;
strncpy (info->file.name, filename, sizeof (info->file.name));
if (file->mime_type == GSMART_FILE_TYPE_IMAGE) {
strcpy (info->file.type, GP_MIME_JPEG);
info->preview.width = 160;
info->preview.height = 120;
} else if (file->mime_type == GSMART_FILE_TYPE_AVI) {
strcpy (info->file.type, GP_MIME_AVI);
info->preview.width = 320;
info->preview.height = 240;
}
info->file.width = file->width;
info->file.height = file->height;
info->preview.fields =
GP_FILE_INFO_TYPE | GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT;
strcpy (info->preview.type, GP_MIME_BMP);
return (GP_OK);
}
static int
delete_file_func (CameraFilesystem *fs, const char *folder,
const char *filename, void *data, GPContext *context)
{
Camera *camera = data;
int n, c;
/* Get the file number from the CameraFileSystem */
CHECK (n =
gp_filesystem_number (camera->fs, folder, filename, context));
CHECK (c = gp_filesystem_count (camera->fs, folder, context));
if (n + 1 != c) {
const char *name;
gp_filesystem_name (fs, "/", c - 1, &name, context);
gp_context_error (context,
_
("Your camera does only support deleting the "
"last file on the camera. In this case, this "
"is file '%s'."), name);
return (GP_ERROR);
}
CHECK (gsmart_delete_file (camera->pl, n));
return GP_OK;
}
static int
delete_all_func (CameraFilesystem *fs, const char *folder, void *data,
GPContext *context)
{
Camera *camera = data;
CHECK (gsmart_delete_all (camera->pl));
return GP_OK;
}