1 /* Sitronix st2205 picframe access library
3 * Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; either version 2.1 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/types.h>
32 #include <gphoto2/gphoto2-result.h>
35 struct image_table_entry {
36 uint8_t present; /* 1 when this image is present, 0 when deleted */
37 uint32_t address; /* memory address where this image is stored */
38 char name[ST2205_FILENAME_LENGTH + 1]; /* Image name (11 bytes) */
39 } __attribute__((packed));
41 /* The st2205 port driver's write and read functions require page aligned
42 buffers, as they use O_DIRECT. */
43 static char *st2205_malloc_page_aligned(int size)
48 fd = open ("/dev/zero", O_RDWR);
49 aligned = mmap (0, size, PROT_READ|PROT_WRITE,MAP_PRIVATE, fd, 0);
50 if (aligned == MAP_FAILED)
56 static void st2205_free_page_aligned(char *aligned, int size)
59 munmap(aligned, size);
63 st2205_send_command(Camera *camera, int cmd, int arg1, int arg2)
65 char *buf = camera->pl->buf;
67 if (gp_port_seek (camera->port, ST2205_CMD_OFFSET, SEEK_SET) !=
73 buf[1] = (arg1 >> 24) & 0xff;
74 buf[2] = (arg1 >> 16) & 0xff;
75 buf[3] = (arg1 >> 8) & 0xff;
76 buf[4] = (arg1 ) & 0xff;
77 buf[5] = (arg2 >> 24) & 0xff;
78 buf[6] = (arg2 >> 16) & 0xff;
79 buf[7] = (arg2 >> 8) & 0xff;
80 buf[8] = (arg2 ) & 0xff;
82 if (gp_port_write (camera->port, buf, 512) != 512)
83 return GP_ERROR_IO_WRITE;
89 st2205_read_block(Camera *camera, int block, char *buf)
92 if (camera->pl->mem_dump) {
93 ret = fseek(camera->pl->mem_dump, block * ST2205_BLOCK_SIZE,
96 gp_log (GP_LOG_ERROR, "st2205",
97 "seeking in memdump: %s", strerror(errno));
98 return GP_ERROR_IO_READ;
100 ret = fread(buf, 1, ST2205_BLOCK_SIZE, camera->pl->mem_dump);
101 if (ret != ST2205_BLOCK_SIZE) {
103 gp_log (GP_LOG_ERROR, "st2205",
104 "reading memdump: %s",
107 gp_log (GP_LOG_ERROR, "st2205",
108 "short read reading from memdump");
109 return GP_ERROR_IO_READ;
112 CHECK (st2205_send_command (camera, 4, block,
114 if (gp_port_seek (camera->port, ST2205_READ_OFFSET, SEEK_SET)
115 != ST2205_READ_OFFSET)
118 if (gp_port_read (camera->port, buf, ST2205_BLOCK_SIZE)
119 != ST2205_BLOCK_SIZE)
120 return GP_ERROR_IO_READ;
126 st2205_write_block(Camera *camera, int block, char *buf)
129 if (camera->pl->mem_dump) {
130 ret = fseek(camera->pl->mem_dump, block * ST2205_BLOCK_SIZE,
133 gp_log (GP_LOG_ERROR, "st2205",
134 "seeking in memdump: %s", strerror(errno));
135 return GP_ERROR_IO_WRITE;
137 ret = fwrite(buf, 1, ST2205_BLOCK_SIZE, camera->pl->mem_dump);
138 if (ret != ST2205_BLOCK_SIZE) {
139 gp_log (GP_LOG_ERROR, "st2205",
140 "writing memdump: %s", strerror(errno));
141 return GP_ERROR_IO_WRITE;
144 /* Prepare for write */
145 CHECK (st2205_send_command (camera, 3, block,
148 if (gp_port_seek (camera->port, ST2205_WRITE_OFFSET, SEEK_SET)
149 != ST2205_WRITE_OFFSET)
152 if (gp_port_write (camera->port, buf, ST2205_BLOCK_SIZE)
153 != ST2205_BLOCK_SIZE)
154 return GP_ERROR_IO_WRITE;
156 CHECK (st2205_send_command (camera, 2, block,
158 /* Read commit response (ignored) */
159 if (gp_port_seek (camera->port, ST2205_READ_OFFSET, SEEK_SET)
160 != ST2205_READ_OFFSET)
163 if (gp_port_read (camera->port, camera->pl->buf, 512)
165 return GP_ERROR_IO_READ;
171 st2205_check_block_present(Camera *camera, int block)
175 if ((block + 1) * ST2205_BLOCK_SIZE > camera->pl->mem_size) {
176 gp_log (GP_LOG_ERROR, "st2205", "read beyond end of memory");
177 return GP_ERROR_CORRUPTED_DATA;
180 if (camera->pl->block_is_present[block])
183 ret = st2205_read_block(camera, block, camera->pl->mem +
184 block * ST2205_BLOCK_SIZE);
186 camera->pl->block_is_present[block] = 1;
192 st2205_detect_mem_size(Camera *camera)
197 buf0 = st2205_malloc_page_aligned(ST2205_BLOCK_SIZE);
198 buf1 = st2205_malloc_page_aligned(ST2205_BLOCK_SIZE);
199 if (!buf0 || !buf1) {
200 st2205_free_page_aligned(buf0, ST2205_BLOCK_SIZE);
201 st2205_free_page_aligned(buf1, ST2205_BLOCK_SIZE);
202 return GP_ERROR_NO_MEMORY;
205 ret = st2205_read_block(camera, 0, buf0);
209 for (i = 0; i < 3; i++) {
210 ret = st2205_read_block(camera,
211 (524288 / ST2205_BLOCK_SIZE) << i,
215 if (memcmp(buf0, buf1, ST2205_BLOCK_SIZE) == 0)
219 camera->pl->mem_size = 524288 << i;
221 st2205_free_page_aligned(buf0, ST2205_BLOCK_SIZE);
222 st2205_free_page_aligned(buf1, ST2205_BLOCK_SIZE);
228 st2205_read_mem(Camera *camera, int offset,
231 int to_copy, block = offset / ST2205_BLOCK_SIZE;
234 CHECK (st2205_check_block_present (camera, block))
236 to_copy = ST2205_BLOCK_SIZE - (offset % ST2205_BLOCK_SIZE);
240 memcpy(buf, camera->pl->mem + offset, to_copy);
250 st2205_write_mem(Camera *camera, int offset,
253 int to_copy, block = offset / ST2205_BLOCK_SIZE;
255 /* Don't allow writing to the firmware space */
257 (camera->pl->mem_size - camera->pl->firmware_size)) {
258 gp_log (GP_LOG_ERROR, "st2205", "write beyond end of memory");
259 return GP_ERROR_CORRUPTED_DATA;
263 CHECK (st2205_check_block_present (camera, block))
265 to_copy = ST2205_BLOCK_SIZE - (offset % ST2205_BLOCK_SIZE);
269 memcpy(camera->pl->mem + offset, buf, to_copy);
270 camera->pl->block_dirty[block] = 1;
281 st2205_read_file_count(Camera *camera)
285 CHECK (st2205_read_mem (camera, ST2205_COUNT_OFFSET, &count, 1))
291 st2205_write_file_count(Camera *camera, int count)
295 CHECK (st2205_write_mem (camera, ST2205_COUNT_OFFSET, &c, 1))
301 st2205_calc_fat_checksum(Camera *camera)
305 CHECK (st2205_check_block_present(camera, 0))
307 /* Calculate the "FAT" checksum, note that the present bits are skipped
308 (as is the checksum location itself). The picframe itself does not
309 care about this, but the windows software does! */
310 for (i = 2; i < ST2205_FAT_SIZE; i++)
312 checksum += (uint8_t)camera->pl->mem[i];
314 return checksum & 0xffff;
318 st2205_check_fat_checksum(Camera *camera)
320 int checksum, expected_checksum;
322 CHECK (st2205_check_block_present (camera, 0))
323 checksum = le16atoh ((uint8_t *)camera->pl->mem);
325 expected_checksum = st2205_calc_fat_checksum (camera);
326 if (expected_checksum < 0) return expected_checksum;
328 if (checksum != expected_checksum) {
329 gp_log (GP_LOG_ERROR, "st2205",
330 "image table checksum mismatch");
331 return GP_ERROR_CORRUPTED_DATA;
338 st2205_update_fat_checksum(Camera *camera)
343 checksum = st2205_calc_fat_checksum(camera);
344 if (checksum < 0) return checksum;
346 htole16a(buf, checksum);
347 return st2205_write_mem (camera, 0, buf, 2);
350 static int st2205_copy_fat(Camera *camera)
354 /* The "FAT" repeats itself on some frames, copy it over */
355 CHECK (st2205_check_block_present (camera, 0))
356 for (i = 1; i < camera->pl->no_fats; i++)
357 CHECK (st2205_write_mem (camera, i * ST2205_FAT_SIZE,
358 camera->pl->mem, ST2205_FAT_SIZE))
364 st2205_add_picture(Camera *camera, int idx, const char *filename,
365 int start, int shuffle, unsigned char *buf, int size)
368 struct image_table_entry entry;
370 count = st2205_read_file_count(camera);
371 if (count < 0) return count;
374 gp_log (GP_LOG_ERROR, "st2205",
375 "adding picture beyond end of FAT");
376 return GP_ERROR_BAD_PARAMETERS;
379 memset(&entry, 0, sizeof(entry));
381 entry.address = htole32(start);
382 snprintf(entry.name, sizeof(entry.name), "%s", filename);
383 CHECK (st2205_write_mem (camera, ST2205_FILE_OFFSET (idx),
384 &entry, sizeof(entry)))
387 /* update picture count */
389 CHECK (st2205_write_file_count (camera, count))
391 /* Add a fake last entry, with no name pointing to beginning
392 of freespace, neither the windows software nor the picframe
393 seem to care about this, but the windows software does this,
394 so lets do it too. */
395 memset (&entry, 0, sizeof(entry));
396 entry.address = htole32 (start + size);
397 CHECK (st2205_write_mem (camera, ST2205_FILE_OFFSET (count),
398 &entry, sizeof(entry)))
401 CHECK (st2205_update_fat_checksum (camera))
402 CHECK (st2205_copy_fat (camera))
403 CHECK (st2205_write_mem (camera, start, buf, size))
405 /* Let the caller know at which index we stored the table entry */
409 static int st2205_file_present(Camera *camera, int idx)
411 struct image_table_entry entry;
413 CHECK (st2205_read_mem (camera, ST2205_FILE_OFFSET (idx),
414 &entry, sizeof(entry)))
416 return entry.present;
419 /***************** Begin "public" functions *****************/
421 /* Note this function assumes the names array is filled with zeros
422 before it gets called */
424 st2205_get_filenames(Camera *camera, st2205_filename *names)
427 struct image_table_entry entry;
429 count = st2205_read_file_count(camera);
430 if (count < 0) return count;
432 if (count > ST2205_MAX_NO_FILES) {
433 gp_log (GP_LOG_ERROR, "st2205", "file table count overflow");
434 return GP_ERROR_CORRUPTED_DATA;
437 for (i = 0; i < count; i++) {
438 CHECK (st2205_read_mem (camera, ST2205_FILE_OFFSET (i),
439 &entry, sizeof(entry)))
444 /* Note we use memcpy as we don't want to depend on the names
445 on the picframe being 0-terminated. We always write 0
446 terminated names, as does windows, but better safe then
448 memcpy(names[i], entry.name, ST2205_FILENAME_LENGTH);
449 /* Make sure a file with no name gets a "name" */
458 st2205_read_raw_file(Camera *camera, int idx, unsigned char **raw)
460 struct image_table_entry entry;
461 struct st2205_image_header header;
462 int ret, count, size;
466 count = st2205_read_file_count(camera);
467 if (count < 0) return count;
470 gp_log (GP_LOG_ERROR, "st2205",
471 "read file beyond end of FAT");
472 return GP_ERROR_BAD_PARAMETERS;
475 CHECK (st2205_read_mem (camera, ST2205_FILE_OFFSET (idx),
476 &entry, sizeof(entry)))
478 /* This should never happen */
479 if (!entry.present) {
480 gp_log (GP_LOG_ERROR, "st2205",
481 "trying to read a deleted file");
482 return GP_ERROR_BAD_PARAMETERS;
484 LE32TOH(entry.address);
486 GP_DEBUG ("file: %d start at: %08x\n", idx, entry.address);
488 if (camera->pl->compressed) {
489 CHECK (st2205_read_mem (camera, entry.address,
490 &header, sizeof(header)))
492 if (header.marker != ST2205_HEADER_MARKER) {
493 gp_log (GP_LOG_ERROR, "st2205", "invalid header magic");
494 return GP_ERROR_CORRUPTED_DATA;
497 BE16TOH(header.width);
498 BE16TOH(header.height);
499 BE16TOH(header.length);
500 BE16TOH(header.blocks);
502 if ((header.width != camera->pl->width) ||
503 (header.height != camera->pl->height)) {
504 gp_log (GP_LOG_ERROR, "st2205",
505 "picture size does not match frame size.");
506 return GP_ERROR_CORRUPTED_DATA;
509 if (((header.width / 8) * (header.height / 8)) != header.blocks) {
510 gp_log (GP_LOG_ERROR, "st2205", "invalid block count");
511 return GP_ERROR_CORRUPTED_DATA;
514 GP_DEBUG ("file: %d header read, size: %dx%d, length: %d bytes\n",
515 idx, header.width, header.height, header.length);
517 size = header.length + sizeof (header);
519 size = camera->pl->width * camera->pl->height * 2;
521 *raw = malloc (size);
523 gp_log (GP_LOG_ERROR, "st2205", "allocating memory");
524 return GP_ERROR_NO_MEMORY;
527 ret = st2205_read_mem (camera, entry.address, *raw, size);
538 st2205_read_file(Camera *camera, int idx, int **rgb24)
543 CHECK (st2205_read_raw_file (camera, idx, &src))
545 if (camera->pl->compressed)
546 ret = st2205_decode_image (camera->pl, src, rgb24);
548 ret = st2205_rgb565_to_rgb24 (camera->pl, src, rgb24);
556 st2205_real_write_file(Camera *camera,
557 const char *filename, int **rgb24, unsigned char *buf,
558 int shuffle, int allow_uv_corr)
561 struct image_table_entry entry;
562 struct st2205_image_header header;
563 int i, start, end, hole_start = 0, hole_idx = 0;
565 if (camera->pl->compressed)
566 size = st2205_code_image (camera->pl, rgb24, buf, shuffle,
569 size = st2205_rgb24_to_rgb565 (camera->pl, rgb24, buf);
571 count = st2205_read_file_count (camera);
572 if (count < 0) return count;
574 /* Try to find a large enough "hole" in the memory */
575 end = camera->pl->picture_start;
576 for (i = 0; i <= count; i++) {
577 /* Fake a present entry at the end of picture mem */
580 start = camera->pl->mem_size -
581 camera->pl->firmware_size;
582 /* If the last entry in the "FAT" was present, we need
583 to set hole_start to the end of the last picture */
589 CHECK (st2205_read_mem (camera, ST2205_FILE_OFFSET (i),
590 (unsigned char *)&entry,
593 start = entry.address;
595 if (camera->pl->compressed) {
596 CHECK (st2205_read_mem (camera, start,
600 BE16TOH(header.length);
601 end = start + sizeof(header) +
608 /* If we have a hole start address look for present entries (so a hole end
609 address), otherwise look for non present entries */
612 int hole_size = start - hole_start;
613 GP_DEBUG ("found a hole at: %08x, of %d bytes "
614 "(need %d)\n", hole_start, hole_size,
616 if (hole_size < size) {
617 /* Too small, start searching
623 /* bingo we have a large enough hole */
624 return st2205_add_picture(camera, hole_idx,
625 filename, hole_start, shuffle,
629 if (!entry.present) {
630 /* We have a hole starting at the end of the
631 *previous* picture, note that end at this
632 moment points to the end of the last present
633 picture, as we don't set end for non present
634 pictures, which is exactly what we want. */
641 /* No freespace found, try again with uv correction tables disabled */
642 if (camera->pl->compressed && allow_uv_corr)
643 return st2205_real_write_file (camera, filename, rgb24, buf,
646 gp_log (GP_LOG_ERROR, "st2205", "not enough freespace to add file %s",
648 return GP_ERROR_NO_SPACE;
652 st2205_write_file(Camera *camera,
653 const char *filename, int **rgb24)
655 /* The buffer must be large enough for the worst case scenario */
656 unsigned char buf[camera->pl->width * camera->pl->height * 2];
659 shuffle = (long long)rand_r(&camera->pl->rand_seed) *
660 camera->pl->no_shuffles / (RAND_MAX + 1ll);
662 return st2205_real_write_file (camera, filename, rgb24, buf,
667 st2205_delete_file(Camera *camera, int idx)
670 int i, present, count, new_count = 0;
672 count = st2205_read_file_count(camera);
673 if (count < 0) return count;
676 gp_log (GP_LOG_ERROR, "st2205",
677 "delete file beyond end of FAT");
678 return GP_ERROR_BAD_PARAMETERS;
681 /* Calculate new file count after the delete operation */
682 for (i = 0; i < count; i++) {
686 present = st2205_file_present (camera, i);
687 if (present < 0) return present;
692 CHECK (st2205_write_mem (camera, ST2205_FILE_OFFSET (idx), &c, 1))
693 CHECK (st2205_write_file_count (camera, new_count))
694 CHECK (st2205_update_fat_checksum (camera))
695 CHECK (st2205_copy_fat (camera))
701 st2205_delete_all(Camera *camera)
703 CHECK (st2205_check_block_present(camera, 0))
704 memset (camera->pl->mem + ST2205_FILE_OFFSET (0), 0,
705 ST2205_FAT_SIZE - ST2205_FILE_OFFSET (0));
706 /* Mark the memory block we've directly manipulated dirty. */
707 camera->pl->block_dirty[0] = 1;
709 CHECK (st2205_write_file_count (camera, 0))
710 CHECK (st2205_update_fat_checksum (camera))
711 CHECK (st2205_copy_fat (camera))
717 st2205_set_time_and_date(Camera *camera, struct tm *t)
719 uint8_t *buf = (uint8_t *)camera->pl->buf;
721 /* We cannot do this when operating on a dump */
722 if (camera->pl->mem_dump)
726 buf[0] = 6; /* cmd 6 set time */
727 htobe16a (buf + 1, t->tm_year + 1900);
728 buf[3] = t->tm_mon + 1;
732 /* The st2205 does not allow one to set seconds, instead the
733 seconds end up being whatever they were when the set time
734 command is send :( */
736 if (gp_port_seek (camera->port, ST2205_CMD_OFFSET, SEEK_SET)
737 != ST2205_CMD_OFFSET)
740 if (gp_port_write (camera->port, camera->pl->buf, 512) != 512)
741 return GP_ERROR_IO_WRITE;
743 /* HACK, the st2205 does not like it if this is the last command
744 send to it, so force re-reading of block 0 */
745 camera->pl->block_is_present[0] = 0;
746 CHECK (st2205_check_block_present(camera, 0))
752 st2205_commit(Camera *camera)
755 int mem_block_size = (camera->pl->mem_size - camera->pl->firmware_size)
757 int erase_block_size = ST2205_ERASE_BLOCK_SIZE / ST2205_BLOCK_SIZE;
759 for (i = 0; i < mem_block_size; i += erase_block_size) {
760 for (j = 0; j < erase_block_size; j++)
761 if (camera->pl->block_dirty[i + j])
764 /* If we have no dirty blocks in this erase block continue */
765 if (j == erase_block_size)
768 /* Make sure all data blocks in this erase block have been
769 read before erasing the block! */
770 for (j = 0; j < erase_block_size; j++)
771 CHECK (st2205_check_block_present (camera, i + j))
773 /* Re-write all the data blocks in this erase block! */
774 for (j = 0; j < erase_block_size; j++) {
775 CHECK (st2205_write_block (camera, i + j,
779 camera->pl->block_dirty[i + j] = 0;
786 st2205_init(Camera *camera)
788 uint16_t *lookup_src, *dest;
789 uint8_t *shuffle_src;
790 int x, y, i, j, shuffle_size, checksum, expected_checksum;
793 int width, height, no_tables, usable_tables;
794 unsigned char unknown3[8];
797 { 128, 160, 8, 7, /* Last shuffle table does not work ?? */
798 { 0xff, 0xff, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
801 { 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01 },
804 { 0xff, 0xff, 0x04, 0x04, 0x04, 0x04, 0x04 },
807 { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
817 { ST2205_V1_LOOKUP_OFFSET, ST2205_V1_FIRMWARE_SIZE,
818 ST2205_V1_PICTURE_START, 4 },
819 { ST2205_V2_LOOKUP_OFFSET, ST2205_V2_FIRMWARE_SIZE,
820 ST2205_V2_PICTURE_START, 1 },
823 const int uncompressed_firmware_checksums[] = {
824 0x00ab02fc, /* Frame 96x64 from blokker (Netherlands) */
825 0x00aa8060, /* Blokker frame with picframe hacked firmware */
828 GP_DEBUG ("st2205_init called");
830 CHECK (st2205_detect_mem_size(camera))
832 if ((camera->pl->width % 8) || (camera->pl->height % 8)) {
833 gp_log (GP_LOG_ERROR, "st2205",
834 "lcd width and height must be a multiple of 8");
838 if (camera->pl->width == 240 && camera->pl->height == 320)
841 shuffle_size = (camera->pl->width / 8) * (camera->pl->height / 8);
842 if (shuffle_size > ST2205_SHUFFLE_SIZE) {
843 gp_log (GP_LOG_ERROR, "st2205",
844 "shuffle table size too small!");
845 return GP_ERROR_FIXED_LIMIT_EXCEEDED;
848 camera->pl->mem = st2205_malloc_page_aligned(camera->pl->mem_size);
849 if (!camera->pl->mem)
850 return GP_ERROR_NO_MEMORY;
852 /* Get the lookup tables from the device */
853 for (i = 0; version_info[i].lookup_offset; i++) {
854 int lookup_offset = version_info[i].lookup_offset;
857 if ((lookup_offset + ST2205_LOOKUP_SIZE) >
858 camera->pl->mem_size)
861 CHECK (st2205_check_block_present(camera,
862 lookup_offset / ST2205_BLOCK_SIZE))
864 lookup_src = (uint16_t *)(camera->pl->mem + lookup_offset);
865 dest = (uint16_t *)(&camera->pl->lookup[0][0][0]);
866 for (j = 0; j < 3 * 256 * 8; j++) {
867 *dest++ = le16toh(*lookup_src++);
868 checksum += (uint8_t)
869 (camera->pl->mem + lookup_offset)[j * 2];
870 checksum += (uint8_t)
871 (camera->pl->mem + lookup_offset)[j * 2 + 1];
874 if (checksum == ST2205_LOOKUP_CHECKSUM)
878 if (!version_info[i].lookup_offset) {
879 gp_log (GP_LOG_ERROR, "st2205", "lookup tables not found");
880 return GP_ERROR_MODEL_NOT_FOUND;
883 camera->pl->firmware_size = version_info[i].firmware_size;
884 camera->pl->picture_start = version_info[i].picture_start;
885 camera->pl->no_fats = version_info[i].no_fats;
887 /* Generate shuffle tables 0 and 1 */
888 for (y = 0, i = 0; y < camera->pl->height; y += 8)
889 for (x = 0; x < camera->pl->width; x += 8, i++) {
890 camera->pl->shuffle[0][i].x = x;
891 camera->pl->shuffle[0][i].y = y;
894 for (x = 0, i = 0; x < camera->pl->width; x += 8)
895 for (y = 0; y < camera->pl->height; y += 8, i++) {
896 camera->pl->shuffle[1][i].x = x;
897 camera->pl->shuffle[1][i].y = y;
900 /* Get the other shuffle tables from the device (they start directly
901 after the chroma lookup table) */
902 shuffle_src = (uint8_t *)lookup_src;
904 /* Skip to the tables for the right resolution */
905 for (i = 0; shuffle_info[i].no_tables; i++) {
906 if (camera->pl->width == shuffle_info[i].width &&
907 camera->pl->height == shuffle_info[i].height)
909 if (is240x320 && shuffle_info[i].width == 120 &&
910 shuffle_info[i].height == 160)
912 shuffle_src += (shuffle_info[i].width *
913 shuffle_info[i].height * 2 / 64) *
914 (shuffle_info[i].no_tables - 2);
916 if (!shuffle_info[i].no_tables) {
917 gp_log (GP_LOG_ERROR, "st2205",
918 "unknown display resolution: %dx%d",
919 camera->pl->width, camera->pl->height);
920 return GP_ERROR_MODEL_NOT_FOUND;
923 memcpy (camera->pl->unknown3, shuffle_info[i].unknown3,
924 sizeof(camera->pl->unknown3));
925 camera->pl->no_shuffles = shuffle_info[i].usable_tables;
926 expected_checksum = shuffle_info[i].checksum;
928 for (j = 2; j < camera->pl->no_shuffles; j++)
929 for (i = 0; i < shuffle_size; i++) {
930 camera->pl->shuffle[j][i].x = *shuffle_src++;
931 camera->pl->shuffle[j][i].y = *shuffle_src++;
932 if (camera->pl->shuffle[j][i].x >= camera->pl->width ||
933 camera->pl->shuffle[j][i].y >= camera->pl->height){
934 gp_log (GP_LOG_ERROR, "st2205",
935 "shuffle table coordinate out of range");
936 return GP_ERROR_CORRUPTED_DATA;
938 checksum += camera->pl->shuffle[j][i].x;
939 checksum += camera->pl->shuffle[j][i].y;
941 camera->pl->shuffle[j][i].x *= 2;
942 camera->pl->shuffle[j][i].y *= 2;
943 camera->pl->shuffle[j][i + 1].x =
944 camera->pl->shuffle[j][i].x + 8;
945 camera->pl->shuffle[j][i + 1].y =
946 camera->pl->shuffle[j][i].y;
947 camera->pl->shuffle[j][i + 2].x =
948 camera->pl->shuffle[j][i].x;
949 camera->pl->shuffle[j][i + 2].y =
950 camera->pl->shuffle[j][i].y + 8;
951 camera->pl->shuffle[j][i + 3].x =
952 camera->pl->shuffle[j][i].x + 8;
953 camera->pl->shuffle[j][i + 3].y =
954 camera->pl->shuffle[j][i].y + 8;
959 if (checksum != expected_checksum) {
960 gp_log (GP_LOG_ERROR, "st2205",
961 "shuffle table checksum mismatch");
962 return GP_ERROR_MODEL_NOT_FOUND;
965 CHECK (st2205_check_fat_checksum (camera))
967 camera->pl->rand_seed = time(NULL);
969 /* Some 96x64 models don't use compression, unfortunately I've found
970 no way to detect if this is the case, so we keep a list of firmware
971 checksums to identify these. */
972 for (i = camera->pl->mem_size - camera->pl->firmware_size;
973 i < camera->pl->mem_size; i += ST2205_BLOCK_SIZE)
974 CHECK (st2205_check_block_present (camera,
975 i / ST2205_BLOCK_SIZE))
977 for (i = camera->pl->mem_size - camera->pl->firmware_size;
978 i < camera->pl->mem_size; i++)
979 checksum += (uint8_t)camera->pl->mem[i];
981 GP_DEBUG ("firmware checksum: 0x%08x", checksum);
983 for (i = 0; uncompressed_firmware_checksums[i]; i++)
984 if (uncompressed_firmware_checksums[i] == checksum)
987 if (!uncompressed_firmware_checksums[i])
988 camera->pl->compressed = 1;
990 camera->pl->compressed = 0;
996 st2205_exit(Camera *camera)
998 st2205_free_page_aligned(camera->pl->mem, camera->pl->mem_size);
999 camera->pl->mem = NULL;
1003 st2205_open_device(Camera *camera)
1005 camera->pl->buf = st2205_malloc_page_aligned(512);
1006 if (!camera->pl->buf)
1007 return GP_ERROR_NO_MEMORY;
1009 /* Check this is a Sitronix frame */
1010 CHECK (gp_port_seek (camera->port, 0, SEEK_SET))
1011 if (gp_port_read (camera->port, camera->pl->buf, 512) != 512)
1012 return GP_ERROR_IO_READ;
1013 if (strcmp (camera->pl->buf, "SITRONIX CORP."))
1014 return GP_ERROR_MODEL_NOT_FOUND;
1016 /* Read LCD size from the device */
1017 CHECK (st2205_send_command (camera, 5, 0 ,0))
1019 if (gp_port_seek (camera->port, ST2205_READ_OFFSET, SEEK_SET) !=
1023 if (gp_port_read (camera->port, camera->pl->buf, 512) != 512)
1024 return GP_ERROR_IO_READ;
1026 camera->pl->width = be16atoh ((uint8_t *)camera->pl->buf);
1027 camera->pl->height = be16atoh ((uint8_t *)camera->pl->buf + 2);
1029 GP_DEBUG ("Sitronix picframe of %dx%d detected.",
1030 camera->pl->width, camera->pl->height);
1032 return st2205_init (camera);
1036 st2205_open_dump(Camera *camera, const char *dump,
1037 int width, int height)
1039 camera->pl->mem_dump = fopen(dump, "r+");
1040 if (!camera->pl->mem_dump) {
1041 gp_log (GP_LOG_ERROR, "st2205", "opening memdump file: %s: %s",
1042 dump, strerror(errno));
1043 return GP_ERROR_IO_INIT;
1046 camera->pl->width = width;
1047 camera->pl->height = height;
1049 return st2205_init (camera);
1052 void st2205_close(Camera *camera)
1054 st2205_exit (camera);
1055 if (camera->pl->mem_dump) {
1056 fclose (camera->pl->mem_dump);
1057 camera->pl->mem_dump = NULL;
1059 st2205_free_page_aligned(camera->pl->buf, 512);
1060 camera->pl->buf = NULL;
1064 st2205_get_mem_size(Camera *camera)
1066 return camera->pl->mem_size;
1070 st2205_get_free_mem_size(Camera *camera)
1072 struct image_table_entry entry;
1073 struct st2205_image_header header;
1074 int i, count, start, end, hole_start = 0, free = 0;
1076 count = st2205_read_file_count (camera);
1077 if (count < 0) return count;
1079 /* Find all holes in the memory and add their sizes together */
1080 end = camera->pl->picture_start;
1081 for (i = 0; i <= count; i++) {
1082 /* Fake a present entry at the end of picture mem */
1085 start = camera->pl->mem_size -
1086 camera->pl->firmware_size;
1087 /* If the last entry in the "FAT" was present, we need
1088 to set hole_start to the end of the last picture */
1092 CHECK (st2205_read_mem (camera, ST2205_FILE_OFFSET (i),
1093 &entry, sizeof(entry)))
1095 start = entry.address;
1096 if (entry.present) {
1097 if (camera->pl->compressed) {
1098 CHECK (st2205_read_mem (camera, start,
1102 BE16TOH(header.length);
1103 end = start + sizeof(header) +
1108 camera->pl->height * 2;
1113 /* If we have a hole start address look for present entries (so
1114 a hole end address), else look for non present entries */
1116 if (entry.present) {
1117 free += start - hole_start;