This is basically an amendment to #1015, I just realized that I overlooked some places due to a too restrictive regex. (I hope this subject is not getting old already...) This is a whitespace only change (if you include newlines as whitespace).
281 lines
5.9 KiB
C
281 lines
5.9 KiB
C
/*
|
|
* sq905.c
|
|
*
|
|
* Here, the functions which are needed to get data from the camera.
|
|
*
|
|
* Copyright (c) 2003 Theodore Kilgore <kilgota@auburn.edu>
|
|
* Camera library support under libgphoto2.1.1 for camera(s)
|
|
* with chipset from Service & Quality Technologies, Taiwan.
|
|
* The chip supported by this driver is presumed to be the SQ905,
|
|
*
|
|
* Licensed under GNU Lesser General Public License, as part of Gphoto
|
|
* camera support project. For a copy of the license, see the file
|
|
* COPYING in the main source tree of libgphoto2.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include <gphoto2/gphoto2.h>
|
|
#include <gphoto2/gphoto2-port.h>
|
|
#include "sq905.h"
|
|
|
|
#define GP_MODULE "sq905"
|
|
|
|
#define SQWRITE gp_port_usb_msg_write
|
|
#define SQREAD gp_port_usb_msg_read
|
|
|
|
#define zero "\x0"
|
|
|
|
static int
|
|
sq_read_data (GPPort *port, unsigned char *data, int size)
|
|
{
|
|
SQWRITE (port, 0x0c, 0x03, size, zero, 1);
|
|
gp_port_read (port, (char *)data, size);
|
|
return GP_OK;
|
|
}
|
|
|
|
|
|
int sq_access_reg (GPPort *port, int reg)
|
|
{
|
|
char c;
|
|
SQWRITE (port, 0x0c, 0x06, reg, zero, 1); /* Access a register */
|
|
SQREAD (port, 0x0c, 0x07, 0x00, &c, 1);
|
|
return GP_OK;
|
|
}
|
|
|
|
int
|
|
sq_init (GPPort *port, CameraPrivateLibrary *priv)
|
|
{
|
|
unsigned char c[0x4];
|
|
int i;
|
|
unsigned char *catalog = malloc(0x4000);
|
|
unsigned char *catalog_tmp;
|
|
if (!catalog) return GP_ERROR_NO_MEMORY;
|
|
|
|
sq_reset (port);
|
|
sq_access_reg(port, ID); /* Access model or chip id */
|
|
|
|
sq_read_data (port, c, 4);
|
|
sq_reset (port);
|
|
if (!memcmp (c, "\x09\x05\x01\x19", 4)) {
|
|
priv->model = SQ_MODEL_POCK_CAM;
|
|
} else if (!memcmp (c, "\x09\x05\x01\x32", 4)) {
|
|
priv->model = SQ_MODEL_MAGPIX;
|
|
/*
|
|
} else if (!memcmp (c, "\x09\x13\x06\x67", 4)) {
|
|
priv->model = SQ_MODEL_913c;
|
|
*/
|
|
/*
|
|
} else if (!memcmp (c, "\x50\x05\x00\x26", 4)) {
|
|
priv->model = SQ_MODEL_PRECISION;
|
|
*/
|
|
} else {
|
|
priv->model = SQ_MODEL_DEFAULT;
|
|
}
|
|
|
|
sq_access_reg(port, CONFIG); /* Access config */
|
|
sq_read_data(port, catalog, 0x4000); /* We need 16 bytes for each photo. */
|
|
sq_reset (port);
|
|
|
|
/* The first occurrence of a zero denotes end of files entries (here clips count as 1 entry) */
|
|
for (i=0; i<0x4000 && catalog[i]; i+=16) ;
|
|
priv->nb_entries = i>>4;
|
|
if (i) {
|
|
catalog_tmp = realloc(catalog, i);
|
|
if (catalog_tmp)
|
|
priv->catalog = catalog_tmp;
|
|
else
|
|
priv->catalog = catalog;
|
|
} else {
|
|
free (catalog);
|
|
priv->catalog = NULL; /* We just have freed catalog_tmp */
|
|
}
|
|
|
|
sq_reset (port);
|
|
|
|
priv->last_fetched_entry = -1;
|
|
free(priv->last_fetched_data);
|
|
priv->last_fetched_data = NULL;
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
int
|
|
sq_get_num_frames (CameraPrivateLibrary *priv, int entry)
|
|
{
|
|
if (sq_is_clip(priv, entry)) {
|
|
GP_DEBUG(" Number of frames in clip %i is %i\n", entry, priv->catalog[16*entry+7]);
|
|
return priv->catalog[16*entry+7];
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
sq_get_comp_ratio (CameraPrivateLibrary *priv, int entry)
|
|
{
|
|
switch (priv->catalog[16*entry]) {
|
|
case 0x61:
|
|
case 0x62:
|
|
case 0x63:
|
|
case 0x76: return 2;
|
|
case 0x41:
|
|
case 0x42:
|
|
case 0x43:
|
|
case 0x52:
|
|
case 0x53:
|
|
case 0x56:
|
|
case 0x72: return 1;
|
|
default:
|
|
GP_DEBUG ("Your camera has unknown resolution settings.\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int
|
|
sq_get_picture_width (CameraPrivateLibrary *priv, int entry)
|
|
{
|
|
switch (priv->catalog[16*entry]) {
|
|
case 0x41:
|
|
case 0x52:
|
|
case 0x61: return 352;
|
|
case 0x42:
|
|
case 0x62:
|
|
case 0x72: return 176;
|
|
case 0x43:
|
|
case 0x53:
|
|
case 0x63: return 320;
|
|
case 0x56:
|
|
case 0x76: return 640;
|
|
default:
|
|
GP_DEBUG ("Your pictures have unknown width.\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int
|
|
sq_is_clip (CameraPrivateLibrary *priv, int entry)
|
|
{
|
|
switch (priv->catalog[16*entry]) {
|
|
case 0x52:
|
|
case 0x53:
|
|
case 0x72: return 1;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
int
|
|
sq_rewind (GPPort *port, CameraPrivateLibrary *priv)
|
|
{
|
|
static unsigned char dummy_buf[0x4000];
|
|
|
|
|
|
GP_DEBUG("REWIND cam's data pointer");
|
|
|
|
/* One has to read the catalog to rewind the data stream...
|
|
* I don't know if it's by design. There ought to be something better to do... :-/
|
|
*/
|
|
|
|
|
|
sq_access_reg(port, CONFIG); /* Access config */
|
|
|
|
sq_read_data(port, dummy_buf, 0x4000);
|
|
sq_reset (port);
|
|
sq_access_reg(port, DATA); /* Access photo data */
|
|
|
|
priv->last_fetched_entry = -1;
|
|
free(priv->last_fetched_data);
|
|
priv->last_fetched_data = NULL;
|
|
return GP_OK;
|
|
}
|
|
|
|
int
|
|
sq_reset (GPPort *port)
|
|
{
|
|
sq_access_reg(port, CLEAR); /* Release current register */
|
|
|
|
return GP_OK;
|
|
}
|
|
|
|
int
|
|
sq_read_picture_data (GPPort *port, unsigned char *data, int size )
|
|
{
|
|
int remainder = size % 0x8000;
|
|
int offset = 0;
|
|
char c;
|
|
|
|
while ((offset + 0x8000 < size)) {
|
|
sq_read_data (port, data + offset, 0x8000);
|
|
offset = offset + 0x8000;
|
|
}
|
|
sq_read_data (port, data + offset, remainder);
|
|
|
|
SQWRITE (port, 0x0c, 0xc0, 0x00, &c, 1);
|
|
return GP_OK;
|
|
}
|
|
|
|
int
|
|
sq_delete_all (GPPort *port, CameraPrivateLibrary *priv)
|
|
{
|
|
/* This will work on the Argus DC-1510, perhaps some others.
|
|
* Will not successfully delete on all SQ905 cameras!
|
|
*/
|
|
|
|
switch (priv->catalog[2]) {
|
|
case 0xd0: /* Searches for DC-1510 */
|
|
sq_access_reg(port, CAPTURE); /* used here to delete */
|
|
|
|
sq_reset(port);
|
|
break;
|
|
default:
|
|
return (GP_ERROR_NOT_SUPPORTED);
|
|
}
|
|
return GP_OK;
|
|
}
|
|
|
|
int
|
|
sq_preprocess (SQModel model, int comp_ratio, unsigned char is_in_clip,
|
|
unsigned char *data, int w, int h)
|
|
{
|
|
int i, m, b;
|
|
unsigned char temp;
|
|
b=w*h/comp_ratio;
|
|
|
|
GP_DEBUG("Running sq_preprocess\n");
|
|
|
|
if (!is_in_clip) {
|
|
/* Turning the picture right-side up. */
|
|
for (i = 0; i < b/2; ++i) {
|
|
temp = data[i];
|
|
data[i] = data[b -1 -i];
|
|
data[b - 1 - i] = temp;
|
|
}
|
|
/* But clip frames are already right-side-up */
|
|
}
|
|
/*
|
|
* POCK_CAM needs de-mirror-imaging, too. But if a photo is
|
|
* compressed we de-mirror after decompression, so not here.
|
|
*/
|
|
if ((model == SQ_MODEL_POCK_CAM) && (comp_ratio == 1)) {
|
|
for (i = 0; i < h; i++) {
|
|
for (m = 0; m < w/2; m++) {
|
|
temp = data[w*i +m];
|
|
data[w*i + m] = data[w*i + w -1 -m];
|
|
data[w*i + w - 1 - m] = temp;
|
|
}
|
|
}
|
|
}
|
|
return GP_OK;
|
|
}
|
|
|
|
|