Files
libgphoto2/camlibs/jamcam/library.c
Marcus Meissner 358e6c7e92 * library.c: We need to read a reply of 8 bytes, or the kernel
reports data overflow.


git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@6007 67ed7778-7388-44ab-90cf-0a291f65f57c
2003-01-05 20:18:18 +00:00

698 lines
17 KiB
C

/****************************************************************/
/* library.c - Gphoto2 library for the KBGear JamCam v2 and v3 */
/* */
/* Copyright © 2001 Chris Pinkham */
/* */
/* Author: Chris Pinkham <cpinkham@infi.net> */
/* */
/* 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 <stdio.h>
#include <string.h>
#include <gphoto2.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#include "library.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
#define GP_MODULE
struct jamcam_file jamcam_files[1024];
static int jamcam_count = 0;
static int jamcam_mmc_card_size = 0;
static int jamcam_set_int_at_pos( unsigned char *buf, int pos, int value ) {
buf[pos + 0] = ( value ) & 0xff;
buf[pos + 1] = ( value >> 8 ) & 0xff;
buf[pos + 2] = ( value >> 16 ) & 0xff;
buf[pos + 3] = ( value >> 24 ) & 0xff;
return( value );
}
static int jamcam_get_int_at_pos( unsigned char *buf, int pos ) {
int ret = 0;
ret += buf[pos + 0];
ret += buf[pos + 1] * 256;
ret += buf[pos + 2] * 256 * 256;
ret += buf[pos + 3] * 256 * 256 * 256;
return( ret );
}
static int jamcam_set_usb_mem_pointer( Camera *camera, int position ) {
char reply[8];
GP_DEBUG ("* jamcam_set_usb_mem_pointer");
GP_DEBUG ("*** position: %d (0x%x)",
position, position);
gp_port_usb_msg_write( camera->port,
0xa1,
( position ) & 0xffff,
( position >> 16 ) & 0xffff,
NULL, 0 );
gp_port_usb_msg_read( camera->port,
0xa0,
0,
0,
reply, 8 );
return( GP_OK );
}
/* get the number of images on the mmc card */
static int jamcam_mmc_card_file_count (Camera *camera) {
char buf[16];
unsigned char reply[512];
unsigned int position = 0x40000000;
int data_incr;
int width;
int height;
GP_DEBUG ("* jamcam_mmc_card_file_count");
memset( buf, 0, sizeof( buf ));
switch( camera->port->type ) {
default:
case GP_PORT_SERIAL:
strcpy( buf, "KB00" );
jamcam_set_int_at_pos( buf, 4, position );
jamcam_write_packet( camera, buf, 8 );
jamcam_read_packet( camera, reply, 16 );
while( strncmp( reply, "KB", 2 ) == 0 ) {
width = (reply[5] * 256) + reply[4];
height = (reply[7] * 256) + reply[6];
data_incr = jamcam_get_int_at_pos( reply, 8 );
jamcam_files[jamcam_count].position = position;
jamcam_files[jamcam_count].width = width;
jamcam_files[jamcam_count].height = height;
jamcam_files[jamcam_count].data_incr = data_incr;
jamcam_count++;
position += data_incr;
jamcam_set_int_at_pos( buf, 4, position );
jamcam_write_packet( camera, buf, 8 );
jamcam_read_packet( camera, reply, 16 );
}
break;
case GP_PORT_USB:
gp_port_usb_msg_write( camera->port,
0xa5,
0x0005,
0x0000,
NULL, 0 );
jamcam_set_usb_mem_pointer( camera, position );
CHECK( gp_port_read (camera->port, reply, 0x10 ));
width = (reply[13] * 256) + reply[12];
height = (reply[15] * 256) + reply[14];
jamcam_set_usb_mem_pointer( camera, position + 8 );
CHECK( gp_port_read (camera->port, reply, 512 ));
gp_port_usb_msg_write( camera->port,
0xa5,
0x0006,
0x0000,
NULL, 0 );
while(((unsigned char)reply[0] != 0xff ) &&
((unsigned char)reply[0] != 0xaa ) &&
(((unsigned char)reply[0] != 0x00 ) ||
((unsigned char)reply[1] != 0x00 ))) {
data_incr = jamcam_get_int_at_pos( reply, 0 );
jamcam_files[jamcam_count].position = position;
jamcam_files[jamcam_count].width = width;
jamcam_files[jamcam_count].height = height;
jamcam_files[jamcam_count].data_incr = data_incr;
jamcam_count++;
position += data_incr;
gp_port_usb_msg_write( camera->port,
0xa5,
0x0005,
0x0000,
NULL, 0 );
jamcam_set_usb_mem_pointer( camera, position );
CHECK( gp_port_read (camera->port, reply, 0x10 ));
width = (reply[13] * 256) + reply[12];
height = (reply[15] * 256) + reply[14];
jamcam_set_usb_mem_pointer( camera, position + 8 );
CHECK( gp_port_read (camera->port, reply, 512 ));
gp_port_usb_msg_write( camera->port,
0xa5,
0x0006,
0x0000,
NULL, 0 );
}
break;
}
GP_DEBUG ( "*** returning with jamcam_count = %d", jamcam_count);
return( 0 );
}
int jamcam_file_count (Camera *camera) {
char buf[16];
unsigned char reply[16];
int position = 0;
int data_incr;
int width;
int height;
int last_offset_size = 0;
GP_DEBUG ("* jamcam_file_count");
jamcam_count = 0;
memset( buf, 0, sizeof( buf ));
switch( camera->port->type ) {
default:
case GP_PORT_SERIAL:
strcpy( buf, "KB00" );
jamcam_set_int_at_pos( buf, 4, position );
jamcam_write_packet( camera, buf, 8 );
jamcam_read_packet( camera, reply, 16 );
while( reply[0] == 'K' ) {
width = (reply[5] * 256) + reply[4];
height = (reply[7] * 256) + reply[6];
data_incr = jamcam_get_int_at_pos( reply, 8 );
last_offset_size = data_incr;
jamcam_files[jamcam_count].position = position;
jamcam_files[jamcam_count].width = width;
jamcam_files[jamcam_count].height = height;
jamcam_files[jamcam_count].data_incr = data_incr;
jamcam_count++;
position += data_incr;
jamcam_set_int_at_pos( buf, 4, position );
jamcam_write_packet( camera, buf, 8 );
jamcam_read_packet( camera, reply, 16 );
}
/* the v3 camera uses 0x3fdf0 data increments so check for MMC */
if ( last_offset_size == 0x03fdf0 ) {
jamcam_query_mmc_card( camera );
}
break;
case GP_PORT_USB:
jamcam_set_usb_mem_pointer( camera, position );
CHECK( gp_port_read (camera->port, reply, 0x10 ));
width = (reply[13] * 256) + reply[12];
height = (reply[15] * 256) + reply[14];
jamcam_set_usb_mem_pointer( camera, position + 8 );
CHECK( gp_port_read (camera->port, reply, 0x10 ));
while((unsigned char)reply[0] != 0xff ) {
data_incr = jamcam_get_int_at_pos( reply, 0 );
jamcam_files[jamcam_count].position = position;
jamcam_files[jamcam_count].width = width;
jamcam_files[jamcam_count].height = height;
jamcam_files[jamcam_count].data_incr = data_incr;
jamcam_count++;
position += data_incr;
jamcam_set_usb_mem_pointer( camera, position );
CHECK( gp_port_read (camera->port, reply, 0x10 ));
width = (reply[13] * 256) + reply[12];
height = (reply[15] * 256) + reply[14];
jamcam_set_usb_mem_pointer( camera, position + 8 );
CHECK( gp_port_read (camera->port, reply, 0x10 ));
}
break;
}
if ( jamcam_mmc_card_size ) {
jamcam_count += jamcam_mmc_card_file_count( camera );
}
GP_DEBUG ( "*** returning jamcam_count = %d", jamcam_count);
return( jamcam_count );
}
int jamcam_fetch_memory( Camera *camera, CameraFile *file,
char *data, int start, int length, GPContext *context) {
char tmp_buf[16];
char packet[16];
int new_start;
int new_end;
int bytes_read = 0;
int bytes_to_read;
int bytes_left = length;
int res = GP_OK;
unsigned int id = 0;
GP_DEBUG ("* jamcam_fetch_memory");
GP_DEBUG (" * start: %d (0x%x)",
start, start);
GP_DEBUG (" * length: %d (0x%x)",
length, length);
if ( length > 1000 )
id = gp_context_progress_start (context, length,
_("Downloading data..."));
while( bytes_left ) {
switch( camera->port->type ) {
default:
case GP_PORT_SERIAL:
bytes_to_read =
bytes_left > SER_PKT_SIZE ? SER_PKT_SIZE : bytes_left;
memset( packet, 0, sizeof( packet ));
strcpy( packet, "KB01" );
new_start = start + bytes_read;
new_end = start + bytes_read + bytes_to_read - 1;
/* start and end (inclusive) */
jamcam_set_int_at_pos( packet, 4, new_start );
jamcam_set_int_at_pos( packet, 8, new_end );
jamcam_write_packet( camera, packet, 12 );
CHECK (jamcam_read_packet( camera, data + bytes_read,
bytes_to_read ));
break;
case GP_PORT_USB:
bytes_to_read = bytes_left > USB_PKT_SIZE ? USB_PKT_SIZE : bytes_left;
/* for some reason this priming read fixes an offset problem */
/* in the images, we are only reading the first 16 bytes of */
/* data twice by doing this, so I don't know why it works */
jamcam_set_usb_mem_pointer( camera, start + bytes_read );
CHECK( gp_port_read (camera->port, tmp_buf, 16 ));
jamcam_set_usb_mem_pointer( camera, start + bytes_read );
CHECK( gp_port_read (camera->port, data + bytes_read, bytes_to_read ));
break;
}
bytes_left -= bytes_to_read;
bytes_read += bytes_to_read;
/* hate this hardcoded, but don't want to update here */
/* when downloading parts of a thumbnail */
if ( length > 1000 ) {
gp_context_progress_update (context, id, bytes_read);
if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
GP_DEBUG (" * CANCELED");
break;
}
}
}
if ( length > 1000 )
gp_context_progress_stop (context, id);
if ( res == GP_OK ) {
GP_DEBUG (" * returning OK");
}
return( res );
}
int jamcam_request_image( Camera *camera, CameraFile *file,
char *buf, int *len, int number, GPContext *context ) {
int position;
int result;
char tmp_buf[300000];
GP_DEBUG ("* jamcam_request_image");
position = jamcam_files[number].position;
/* don't know why this is necessary, but do it anyway */
if ( camera->port->type == GP_PORT_USB ) {
position += 8;
}
if ( camera->port->type == GP_PORT_USB ) {
gp_port_usb_msg_write( camera->port,
0xa5,
0x0005,
0x0000,
NULL, 0 );
}
result = jamcam_fetch_memory( camera, file, tmp_buf, position,
jamcam_files[number].data_incr, context );
/* this seems to reset the camera to a sane status */
if ( camera->port->type == GP_PORT_USB ) {
gp_port_usb_msg_write( camera->port,
0xa5,
0x0006,
0x0000,
NULL, 0 );
}
if ( result == GP_OK ) {
*len = jamcam_files[number].width * jamcam_files[number].height;
memcpy( buf, tmp_buf + 0x10, *len );
}
return( result );
}
struct jamcam_file *jamcam_file_info(Camera *camera, int number)
{
return( &jamcam_files[number] );
}
int jamcam_request_thumbnail( Camera *camera, CameraFile *file,
char *buf, int *len, int number, GPContext *context ) {
char line[2048];
char packet[16];
int position;
int x, y;
int res = GP_OK;
char *ptr;
int bytes_to_read;
unsigned int id;
GP_DEBUG ("* jamcam_request_thumbnail");
memset( packet, 0, sizeof( packet ));
position = jamcam_files[number].position + 0x10;
*len = 4800;
ptr = buf;
if ( camera->port->type == GP_PORT_USB ) {
/* windows driver does this sometimes */
gp_port_usb_msg_write( camera->port,
0xa5,
0x0005,
0x0000,
NULL, 0 );
/* just read one row of data at a time */
bytes_to_read = jamcam_files[number].width;
} else {
/* MMC card is quirky, need to fetch larger amounts of data */
if ( position >= 0x40000000 ) {
/* serial with mmc card needs bigger packets */
bytes_to_read = 2048;
} else {
/* just read one row of data at a time */
bytes_to_read = jamcam_files[number].width;
}
}
/* fetch thumbnail lines and build the thumbnail */
position += 10 * jamcam_files[number].width;
id = gp_context_progress_start (context, 60.,
_("Downloading thumbnail..."));
for( y = 0 ; y < 60 ; y++ ) {
jamcam_fetch_memory( camera, file, line, position, bytes_to_read, context );
gp_context_progress_update (context, id, y);
if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
res = GP_ERROR_CANCEL;
break;
}
if ( jamcam_files[number].width == 600 ) {
for( x = 22; x < 578 ; x += 7 ) {
*(ptr++) = line[x];
}
position += 7 * 600;
} else {
for( x = 0; x < 320 ; ) {
*(ptr++) = line[x];
x += 3;
*(ptr++) = line[x];
x += 5;
}
if ( y % 2 ) {
position += 5 * 320;
} else {
position += 3 * 320;
}
}
}
gp_context_progress_stop (context, id);
/* this seems to reset the camera to a sane status */
if ( camera->port->type == GP_PORT_USB ) {
gp_port_usb_msg_write( camera->port,
0xa5,
0x0006,
0x0000,
NULL, 0 );
}
return( res );
}
int jamcam_write_packet (Camera *camera, char *packet, int length) {
int ret, r;
GP_DEBUG ("* jamcam_write_packet");
for (r = 0; r < RETRIES; r++) {
ret = gp_port_write (camera->port, packet, length);
if (ret == GP_ERROR_TIMEOUT)
continue;
return (ret);
}
return (GP_ERROR_TIMEOUT);
}
int jamcam_read_packet (Camera *camera, char *packet, int length) {
int r = 0;
int bytes_read;
GP_DEBUG ("* jamcam_read_packet");
GP_DEBUG ("*** length: %d (0x%x)",
length, length);
for (r = 0; r < RETRIES; r++) {
bytes_read = gp_port_read (camera->port, packet, length);
if (bytes_read == GP_ERROR_TIMEOUT)
continue;
if (bytes_read < 0)
return (bytes_read);
if ( bytes_read == length ) {
return( GP_OK );
}
}
return (GP_ERROR_TIMEOUT);
}
int jamcam_enq (Camera *camera)
{
int ret, r = 0;
unsigned char buf[16];
GP_DEBUG ("* jamcam_enq");
memset( buf, 0, 16 );
switch( camera->port->type ) {
default:
case GP_PORT_SERIAL:
for (r = 0; r < RETRIES; r++) {
strcpy((char *)buf, "KB99" );
ret = jamcam_write_packet (camera, (char *)buf, 4);
if (ret == GP_ERROR_TIMEOUT)
continue;
if (ret != GP_OK)
return (ret);
ret = jamcam_read_packet (camera, (char *)buf, 4);
if (ret == GP_ERROR_TIMEOUT)
continue;
if (ret != GP_OK)
return (ret);
if ( !strncmp( (char *)buf, "KIDB", 4 )) {
return (GP_OK);
}
}
return (GP_ERROR_CORRUPTED_DATA);
break;
case GP_PORT_USB:
for (r = 0; r < RETRIES; r++) {
gp_port_usb_msg_write( camera->port,
0xa5,
0x0004,
0x0000,
NULL, 0 );
jamcam_set_usb_mem_pointer( camera, 0x0000 );
CHECK( gp_port_read( camera->port, (char *)buf, 0x0c ));
if (( !strncmp( (char *)buf, "KB00", 4 )) ||
(( buf[0] == 0xff ) && ( buf[1] == 0xff ) &&
( buf[2] == 0xff ) && ( buf[3] == 0xff ) &&
( buf[4] == 0xff ) && ( buf[5] == 0xff ) &&
( buf[6] == 0xff ) && ( buf[7] == 0xff ))) {
/* found a JamCam v3 camera */
/* reply contains 4-bytes with MMC card size if present */
/* set to 0 if none */
jamcam_mmc_card_size = jamcam_get_int_at_pos( buf, 8 );
if ( jamcam_mmc_card_size ) {
GP_DEBUG ( "* jamcam_enq, MMC card size = %d",
jamcam_mmc_card_size );
}
return (GP_OK);
} else if ( !strncmp( (char *)buf + 8, "KB00", 4 )) {
/* found a JamCam v2 camera */
/* JamCam v2 doesn't support MMC card so no need to check */
return (GP_OK);
} else if (( buf[0] == 0xf0 ) &&
( buf[1] == 0xfd ) &&
( buf[2] == 0x03 )) {
return( GP_OK );
}
}
return (GP_ERROR_CORRUPTED_DATA);
break;
}
return (GP_ERROR_TIMEOUT);
}
int jamcam_query_mmc_card (Camera *camera)
{
int ret, r = 0;
char buf[16];
GP_DEBUG ("* jamcam_query_mmc_card");
/* usb port doesn't need this packet, this info found in enquiry reply */
if ( camera->port->type == GP_PORT_USB ) {
return( GP_OK );
}
strcpy( buf, "KB04" );
for (r = 0; r < RETRIES; r++) {
ret = jamcam_write_packet (camera, buf, 4);
if (ret == GP_ERROR_TIMEOUT)
continue;
if (ret != GP_OK)
return (ret);
ret = jamcam_read_packet (camera, buf, 4);
if (ret == GP_ERROR_TIMEOUT)
continue;
if (ret != GP_OK)
return (ret);
/* reply is 4-byte int showing length of MMC card if any, 0 if none */
jamcam_mmc_card_size = jamcam_get_int_at_pos( buf, 0 );
if ( jamcam_mmc_card_size ) {
GP_DEBUG ("* jamcam_query_mmc_card, MMC card size = %d",
jamcam_mmc_card_size );
}
return (GP_OK);
}
return (GP_ERROR_TIMEOUT);
}