From: <jwr...@us...> - 2011-06-14 14:15:37
|
Revision: 13654 http://gphoto.svn.sourceforge.net/gphoto/?rev=13654&view=rev Author: jwrdegoede Date: 2011-06-14 14:15:24 +0000 (Tue, 14 Jun 2011) Log Message: ----------- Add tp6801 camlib Modified Paths: -------------- trunk/libgphoto2/camlibs/Makefile.am trunk/libgphoto2/configure.ac Added Paths: ----------- trunk/libgphoto2/camlibs/tp6801/ trunk/libgphoto2/camlibs/tp6801/Makefile-files trunk/libgphoto2/camlibs/tp6801/README.tp6801 trunk/libgphoto2/camlibs/tp6801/library.c trunk/libgphoto2/camlibs/tp6801/tp6801-dump.c trunk/libgphoto2/camlibs/tp6801/tp6801.c trunk/libgphoto2/camlibs/tp6801/tp6801.h Modified: trunk/libgphoto2/camlibs/Makefile.am =================================================================== --- trunk/libgphoto2/camlibs/Makefile.am 2011-06-14 14:06:51 UTC (rev 13653) +++ trunk/libgphoto2/camlibs/Makefile.am 2011-06-14 14:15:24 UTC (rev 13654) @@ -115,6 +115,7 @@ include template/Makefile-files include topfield/Makefile-files include toshiba/pdrm11/Makefile-files +include tp6801/Makefile-files # End of list of Makefile-files Added: trunk/libgphoto2/camlibs/tp6801/Makefile-files =================================================================== --- trunk/libgphoto2/camlibs/tp6801/Makefile-files (rev 0) +++ trunk/libgphoto2/camlibs/tp6801/Makefile-files 2011-06-14 14:15:24 UTC (rev 13654) @@ -0,0 +1,9 @@ +EXTRA_DIST += tp6801/README.tp6801 tp6801/tp6801-dump.c +camlibdoc_DATA += tp6801/README.tp6801 + +EXTRA_LTLIBRARIES += tp6801.la + +tp6801_la_SOURCES = tp6801/library.c tp6801/tp6801.c tp6801/tp6801.h +tp6801_la_LDFLAGS = $(camlib_ldflags) +tp6801_la_DEPENDENCIES = $(camlib_dependencies) +tp6801_la_LIBADD = $(camlib_libadd) @LIBGD@ Property changes on: trunk/libgphoto2/camlibs/tp6801/Makefile-files ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: trunk/libgphoto2/camlibs/tp6801/README.tp6801 =================================================================== --- trunk/libgphoto2/camlibs/tp6801/README.tp6801 (rev 0) +++ trunk/libgphoto2/camlibs/tp6801/README.tp6801 2011-06-14 14:15:24 UTC (rev 13654) @@ -0,0 +1,65 @@ +About this driver +================= + +This driver allows you to upload / download and delete pictures from +Tenx TP6801 based picture frames. This are small, cheap picture frames with a +1.1, 1.5 or 1.8 inch display. Currently this driver only supports the following +models: + +Insignia NS-KEYXX10 (0168:3011) + +I would very much like to extend the list of supported models, if you've +a picture frame which you think is Tenx TP68xx based please drop me a mail +at hde...@re... + +TP6801 based frames present themselves as a usb mass storage cdrom, which +contains the windows software. Communication with the device happens by +issuing special (custom) scsi commands. This driver uses the special +"usbscsi" port driver, which allows sending the custom scsi commands. + + +About the TP6801 access protocol +================================ + +Accessing the pictures uses scsi opcodes, in the vendor specific range, +for accessing the onboard flash memory the following 3 opcodes are used: +0xc1 Read +0xc6 Erase Block (64k) +0xcb Program page (256 bytes) + +Each opcode is followed by the magic sequence 0x11 0x31 0x0f 0x30 0x01 and +then the number of bytes to read / write (0 for erase block) in 16bit BE +format, followed by the (start)address for the operation in 24bit BE format. +The SCB is further padded out with 0-s to 16 bytes. + +There also is an opcode for setting the time of the photo frame, 0xca, +this opcode is followed by the same magic sequence 0x11 0x31 0x0f 0x30 0x01 +and then 1 byte each for hour, minute, seconds, year (no centuries), month +and day of month, and again further padding to 16 bytes with 0-s. + + +TP6810 memory map +================= + +All addresses are in hex! + +000000-001dff Looks font-ish, may be the battery charging icon +001e00-001e3f Picture Allocation Table, each byte refers to the location in + the picture memory at the same index (multiplied by imagesize). + A value between 1 and max-pictures indicates the corresponding + location contains picture nr value, 0xfe means it contains a + deleted picture, 0xff means it contains pre-erased memory + (this allows uploading a new picture without needing an erase). +001e40-001e7f Unknown, maybe settings (text color, etc). +001e80-001ebf "Tnex TP6801 Image File System Signature" but then reversed +007c00-007fff Website url the windows app automatically opens on insert +008000-00dfff Font +010000-19ffff Pictures in rgb565 format +1a0000-1a0003 USB vid:pid first pid then vid +1a0020-1a003f SCSI model string +1a0100-1f5fff ISO img for emulated cdrom, minus first 32k (which is all 0). +1f6000-1fffff Power on logo in rgb565 format (same as pictures) + + +Hans de Goede <hde...@re...> +13 June 2011 Property changes on: trunk/libgphoto2/camlibs/tp6801/README.tp6801 ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: trunk/libgphoto2/camlibs/tp6801/library.c =================================================================== --- trunk/libgphoto2/camlibs/tp6801/library.c (rev 0) +++ trunk/libgphoto2/camlibs/tp6801/library.c 2011-06-14 14:15:24 UTC (rev 13654) @@ -0,0 +1,531 @@ +/* Tenx tp6801 picframe access library + * + * Copyright (c) 2011 Hans de Goede <hde...@re...> + * + * This program 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.1 of the License, or + * (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#include <string.h> +#include <stdlib.h> +#ifdef HAVE_GD +#include <gd.h> +#endif + +#include <gphoto2/gphoto2-library.h> +#include <gphoto2/gphoto2-result.h> +#include <gphoto2/gphoto2-port.h> +#include <gphoto2/gphoto2-setting.h> +#include "tp6801.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 + +static const struct tp6801_devinfo tp6801_devinfo[] = { + { 0x0168, 0x3011 }, + {} +}; + +int +camera_id (CameraText *id) +{ + strcpy (id->text, "TP6801 USB picture frame"); + + return GP_OK; +} + + +int +camera_abilities (CameraAbilitiesList *list) +{ + CameraAbilities a; + int i; + + for (i = 0; tp6801_devinfo[i].vendor_id; i++) { + memset (&a, 0, sizeof(a)); + snprintf(a.model, sizeof (a.model), + "TP6801 USB picture frame"); + a.status = GP_DRIVER_STATUS_TESTING; + a.port = GP_PORT_USB_SCSI; + a.speed[0] = 0; + a.usb_vendor = tp6801_devinfo[i].vendor_id; + a.usb_product= tp6801_devinfo[i].product_id; + a.operations = GP_OPERATION_NONE; + a.folder_operations = GP_FOLDER_OPERATION_PUT_FILE | + GP_FOLDER_OPERATION_DELETE_ALL; + a.file_operations = GP_FILE_OPERATION_DELETE | + GP_FILE_OPERATION_RAW; + gp_abilities_list_append (list, a); + } + + return GP_OK; +} + +static int +camera_summary (Camera *camera, CameraText *summary, GPContext *context) +{ + sprintf (summary->text, + _("Your USB picture frame has a TP6801 chipset\n")); + return GP_OK; +} + +static int +camera_manual (Camera *camera, CameraText *manual, GPContext *context) +{ + strcpy(manual->text, + _( + "TP6801 based picture frames come with a variety of resolutions.\n" + "The gphoto driver for these devices allows you to download,\n" + "upload and delete pictures from the picture frame." + )); + + return GP_OK; +} + +static int +camera_about (Camera *camera, CameraText *about, GPContext *context) +{ + strcpy (about->text, + _( + "TP6801 USB picture frame driver\n" + "Hans de Goede <hde...@re...>\n" + "This driver allows you to download, upload and delete pictures\n" + "from the picture frame." + )); + + return GP_OK; +} + +static int get_file_idx(Camera *camera, const char *folder, + const char *filename) +{ + int idx, count, present; + char *c; + + if (strcmp (folder, "/")) + return GP_ERROR_DIRECTORY_NOT_FOUND; + + if (strlen (filename) != 12 || + strncmp (filename, "pict", 4) || + strcmp (filename + 8, ".png")) + return GP_ERROR_FILE_NOT_FOUND; + + idx = strtoul(filename + 4, &c, 10); + if (*c != '.') + return GP_ERROR_FILE_NOT_FOUND; + idx--; + + count = tp6801_max_filecount (camera); + if (count < 0) return count; + + if (idx < 0 || idx >= count) + return GP_ERROR_FILE_NOT_FOUND; + + present = tp6801_file_present (camera, idx); + if (present < 0) return present; + if (!present) + return GP_ERROR_FILE_NOT_FOUND; + + return idx; +} + +static int +get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, + CameraFileType type, CameraFile *file, void *data, + GPContext *context) +{ + Camera *camera = data; + int idx, size; +#ifdef HAVE_GD + int ret; + gdImagePtr im; + void *gdpng; +#endif + + idx = get_file_idx(camera, folder, filename); + if (idx < 0) + return idx; + + if (type == GP_FILE_TYPE_RAW) { + char *raw; + + CHECK (tp6801_read_raw_file (camera, idx, &raw)) + gp_file_set_mime_type (file, GP_MIME_RAW); + gp_file_set_name (file, filename); + gp_file_set_data_and_size (file, raw, + tp6801_filesize (camera)); + + return GP_OK; + } + +#ifdef HAVE_GD + if (type != GP_FILE_TYPE_NORMAL) + return GP_ERROR_NOT_SUPPORTED; + + im = gdImageCreateTrueColor(camera->pl->width, camera->pl->height); + if (im == NULL) + return GP_ERROR_NO_MEMORY; + + ret = tp6801_read_file(camera, idx, im->tpixels); + if (ret < 0) { + gdImageDestroy (im); + return ret; + } + + gdpng = gdImagePngPtr(im, &size); + gdImageDestroy (im); + if (gdpng == NULL) + return GP_ERROR_NO_MEMORY; + + ret = gp_file_set_mime_type (file, GP_MIME_PNG); + if (ret < 0) { gdFree (gdpng); return ret; } + + ret = gp_file_set_name (file, filename); + if (ret < 0) { gdFree (gdpng); return ret; } + + ret = gp_file_append (file, gdpng, size); + gdFree (gdpng); + return ret; +#else + gp_log(GP_LOG_ERROR,"tp6801", "GD decompression not supported - no libGD present during build"); + return GP_ERROR_NOT_SUPPORTED; +#endif +} + +static int +put_file_func (CameraFilesystem *fs, const char *folder, const char *name, + CameraFileType type, CameraFile *file, void *data, GPContext *context) +{ +#ifdef HAVE_GD + Camera *camera = data; + char *filedata = NULL; + int ret, in_width, in_height, in_x, in_y; + double aspect_in, aspect_out; + unsigned long filesize = 0; + gdImagePtr im_out, im_in = NULL; + + if (strcmp (folder, "/")) + return GP_ERROR_DIRECTORY_NOT_FOUND; + + CHECK (gp_file_get_data_and_size (file, (const char **)&filedata, + &filesize)) + + /* Try loading the file using gd, starting with the most often + used types first */ + + /* gdImageCreateFromJpegPtr is chatty on error, don't call it on + non JPEG files */ + if (filesize > 2 && + (uint8_t)filedata[0] == 0xff && (uint8_t)filedata[1] == 0xd8) + im_in = gdImageCreateFromJpegPtr(filesize, filedata); + if (im_in == NULL) + im_in = gdImageCreateFromPngPtr(filesize, filedata); + if (im_in == NULL) + im_in = gdImageCreateFromGifPtr(filesize, filedata); + if (im_in == NULL) + im_in = gdImageCreateFromWBMPPtr(filesize, filedata); + if (im_in == NULL) { + gp_log (GP_LOG_ERROR, "tp6801", + "Unrecognized file format for file: %s%s", + folder, name); + return GP_ERROR_BAD_PARAMETERS; + } + + im_out = gdImageCreateTrueColor(camera->pl->width, camera->pl->height); + if (im_out == NULL) { + gdImageDestroy (im_in); + return GP_ERROR_NO_MEMORY; + } + + /* Keep aspect */ + aspect_in = (double)im_in->sx / im_in->sy; + aspect_out = (double)im_out->sx / im_out->sy; + if (aspect_in > aspect_out) { + /* Reduce in width (crop left and right) */ + in_width = (im_in->sx / aspect_in) * aspect_out; + in_x = (im_in->sx - in_width) / 2; + in_height = im_in->sy; + in_y = 0; + } else { + /* Reduce in height (crop top and bottom) */ + in_width = im_in->sx; + in_x = 0; + in_height = (im_in->sy * aspect_in) / aspect_out; + in_y = (im_in->sy - in_height) / 2; + } + + gdImageCopyResampled (im_out, im_in, 0, 0, in_x, in_y, + im_out->sx, im_out->sy, + in_width, in_height); + + if (im_in->sx != im_out->sx || + im_in->sy != im_out->sy) + gdImageSharpen(im_out, 100); + + ret = tp6801_write_file (camera, im_out->tpixels); + if (ret >= 0) { + /* Commit the changes to the device */ + ret = tp6801_commit(camera); + } + + gdImageDestroy (im_in); + gdImageDestroy (im_out); + return ret; +#else + gp_log(GP_LOG_ERROR,"tp6801", "GD compression not supported - no libGD present during build"); + return GP_ERROR_NOT_SUPPORTED; +#endif +} + +static int +delete_file_func (CameraFilesystem *fs, const char *folder, + const char *filename, void *data, GPContext *context) +{ + Camera *camera = data; + int idx; + + idx = get_file_idx(camera, folder, filename); + if (idx < 0) + return idx; + + CHECK (tp6801_delete_file(camera, idx)) + + return tp6801_commit(camera); +} + +static int +delete_all_func (CameraFilesystem *fs, const char *folder, void *data, + GPContext *context) +{ + Camera *camera = data; + + CHECK (tp6801_delete_all (camera)) + + return tp6801_commit(camera); +} + +static int +get_info_func (CameraFilesystem *fs, const char *folder, const char *filename, + CameraFileInfo *info, void *data, GPContext *context) +{ + memset (info, 0, sizeof(CameraFileInfo)); + /* FIXME: fill in some stuff? */ + return GP_OK; +} + +static int +folder_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, + void *data, GPContext *context) +{ + if (strcmp(folder, "/")) + return GP_ERROR_DIRECTORY_NOT_FOUND; + + /* Subfolders not supported */ + return GP_OK; +} + +static int +file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, + void *data, GPContext *context) +{ + Camera *camera = data; + int i, count, present; + char buf[16]; + + count = tp6801_max_filecount (camera); + if (count < 0) return count; + + for (i = 0; i < count; i++) { + present = tp6801_file_present (camera, i); + if (present < 0) return present; + if (present) { + snprintf(buf, sizeof(buf), "pict%04d.png", i + 1); + CHECK (gp_list_append (list, buf, NULL)) + } + } + + return GP_OK; +} + +static int +storage_info_func (CameraFilesystem *fs, + CameraStorageInformation **sinfos, + int *nrofsinfos, + void *data, GPContext *context) +{ + Camera *camera = (Camera*)data; + CameraStorageInformation *sinfo; + int free, imagesize; + + free = tp6801_get_free_mem_size (camera); + if (free < 0) return free; + + sinfo = malloc(sizeof(CameraStorageInformation)); + if (!sinfo) return GP_ERROR_NO_MEMORY; + + *sinfos = sinfo; + *nrofsinfos = 1; + + sinfo->fields = GP_STORAGEINFO_BASE; + strcpy(sinfo->basedir, "/"); + + sinfo->fields |= GP_STORAGEINFO_ACCESS; + sinfo->access = GP_STORAGEINFO_AC_READWRITE; + sinfo->fields |= GP_STORAGEINFO_STORAGETYPE; + sinfo->type = GP_STORAGEINFO_ST_FIXED_RAM; + sinfo->fields |= GP_STORAGEINFO_FILESYSTEMTYPE; + sinfo->fstype = GP_STORAGEINFO_FST_GENERICFLAT; + sinfo->fields |= GP_STORAGEINFO_MAXCAPACITY; + sinfo->capacitykbytes = tp6801_get_mem_size (camera) / 1024; + sinfo->fields |= GP_STORAGEINFO_FREESPACEKBYTES; + sinfo->freekbytes = free / 1024; + + imagesize = tp6801_filesize (camera); + if (imagesize) { + sinfo->fields |= GP_STORAGEINFO_FREESPACEIMAGES; + sinfo->freeimages = free / imagesize; + } + + return GP_OK; +} + +static CameraFilesystemFuncs fsfuncs = { + .file_list_func = file_list_func, + .folder_list_func = folder_list_func, + .get_info_func = get_info_func, + .get_file_func = get_file_func, + .del_file_func = delete_file_func, + .put_file_func = put_file_func, + .delete_all_func = delete_all_func, + .storage_info_func = storage_info_func +}; + +static int +camera_get_config (Camera *camera, CameraWidget **window, GPContext *context) +{ + CameraWidget *child; + + GP_DEBUG ("*** camera_get_config"); + + gp_widget_new (GP_WIDGET_WINDOW, + _("Picture Frame Configuration"), window); + + gp_widget_new (GP_WIDGET_TOGGLE, + _("Synchronize frame data and time with PC"), &child); + gp_widget_set_value (child, &camera->pl->syncdatetime); + gp_widget_append (*window, child); + + return GP_OK; +} + +static int +camera_set_config (Camera *camera, CameraWidget *window, GPContext *context) +{ + CameraWidget *child; + int ret; + + GP_DEBUG ("*** camera_set_config"); + + ret = gp_widget_get_child_by_label (window, + _("Synchronize frame data and time with PC"), &child); + if (ret == GP_OK) + gp_widget_get_value (child, &camera->pl->syncdatetime); + + return GP_OK; +} + +static int +camera_exit (Camera *camera, GPContext *context) +{ + char buf[2]; + + if (camera->pl != NULL) { + buf[0] = '0' + camera->pl->syncdatetime; + buf[1] = 0; + gp_setting_set("tp6801", "syncdatetime", buf); + tp6801_close (camera); + free (camera->pl); + camera->pl = NULL; + } + return GP_OK; +} + +int +camera_init (Camera *camera, GPContext *context) +{ + CameraAbilities a; + int ret; + char *dump, buf[256]; + + /* First, set up all the function pointers */ + camera->functions->exit = camera_exit; + camera->functions->summary = camera_summary; + camera->functions->manual = camera_manual; + camera->functions->about = camera_about; + camera->functions->get_config = camera_get_config; + camera->functions->set_config = camera_set_config; + + /* Tell the CameraFilesystem where to get lists from */ + gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera); + + camera->pl = calloc (1, sizeof(CameraPrivateLibrary)); + if (!camera->pl) return GP_ERROR_NO_MEMORY; + + ret = gp_setting_get("tp6801", "syncdatetime", buf); + if (ret == GP_OK) + camera->pl->syncdatetime = buf[0] == '1'; + else + camera->pl->syncdatetime = 1; + + CHECK (gp_camera_get_abilities(camera, &a)) + + dump = getenv("GP_TP6801_DUMP"); + if (dump) + ret = tp6801_open_dump (camera, dump); + else + ret = tp6801_open_device (camera); + + if (ret != GP_OK) { + camera_exit (camera, context); + return ret; + } + + if (camera->pl->syncdatetime) { + struct tm tm; + time_t t; + + t = time (NULL); + if (localtime_r (&t , &tm)) { + ret = tp6801_set_time_and_date (camera, &tm); + if (ret != GP_OK) { + camera_exit (camera, context); + return ret; + } + } + } + + return GP_OK; +} Property changes on: trunk/libgphoto2/camlibs/tp6801/library.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: trunk/libgphoto2/camlibs/tp6801/tp6801-dump.c =================================================================== --- trunk/libgphoto2/camlibs/tp6801/tp6801-dump.c (rev 0) +++ trunk/libgphoto2/camlibs/tp6801/tp6801-dump.c 2011-06-14 14:15:24 UTC (rev 13654) @@ -0,0 +1,125 @@ +/* Tenx tp6801 picframe memory dump tool + * + * Copyright (c) 2011 Hans de Goede <hde...@re...> + * + * This program 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.1 of the License, or + * (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <scsi/sg.h> + +#define READ 0 +#define WRITE 1 + +void tp6801_send_cmd(int fd, int rw, int cmd, int offset, unsigned char *data, int data_size) +{ + int i; + sg_io_hdr_t io_hdr; + unsigned char sense_buffer[32]; + unsigned char cmd_buffer[16]; + + memset(cmd_buffer, 0, sizeof(cmd_buffer)); + cmd_buffer[0] = cmd; + cmd_buffer[1] = 0x11; + cmd_buffer[2] = 0x31; + cmd_buffer[3] = 0x0f; + cmd_buffer[4] = 0x30; + cmd_buffer[5] = 0x01; /* cmd 0xca hour not bcd! */ + cmd_buffer[6] = data_size >> 8; /* cmd 0xca min */ + cmd_buffer[7] = data_size & 0xff; /* cmd 0xca sec */ + cmd_buffer[8] = (offset >> 16) & 0xff; + cmd_buffer[9] = (offset >> 8) & 0xff; + cmd_buffer[10] = offset & 0xff; + + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + if (rw == READ) + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + else + io_hdr.dxfer_direction = SG_DXFER_TO_DEV; + io_hdr.interface_id = 'S'; + io_hdr.dxfer_len = data_size; + io_hdr.dxferp = (unsigned char *)data; + io_hdr.cmdp = cmd_buffer; + io_hdr.cmd_len = sizeof(cmd_buffer); + io_hdr.sbp = sense_buffer; + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.timeout = 1000; + + if(ioctl(fd, SG_IO, &io_hdr) < 0) + { + printf("error status: %d, errno: %s\n", io_hdr.status, strerror(errno)); + exit (1); + } +} + +void eeprom_read(int fd, int offset, unsigned char *data, int data_size) +{ + tp6801_send_cmd(fd, READ, 0xc1, offset, data, data_size); +} + +void eeprom_erase_block(int fd, int offset) +{ + tp6801_send_cmd(fd, READ, 0xc6, offset, NULL, 0); +} + +void eeprom_program_page(int fd, int offset, unsigned char *data) +{ + tp6801_send_cmd(fd, WRITE, 0xcb, offset, data, 256); +} + +int main(int argc, char* argv[]) +{ + int i, j, fd; + FILE* f; + unsigned char data[0x10000]; /* 64k */ + + fd = open(argv[1], O_RDWR); + if(fd < 0) + { + printf("Cannot open %s: %s\n", argv[1], strerror(errno)); + exit(-1); + } + +#if 1 + f = fopen("dump.bin", "w"); + /* We can read max 32k at a time */ + for(i = 0; i < (4160*1024); i += 0x8000) + { + eeprom_read(fd, i, data, 0x8000); + fwrite(data, 1, 0x8000, f); + } +#else + f = fopen("dump.bin", "r"); + /* programming is done in blocks of 64k */ + /* Note this is only restores the 64k block as that often gets + mangled during development */ + for(i = 0; i < 0x10000; i += 0x10000) + { + fread(data, 1, 0x10000, f); + eeprom_erase_block(fd, i); + for (j = 0; j < 0x10000; j += 256) + eeprom_program_page(fd, i + j, data + j); + } +#endif + fclose(f); + close(fd); + + return 0; +} Property changes on: trunk/libgphoto2/camlibs/tp6801/tp6801-dump.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: trunk/libgphoto2/camlibs/tp6801/tp6801.c =================================================================== --- trunk/libgphoto2/camlibs/tp6801/tp6801.c (rev 0) +++ trunk/libgphoto2/camlibs/tp6801/tp6801.c 2011-06-14 14:15:24 UTC (rev 13654) @@ -0,0 +1,836 @@ +/* Tenx tp6801 picframe access library + * + * Copyright (c) 2011 Hans de Goede <hde...@re...> + * + * This program 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.1 of the License, or + * (at your option) any later version. + * + * This program 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 program; 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 <errno.h> +#include <_stdint.h> +#include <stdlib.h> +#include <time.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_GD +#include <gd.h> +#endif + +#include <gphoto2/gphoto2-result.h> +#include "tp6801.h" + +static int +tp6801_send_cmd(Camera *camera, int to_dev, unsigned char cmd, int offset, + char *data, int data_size) +{ + char cmd_buffer[16]; + char sense_buffer[32]; + + /* The device firmware does not seem to wait for the last cmd to + finish when going from PP to READ, do this for it */ + if (camera->pl->last_cmd == TP6801_PROGRAM_PAGE && + cmd == TP6801_READ) { + usleep(5000); /* Max page program time for most spi flash */ + } + camera->pl->last_cmd = cmd; + + memset (cmd_buffer, 0, sizeof (cmd_buffer)); + cmd_buffer[0] = cmd; + cmd_buffer[1] = 0x11; + cmd_buffer[2] = 0x31; + cmd_buffer[3] = 0x0f; + cmd_buffer[4] = 0x30; + cmd_buffer[5] = 0x01; + cmd_buffer[6] = (data_size >> 8) & 0xff; + cmd_buffer[7] = data_size & 0xff; + cmd_buffer[8] = (offset >> 16) & 0xff; + cmd_buffer[9] = (offset >> 8) & 0xff; + cmd_buffer[10] = offset & 0xff; + + return gp_port_send_scsi_cmd (camera->port, to_dev, + cmd_buffer, sizeof(cmd_buffer), + sense_buffer, sizeof(sense_buffer), + data, data_size); +} + +int +tp6801_set_time_and_date(Camera *camera, struct tm *t) +{ + char cmd_buffer[16]; + char sense_buffer[32]; + + memset (cmd_buffer, 0, sizeof (cmd_buffer)); + + cmd_buffer[0] = TP6801_SET_TIME; + cmd_buffer[1] = 0x11; + cmd_buffer[2] = 0x31; + cmd_buffer[3] = 0x0f; + cmd_buffer[4] = 0x30; + cmd_buffer[5] = 0x01; + cmd_buffer[6] = t->tm_hour; + cmd_buffer[7] = t->tm_min; + cmd_buffer[8] = t->tm_sec; + cmd_buffer[9] = t->tm_year % 100; + cmd_buffer[10] = t->tm_mon + 1; + cmd_buffer[11] = t->tm_mday; + + return gp_port_send_scsi_cmd (camera->port, 0, + cmd_buffer, sizeof(cmd_buffer), + sense_buffer, sizeof(sense_buffer), + NULL, 0); +} + +static int +tp6801_read(Camera *camera, int offset, char *buf, int size) +{ + int ret; + if (camera->pl->mem_dump) { + ret = fseek (camera->pl->mem_dump, offset, SEEK_SET); + if (ret) { + gp_log (GP_LOG_ERROR, "tp6801", + "seeking in memdump: %s", strerror(errno)); + return GP_ERROR_IO_READ; + } + ret = fread (buf, 1, size, camera->pl->mem_dump); + if (ret != size) { + if (ret < 0) + gp_log (GP_LOG_ERROR, "tp6801", + "reading memdump: %s", + strerror(errno)); + else + gp_log (GP_LOG_ERROR, "tp6801", + "short read reading from memdump"); + return GP_ERROR_IO_READ; + } + } else { + CHECK (tp6801_send_cmd (camera, 0, TP6801_READ, offset, + buf, size)) + } + return GP_OK; +} + +static int +tp6801_program_page(Camera *camera, int offset, char *buf) +{ + int ret; + + if (camera->pl->mem_dump) { + ret = fseek (camera->pl->mem_dump, offset, SEEK_SET); + if (ret) { + gp_log (GP_LOG_ERROR, "tp6801", + "seeking in memdump: %s", strerror(errno)); + return GP_ERROR_IO_WRITE; + } + ret = fwrite (buf, 1, TP6801_PAGE_SIZE, camera->pl->mem_dump); + if (ret != TP6801_PAGE_SIZE) { + gp_log (GP_LOG_ERROR, "tp6801", + "writing memdump: %s", strerror(errno)); + return GP_ERROR_IO_WRITE; + } + } else { + CHECK (tp6801_send_cmd (camera, 1, TP6801_PROGRAM_PAGE, + offset, buf, TP6801_PAGE_SIZE)) + } + return GP_OK; +} + +static int +tp6801_erase_block(Camera *camera, int offset) +{ + int ret; + char *buf; + + if (camera->pl->mem_dump) { + buf = camera->pl->mem + offset; + memset(buf, 0xff, TP6801_BLOCK_SIZE); + ret = fseek (camera->pl->mem_dump, offset, SEEK_SET); + if (ret) { + gp_log (GP_LOG_ERROR, "tp6801", + "seeking in memdump: %s", strerror(errno)); + return GP_ERROR_IO_WRITE; + } + ret = fwrite (buf, 1, TP6801_BLOCK_SIZE, camera->pl->mem_dump); + if (ret != TP6801_BLOCK_SIZE) { + gp_log (GP_LOG_ERROR, "tp6801", + "writing memdump: %s", strerror(errno)); + return GP_ERROR_IO_WRITE; + } + return GP_OK; + } else { + CHECK (tp6801_send_cmd (camera, 0, TP6801_ERASE_BLOCK, offset, + NULL, 0)) + } + + return GP_OK; +} + +static int +tp6801_check_offset_len(Camera *camera, int offset, int len) +{ + if (offset < 0 || len < 0) { + gp_log (GP_LOG_ERROR, "tp6801", "negative offset or len"); + return GP_ERROR_CORRUPTED_DATA; + } + + if (offset + len > camera->pl->mem_size) { + gp_log (GP_LOG_ERROR, "tp6801", "access beyond end of memory"); + return GP_ERROR_CORRUPTED_DATA; + } + return GP_OK; +} + +static int +tp6801_read_mem(Camera *camera, int offset, int len) +{ + int i, to_read, page = offset / TP6801_PAGE_SIZE; + + CHECK (tp6801_check_offset_len (camera, offset, len)) + + /* Adjust len for us reading 1 page at a time */ + len += offset % TP6801_PAGE_SIZE; + + while (len > 0) { + /* Skip already read pages */ + if (camera->pl->page_state[page] & TP6801_PAGE_READ) { + len -= TP6801_PAGE_SIZE; + page++; + continue; + } + + /* Try to read as much as possible in one go */ + to_read = 0; + while (len > 0 && to_read < TP6801_MAX_READ && + !(camera->pl->page_state[page + to_read] & + TP6801_PAGE_READ)) { + len -= TP6801_PAGE_SIZE; + to_read++; + } + + offset = page * TP6801_PAGE_SIZE; + CHECK (tp6801_read (camera, offset, camera->pl->mem + offset, + to_read * TP6801_PAGE_SIZE)) + for (i = 0; i < to_read; i++, page++) + camera->pl->page_state[page] |= TP6801_PAGE_READ; + } + return GP_OK; +} + +static int +tp6801_write_mem(Camera *camera, int offset, + void *buf, int len) +{ + int i, first, last; + + CHECK (tp6801_check_offset_len (camera, offset, len)) + + first = offset / TP6801_PAGE_SIZE; + last = (offset + len - 1) / TP6801_PAGE_SIZE; + + /* If we're not going to completely fill the first page, first read + it to ensure it is present in our device memory copy */ + if ((offset % TP6801_PAGE_SIZE || len < TP6801_PAGE_SIZE) && + (camera->pl->page_state[first] & TP6801_PAGE_CONTAINS_DATA) && + !(camera->pl->page_state[first] & TP6801_PAGE_READ)) { + int o = first * TP6801_PAGE_SIZE; + CHECK (tp6801_read (camera, o, camera->pl->mem + o, + TP6801_PAGE_SIZE)) + camera->pl->page_state[first] |= TP6801_PAGE_READ; + } + + /* Likewise for the last page */ + if ((offset + len) % TP6801_PAGE_SIZE && + (camera->pl->page_state[last] & TP6801_PAGE_CONTAINS_DATA) && + !(camera->pl->page_state[last] & TP6801_PAGE_READ)) { + int o = last * TP6801_PAGE_SIZE; + CHECK (tp6801_read (camera, o, camera->pl->mem + o, + TP6801_PAGE_SIZE)) + camera->pl->page_state[last] |= TP6801_PAGE_READ; + } + + memcpy(camera->pl->mem + offset, buf, len); + for (i = first; i <= last; i++) { + /* Note we mark the written pages as read too, to avoid + them getting overwritten by a read from the device later */ + camera->pl->page_state[i] |= TP6801_PAGE_DIRTY | + TP6801_PAGE_CONTAINS_DATA | + TP6801_PAGE_READ; + } + return GP_OK; +} + +static int +tp6801_detect_mem(Camera *camera) +{ + int i; + char *m; + + camera->pl->mem = malloc(TP6801_MAX_MEM_SIZE); + if (!camera->pl->mem) + return GP_ERROR_NO_MEMORY; + camera->pl->mem_size = TP6801_MAX_MEM_SIZE; + + /* Note we read the PAT instead of some mem at offset 0, because: + 1) This saves a read when reading the PAT later + 2) The PAT contains reasonably unique data */ + CHECK (tp6801_read_mem (camera, TP6801_PAT_OFFSET, TP6801_PAT_SIZE)) + + for (i = 0; (1048576 << i) != TP6801_MAX_MEM_SIZE; i++) { + int offset = (1048576 << i) + TP6801_PAT_OFFSET; + CHECK (tp6801_read_mem (camera, offset, TP6801_PAT_SIZE)) + if (memcmp(camera->pl->mem + TP6801_PAT_OFFSET, + camera->pl->mem + offset, + TP6801_PAT_SIZE) == 0) + break; + } + + camera->pl->mem_size = 1048576 << i; + GP_DEBUG ("tp6801 detected %d bytes of memory", camera->pl->mem_size); + + m = realloc(camera->pl->mem, camera->pl->mem_size); + if (!m) + return GP_ERROR_NO_MEMORY; + + camera->pl->mem = m; + return GP_OK; +} + +int +tp6801_filesize(Camera *camera) +{ + /* The pictures are stored as rgb565be, so 2 bytes / pixel */ + return camera->pl->width * camera->pl->height * 2; +} + +int +tp6801_max_filecount(Camera *camera) +{ + int free_mem, size; + + size = tp6801_filesize (camera); + free_mem = camera->pl->mem_size - TP6801_PICTURE_OFFSET(0, size); + free_mem -= TP6801_CONST_DATA_SIZE; + + return free_mem / size; +} + +int +tp6801_file_present(Camera *camera, int idx) +{ + if (idx < 0) { + gp_log (GP_LOG_ERROR, "tp6801", + "file index < 0"); + return GP_ERROR_BAD_PARAMETERS; + } + + if (idx >= tp6801_max_filecount (camera)) { + gp_log (GP_LOG_ERROR, "tp6801", + "file index beyond end of ABFS"); + return GP_ERROR_BAD_PARAMETERS; + } + + if (camera->pl->pat[idx] >= 1 && + camera->pl->pat[idx] <= camera->pl->picture_count) + return 1; + else switch (camera->pl->pat[idx]) { + case TP6801_PAT_ENTRY_DELETED: + case TP6801_PAT_ENTRY_PRE_ERASED: + return 0; + default: + return GP_ERROR_CORRUPTED_DATA; + } +} + +static int +tp6801_check_file_present(Camera *camera, int idx) +{ + int r = tp6801_file_present (camera, idx); + if (r < 0) + return r; + if (r == 0) + return GP_ERROR_BAD_PARAMETERS; + return GP_OK; +} + +static int +tp6801_decode_image(Camera *camera, char *_src, int **dest) +{ +#ifdef HAVE_GD + int x, y; + unsigned char *src = (unsigned char *)_src; + + for (y = 0; y < camera->pl->height; y++) { + for (x = 0; x < camera->pl->width; x++) { + int r, g, b, rgb565; + + rgb565 = (src[0] << 8) | src[1]; + r = (rgb565 & 0xf800) >> 8; + g = (rgb565 & 0x07e0) >> 3; + b = (rgb565 & 0x001f) << 3; + + dest[y][x] = gdTrueColor (r, g, b); + src += 2; + } + } + return GP_OK; +#else + gp_log(GP_LOG_ERROR,"tp6801", "GD decompression not supported - no libGD present during build"); + /* Never reached */ + return GP_ERROR_NOT_SUPPORTED; +#endif +} + +static int +tp6801_encode_image(Camera *camera, int **src, char *dest) +{ +#ifdef HAVE_GD + int x, y; + + for (y = 0; y < camera->pl->height; y++) { + for (x = 0; x < camera->pl->width; x++) { + int r, g, b, rgb565; + int p = src[y][x]; + + r = gdTrueColorGetRed(p); + g = gdTrueColorGetGreen(p); + b = gdTrueColorGetBlue(p); + rgb565 = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + ((b & 0xf8) >> 3); + dest[0] = (rgb565 >> 8) & 0xff; + dest[1] = (rgb565 >> 0) & 0xff; + dest += 2; + } + } + return GP_OK; +#else + gp_log(GP_LOG_ERROR,"tp6801", "GD compression not supported - no libGD present during build"); + return GP_ERROR_NOT_SUPPORTED; +#endif +} + +int +tp6801_read_raw_file(Camera *camera, int idx, char **raw) +{ + int size; + + *raw = NULL; + size = tp6801_filesize (camera); + + CHECK (tp6801_check_file_present (camera, idx)) + CHECK (tp6801_read_mem (camera, TP6801_PICTURE_OFFSET(idx, size), + size)) + + *raw = malloc (size); + if (!*raw) { + gp_log (GP_LOG_ERROR, "tp6801", "allocating memory"); + return GP_ERROR_NO_MEMORY; + } + + memcpy(*raw, camera->pl->mem + TP6801_PICTURE_OFFSET(idx, size), size); + return GP_OK; +} + +int +tp6801_read_file(Camera *camera, int idx, int **rgb24) +{ + int size = tp6801_filesize (camera); + + CHECK (tp6801_check_file_present (camera, idx)) + CHECK (tp6801_read_mem (camera, TP6801_PICTURE_OFFSET(idx, size), + size)) + CHECK (tp6801_decode_image (camera, + camera->pl->mem + TP6801_PICTURE_OFFSET(idx, size), + rgb24)) + return GP_OK; +} + +int +tp6801_write_file(Camera *camera, int **rgb24) +{ + const int size = tp6801_filesize (camera); + int i, count = tp6801_max_filecount (camera); + char buf[size]; + + /* Pass 1 try to find a pre-erased slot in the PAT */ + for (i = 0; i < count; i++) + if (camera->pl->pat[i] == TP6801_PAT_ENTRY_PRE_ERASED) + break; + + if (i == count) { + /* Pass 2 try to find a deleted slot in the PAT */ + for (i = 0; i < count; i++) + if (camera->pl->pat[i] == TP6801_PAT_ENTRY_DELETED) + break; + } + + if (i == count) { + gp_log (GP_LOG_ERROR, "tp6801", + "not enough freespace to add file"); + return GP_ERROR_NO_SPACE; + } + + CHECK (tp6801_encode_image (camera, rgb24, buf)) + CHECK (tp6801_write_mem (camera, TP6801_PICTURE_OFFSET(i, size), + buf, size)) + camera->pl->picture_count++; + camera->pl->pat[i] = camera->pl->picture_count; + camera->pl->page_state[TP6801_PAT_PAGE] |= TP6801_PAGE_DIRTY; + + return GP_OK; +} + +int +tp6801_delete_file(Camera *camera, int idx) +{ + int i, n, count = tp6801_max_filecount (camera); + + CHECK (tp6801_check_file_present (camera, idx)) + + n = camera->pl->pat[idx]; + camera->pl->pat[idx] = TP6801_PAT_ENTRY_DELETED; + + /* Renumber remaining pictures */ + for (i = 0; i < count; i++) { + if (camera->pl->pat[i] >= 1 && + camera->pl->pat[i] <= camera->pl->picture_count) { + if (camera->pl->pat[i] > n) + camera->pl->pat[i]--; + } else switch (camera->pl->pat[i]) { + case TP6801_PAT_ENTRY_DELETED: + case TP6801_PAT_ENTRY_PRE_ERASED: + break; + default: + return GP_ERROR_CORRUPTED_DATA; + } + } + + camera->pl->picture_count--; + camera->pl->page_state[TP6801_PAT_PAGE] |= TP6801_PAGE_DIRTY; + + return GP_OK; +} + +int +tp6801_delete_all(Camera *camera) +{ + int i, start, end; + + /* Erase the entire picture memory */ + start = TP6801_PICTURE_OFFSET(0, 0); + end = camera->pl->mem_size - TP6801_CONST_DATA_SIZE; + for (i = start; i < end; i += TP6801_BLOCK_SIZE) + CHECK (tp6801_erase_block (camera, i)) + + /* Update state of all picture memory pages */ + start /= TP6801_PAGE_SIZE; + end /= TP6801_PAGE_SIZE; + for (i = start; i < end; i++) + camera->pl->page_state[i] = 0; + + /* Update PAT */ + end = tp6801_max_filecount (camera); + for (i = 0; i < end; i++) + camera->pl->pat[i] = TP6801_PAT_ENTRY_PRE_ERASED; + camera->pl->picture_count = 0; + camera->pl->page_state[TP6801_PAT_PAGE] |= TP6801_PAGE_DIRTY; + + return GP_OK; +} + +/* bsp = block start page */ +static int +tp6801_program_block(Camera *camera, int bsp, char prog_flags) +{ + const int block_page_size = TP6801_BLOCK_SIZE / TP6801_PAGE_SIZE; + int i, offset; + + for (i = 0, offset = bsp * TP6801_PAGE_SIZE; + i < block_page_size; + i++, offset += TP6801_PAGE_SIZE) { + if (!(camera->pl->page_state[bsp + i] & prog_flags)) + continue; + + CHECK (tp6801_program_page (camera, offset, + camera->pl->mem + offset)) + camera->pl->page_state[bsp + i] &= ~TP6801_PAGE_DIRTY; + camera->pl->page_state[bsp + i] |= TP6801_PAGE_NEEDS_ERASE; + } + return GP_OK; +} + +static int +tp6801_read_erase_program_block(Camera *camera, int bsp) +{ + const int block_page_size = TP6801_BLOCK_SIZE / TP6801_PAGE_SIZE; + int i, offset, to_read; + + /* Step 1 read in any pages which contain data before erasing! */ + i = 0; + while (i < block_page_size) { + /* Skip unused pages */ + if (!(camera->pl->page_state[bsp + i] & + TP6801_PAGE_CONTAINS_DATA)) { + i++; + continue; + } + + /* Read as many pages in one go as possible */ + to_read = 0; + while ((i + to_read) < block_page_size && + (camera->pl->page_state[bsp + i + to_read] & + TP6801_PAGE_CONTAINS_DATA)) { + to_read++; + } + offset = (bsp + i) * TP6801_PAGE_SIZE; + CHECK (tp6801_read_mem (camera, offset, + to_read * TP6801_PAGE_SIZE)) + i += to_read; + } + + /* Step 2 erase the block */ + CHECK (tp6801_erase_block (camera, bsp * TP6801_PAGE_SIZE)) + for (i = 0; i < block_page_size; i++) { + camera->pl->page_state[bsp + i] &= + ~TP6801_PAGE_NEEDS_ERASE; + } + + /* Step 3 program all pages which are dirty or contain data */ + CHECK (tp6801_program_block (camera, bsp, + TP6801_PAGE_DIRTY | TP6801_PAGE_CONTAINS_DATA)) + + return GP_OK; +} + +static int +tp6801_commit_block(Camera *camera, int bsp) +{ + const int block_page_size = TP6801_BLOCK_SIZE / TP6801_PAGE_SIZE; + int i, dirty_pages = 0, needs_erase = 0; + + for (i = 0; i < block_page_size; i++) { + char page_state = camera->pl->page_state[bsp + i]; + if (page_state & TP6801_PAGE_DIRTY) { + dirty_pages++; + if (page_state & TP6801_PAGE_NEEDS_ERASE) + needs_erase++; + } + } + + if (!dirty_pages) + return GP_OK; + + if (needs_erase) + CHECK (tp6801_read_erase_program_block (camera, bsp)) + else + /* No erase needed, just program dirty pages */ + CHECK (tp6801_program_block (camera, bsp, + TP6801_PAGE_DIRTY)) + + return GP_OK; +} + +int +tp6801_commit(Camera *camera) +{ + const int size = tp6801_filesize (camera); + const int block_page_size = TP6801_BLOCK_SIZE / TP6801_PAGE_SIZE; + int mem_page_size = camera->pl->mem_size / TP6801_PAGE_SIZE; + int i, j, begin, end, count = tp6801_max_filecount (camera); + + /* Skip the first block as that contains the PAT */ + for (i = block_page_size; + i < mem_page_size; + i += block_page_size) { + CHECK (tp6801_commit_block (camera, i)) + } + + /* Now see if we've completely erased the area of some deleted files + and if so mark there PAT entries as pre-erased, rather then just + deleted */ + for (i = 0; i < count; i++) { + if (camera->pl->pat[i] != TP6801_PAT_ENTRY_DELETED) + continue; + + begin = TP6801_PICTURE_OFFSET(i, size) / TP6801_PAGE_SIZE; + end = TP6801_PICTURE_OFFSET(i + 1, size) / TP6801_PAGE_SIZE; + for (j = begin; j < end; j++) { + char page_state = camera->pl->page_state[j]; + if (page_state & TP6801_PAGE_NEEDS_ERASE) + break; + } + if (j == end) { /* No page needs erase -> mark pre-erased */ + camera->pl->pat[i] = TP6801_PAT_ENTRY_PRE_ERASED; + camera->pl->page_state[TP6801_PAT_PAGE] |= + TP6801_PAGE_DIRTY; + } + } + + /* And commit the block with the PAT */ + CHECK (tp6801_commit_block (camera, 0)) + + return GP_OK; +} + +static const struct tp6801_model_info { + int vid; + int pid; + char model[TP6801_SCSI_MODEL_LEN + 1]; + int width; + int height; +} tp6801_models[] = { + { 0x0168, 0x3011, "InsigniaNS-KEYXX09", 160, 128 }, /* Guessed */ + { 0x0168, 0x3011, "InsigniaNS-KEYXX10", 160, 128 }, + {} +}; + +int +tp6801_open_device(Camera *camera) +{ + int i, j, count, size, begin, end, offset, vid, pid; + char model[TP6801_SCSI_MODEL_LEN + 1]; + + CHECK (tp6801_detect_mem (camera)) + + /* Read the first 512 bytes of the const data area, this gives us + the usb id, scsi model and begin of the iso img */ + offset = camera->pl->mem_size - TP6801_CONST_DATA_SIZE; + CHECK (tp6801_read_mem (camera, offset, 512)) + + /* Sanity check, verify that the iso starts where we expect it, if it + does not we likely have the size of the const data wrong for this + model, and could overwrite part of the iso, not good! */ + offset += TP6801_ISO_OFFSET; + if (memcmp (camera->pl->mem + offset, "\001CD001", 6)) { + gp_log (GP_LOG_ERROR, "tp6801", "Could not find ISO header"); + return GP_ERROR_MODEL_NOT_FOUND; + } + offset -= TP6801_ISO_OFFSET; + + /* The 4st 4 bytes of the const data are pid:vid */ + pid = (camera->pl->mem[offset + 0] << 8) | camera->pl->mem[offset + 1]; + vid = (camera->pl->mem[offset + 2] << 8) | camera->pl->mem[offset + 3]; + + offset += TP6801_SCSI_MODEL_OFFSET; + CHECK (tp6801_read_mem (camera, offset, TP6801_SCSI_MODEL_LEN)) + memcpy (model, camera->pl->mem + offset, TP6801_SCSI_MODEL_LEN); + model[TP6801_SCSI_MODEL_LEN] = 0; + + for (i = 0; tp6801_models[i].pid; i++) { + if (tp6801_models[i].pid == pid && + tp6801_models[i].vid == vid && + strcmp(tp6801_models[i].model, model) == 0) + break; + } + if (!tp6801_models[i].pid) { + gp_log (GP_LOG_ERROR, "tp6801", + "unknown model %04x:%04x %s", vid, pid, model); + return GP_ERROR_MODEL_NOT_FOUND; + } + camera->pl->width = tp6801_models[i].width; + camera->pl->height = tp6801_models[i].height; + GP_DEBUG("tp6801 detect %s model (%dx%d)", model, + camera->pl->width, camera->pl->height); + + /* One more sanity check */ + size = tp6801_filesize (camera); + if (size % TP6801_PAGE_SIZE) { + gp_log (GP_LOG_ERROR, "tp6801", "image size not page aligned"); + return GP_ERROR_MODEL_NOT_FOUND; + } + + /* Read PAT, verify signature */ + CHECK (tp6801_read_mem (camera, TP6801_PAT_OFFSET, TP6801_PAT_SIZE)) + if (memcmp (camera->pl->mem + TP6801_PAT_MAGIC_OFFSET, + TP6801_PAT_MAGIC, strlen(TP6801_PAT_MAGIC))) { + gp_log (GP_LOG_ERROR, "tp6801", "invalid pat magic"); + return GP_ERROR_MODEL_NOT_FOUND; + } + camera->pl->pat = (unsigned char *)camera->pl->mem + TP6801_PAT_OFFSET; + + /* Set initial page state for all pages */ + for (i = 0; i < camera->pl->mem_size / TP6801_PAGE_SIZE; i++) + camera->pl->page_state[i] |= TP6801_PAGE_CONTAINS_DATA | + TP6801_PAGE_NEEDS_ERASE; + + /* Parse and verify PAT and update page_state based on it */ + count = tp6801_max_filecount(camera); + for (i = 0; i < count; i++) { + int clear_flags = 0; + + if (camera->pl->pat[i] >= 1 && + camera->pl->pat[i] <= count) { + if (camera->pl->pat[i] > camera->pl->picture_count) + camera->pl->picture_count = camera->pl->pat[i]; + continue; + } else switch (camera->pl->pat[i]) { + case TP6801_PAT_ENTRY_PRE_ERASED: + clear_flags |= TP6801_PAGE_NEEDS_ERASE; + /* fall through */ + case TP6801_PAT_ENTRY_DELETED: + clear_flags |= TP6801_PAGE_CONTAINS_DATA; + break; + default: + gp_log (GP_LOG_ERROR, "tp6801", "invalid pat entry"); + return GP_ERROR_CORRUPTED_DATA; + } + + begin = TP6801_PICTURE_OFFSET(i, size) / TP6801_PAGE_SIZE; + end = TP6801_PICTURE_OFFSET(i + 1, size) / TP6801_PAGE_SIZE; + for (j = begin; j < end; j++) + camera->pl->page_state[j] &= ~clear_flags; + } + + return GP_OK; +} + +int +tp6801_open_dump(Camera *camera, const char *dump) +{ + camera->pl->mem_dump = fopen(dump, "r+"); + if (!camera->pl->mem_dump) { + gp_log (GP_LOG_ERROR, "tp6801", "opening memdump file: %s: %s", + dump, strerror(errno)); + return GP_ERROR_IO_INIT; + } + + return tp6801_open_device (camera); +} + +void tp6801_close(Camera *camera) +{ + free (camera->pl->mem); + camera->pl->mem = NULL; + if (camera->pl->mem_dump) { + fclose (camera->pl->mem_dump); + camera->pl->mem_dump = NULL; + } +} + +int +tp6801_get_mem_size(Camera *camera) +{ + return camera->pl->mem_size; +} + +int +tp6801_get_free_mem_size(Camera *camera) +{ + return (tp6801_max_filecount (camera) - camera->pl->picture_count) * + tp6801_filesize (camera); +} Property changes on: trunk/libgphoto2/camlibs/tp6801/tp6801.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: trunk/libgphoto2/camlibs/tp6801/tp6801.h =================================================================== --- trunk/libgphoto2/camlibs/tp6801/tp6801.h (rev 0) +++ trunk/libgphoto2/camlibs/tp6801/tp6801.h 2011-06-14 14:15:24 UTC (rev 13654) @@ -0,0 +1,125 @@ +/* Tenx tp6801 picframe access library + * + * Copyright (c) 2011 Hans de Goede <hde...@re...> + * + * This program 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.1 of the License, or + * (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TP6801_H__ +#define __TP6801_H__ +#include "config.h" + +#include <stdio.h> + +#include <gphoto2/gphoto2-library.h> +#include <gphoto2-endian.h> + +#define GP_MODULE "tp6801" + +#define TP6801_PAT_MAGIC "erutangiS metsyS eliF egamI 1086PT xneT" +#define TP6801_PAT_MAGIC_OFFSET 0x1e80 +#define TP6801_PAT_OFFSET 0x1e00 +#define TP6801_PAT_PAGE (TP6801_PAT_OFFSET / TP6801_PAGE_SIZE) +#define TP6801_PAT_SIZE 256 /* Including the magic */ +#define TP6801_PAT_ENTRY_PRE_ERASED 0xff +#define TP6801_PAT_ENTRY_DELETED 0xfe +#define TP6801_PICTURE_OFFSET(i, size) (0x10000 + (i) * (size)) +#define TP6801_READ 0xC1 +#define TP6801_ERASE_BLOCK 0xC6 +#define TP6801_SET_TIME 0xCA +#define TP6801_PROGRAM_PAGE 0xCB +#define TP6801_BLOCK_SIZE 65536 +#define TP6801_PAGE_SIZE 256 +/* USB bulk transfers are 32k max */ +#define TP6801_MAX_READ (32768 / TP6801_PAGE_SIZE) +#define TP6801_MAX_MEM_SIZE 4194304 +#define TP6801_CONST_DATA_SIZE 393216 +#define TP6801_SCSI_MODEL_OFFSET 32 +#define TP6801_SCSI_MODEL_LEN 32 +#define TP6801_ISO_OFFSET 256 +/* page_state flags */ +#define TP6801_PAGE_READ 0x01 +#define TP6801_PAGE_DIRTY 0x02 +#define TP6801_PAGE_CONTAINS_DATA 0x04 +#define TP6801_PAGE_NEEDS_ERASE 0x08 + +#define CHECK(result) {int r=(result); if (r<0) return (r);} + +struct _CameraPrivateLibrary { + FILE *mem_dump; + char *mem; + unsigned char *pat; + char page_state[TP6801_MAX_MEM_SIZE / TP6801_PAGE_SIZE]; + unsigned char last_cmd; + int picture_count; + /* LCD display attributes */ + int width; + int height; + /* EEPROM attributes */ + int mem_size; + /* Driver configuration settings */ + int syncdatetime; +}; + +struct tp6801_devinfo { + unsigned short vendor_id; + unsigned short product_id; +}; + +/* functions in tp6801.c */ +int +tp6801_open_device(Camera *camera); + +int +tp6801_open_dump(Camera *camera, const char *dump); + +void tp6801_close(Camera *camera); + +int +tp6801_max_filecount(Camera *camera); + +int +tp6801_file_present(Camera *camera, int idx); + +int +tp6801_read_raw_file(Camera *camera, int idx, char **raw); + +int +tp6801_read_file(Camera *camera, int idx, int **rgb24); + +int +tp6801_write_file(Camera *camera, int **rgb24); + +int +tp6801_delete_file(Camera *camera, int idx); + +int +tp6801_delete_all(Camera *camera); + +int +tp6801_commit(Camera *camera); + +int +tp6801_get_mem_size(Camera *camera); + +int +tp6801_get_free_mem_size(Camera *camera); + +int +tp6801_set_time_and_date(Camera *camera, struct tm *t); + +int +tp6801_filesize(Camera *camera); + +#endif Property changes on: trunk/libgphoto2/camlibs/tp6801/tp6801.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Modified: trunk/libgphoto2/configure.ac =================================================================== --- trunk/libgphoto2/configure.ac 2011-06-14 14:06:51 UTC (rev 13653) +++ trunk/libgphoto2/configure.ac 2011-06-14 14:15:24 UTC (rev 13654) @@ -555,6 +555,7 @@ GP_CAMLIB([template], [unlisted])dnl GP_CAMLIB([topfield])dnl GP_CAMLIB([toshiba_pdrm11])dnl +GP_CAMLIB([tp6801])dnl dnl GP_CAMLIBS_DEFINE()dnl GP_CONFIG_MSG([Camlibs],[${camlibs}]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |