/****************************************************************/ /* spca50x_sdram.c - Gphoto2 library for cameras with sunplus */ /* spca50x chips */ /* */ /* Copyright © 2002, 2003 Till Adam */ /* */ /* Author: Till Adam <till@adam-lilienthal.de> */ /* */ /* This library is free software; you can redistribute it */ /* and/or modify it under the terms of the GNU Library General */ /* Public License as published by the Free Software Foundation; */ /* either version 2 of the License, or (at your option) any */ /* later version. */ /* */ /* This library is distributed in the hope that it will be */ /* useful, but WITHOUT ANY WARRANTY; without even the implied */ /* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */ /* PURPOSE. See the GNU Library General Public License for */ /* more details. */ /* */ /* You should have received a copy of the GNU Library General */ /* Public License along with this library; if not, write to the */ /* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ /* Boston, MA 02111-1307, USA. */ /****************************************************************/ #include "config.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include <gphoto2/gphoto2.h> #include "gphoto2-endian.h" #include "spca50x.h" #include "spca50x-sdram.h" #include "spca50x-registers.h" #include "spca50x-avi-header.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 "spca50x" static int spca50x_mode_set_idle (CameraPrivateLibrary * lib); static int spca50x_is_idle (CameraPrivateLibrary * lib); static int spca50x_mode_set_download (CameraPrivateLibrary * lib); static int spca50x_download_data (CameraPrivateLibrary * lib, uint32_t start, unsigned int size, uint8_t * buf); static int spca50x_get_FATs (CameraPrivateLibrary * lib, int dramtype); static int spca50x_sdram_get_file_count_and_fat_count (CameraPrivateLibrary * lib, int dramtype); static int spca50x_get_avi_thumbnail (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file); static int spca50x_get_image_thumbnail (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file); static int spca50x_get_avi (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file); static int spca50x_get_image (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file); static inline uint8_t *put_dword (uint8_t * ptr, uint32_t value); static int spca50x_sdram_get_fat_page (CameraPrivateLibrary * lib, int index, int dramtype, uint8_t *p) { switch (dramtype) { case 4: /* 128 Mbit */ CHECK (spca50x_download_data (lib, 0x7fff80 - index * 0x80, SPCA50X_FAT_PAGE_SIZE, p)); break; case 3: /* 64 Mbit */ CHECK (spca50x_download_data (lib, 0x3fff80 - index * 0x80, SPCA50X_FAT_PAGE_SIZE, p)); break; default: break; } return GP_OK; } static int spca50x_sdram_get_file_count_and_fat_count (CameraPrivateLibrary * lib, int dramtype) { uint8_t theFat[256]; lib->num_fats = 0; lib->num_files_on_sdram = 0; if (lib->bridge == BRIDGE_SPCA500){ uint8_t lower, upper; CHECK (gp_port_usb_msg_write (lib->gpdev, 0x5, 0, 0, NULL, 0)); sleep (1); CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, 0xe15, (uint8_t *) & lib->num_files_on_sdram, 1)); LE32TOH (lib->num_files_on_sdram); /* get fatscount */ CHECK (gp_port_usb_msg_write (lib->gpdev, 0x05, 0x0000, 0x0008, NULL, 0)); sleep (1); CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, 0x0e19, (uint8_t *) & lower, 1)); CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, 0x0e20, (uint8_t *) & upper, 1)); lib->num_fats = ((upper & 0xFF << 8) | (lower & 0xFF)); } else { while (1) { CHECK (spca50x_sdram_get_fat_page (lib, lib->num_fats, dramtype, theFat)); if (theFat[0] == 0xFF) break; if (theFat[0] == 0x08 || theFat[0] == 0x00) lib->num_files_on_sdram++; lib->num_fats++; } } return (GP_OK); } int spca50x_sdram_delete_file (CameraPrivateLibrary * lib, unsigned int index) { struct SPCA50xFile *g_file; uint16_t fat_index; CHECK (spca50x_sdram_get_file_info (lib, index, &g_file)); if (lib->bridge == BRIDGE_SPCA500) fat_index = 0x70FF - g_file->fat_start - 1; else /* if (lib->bridge == BRIDGE_SPCA504) */ fat_index = 0xD8000 - g_file->fat_start - 1; CHECK (gp_port_usb_msg_write (lib->gpdev, 0x06, fat_index, 0x0007, NULL, 0)); sleep (1); /* Reread fats the next time it is accessed */ lib->dirty_sdram = 1; return GP_OK; } int spca50x_sdram_delete_all (CameraPrivateLibrary * lib) { if (lib->fw_rev == 2) { CHECK (gp_port_usb_msg_write (lib->gpdev, 0x71, 0x0000, 0x0000, NULL, 0)); } else { CHECK (gp_port_usb_msg_write (lib->gpdev, 0x02, 0x0000, 0x0005, NULL, 0)); } sleep (3); /* Reread fats the next time it is accessed */ lib->dirty_sdram = 1; return GP_OK; } int spca50x_sdram_request_file (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, unsigned int number, int *type) { struct SPCA50xFile *g_file; CHECK (spca50x_sdram_get_file_info (lib, number, &g_file)); *type = g_file->mime_type; if (g_file->mime_type == SPCA50X_FILE_TYPE_AVI) return (spca50x_get_avi (lib, buf, len, g_file)); else return (spca50x_get_image (lib, buf, len, g_file)); } static int spca50x_get_image (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file) { uint8_t *p, *lp_jpg; uint8_t qIndex = 0, format; uint32_t start; uint8_t *mybuf; int size, o_size, file_size, ret; int omit_escape = 0; p = g_file->fat; /* get the position in memory where the image is */ start = (p[1] & 0xff) + (p[2] & 0xff) * 0x100; start *= 128; /* decode the image size */ if (lib->bridge == BRIDGE_SPCA500) { o_size = size = (p[5] & 0xff) * 0x100 + (p[6] & 0xff) * 0x10000; qIndex = p[7] & 0x0f; } else { o_size = size = (p[13] & 0xff) * 0x10000 + (p[12] & 0xff) * 0x100 + (p[11] & 0xff); if (lib->fw_rev == 1) { qIndex = p[7] & 0x0f; } else if (lib->fw_rev == 2) { omit_escape = 1; qIndex = p[10] & 0x0f; } } format = 0x21; /* align */ if (size % 64 != 0) size = ((size / 64) + 1) * 64; file_size = size + SPCA50X_JPG_DEFAULT_HEADER_LENGTH + 1024 * 10; /* slurp in the image */ mybuf = malloc (size); if (!mybuf) return GP_ERROR_NO_MEMORY; if (lib->bridge == BRIDGE_SPCA504) { ret = spca50x_download_data (lib, start, size, mybuf); if (ret < GP_OK) { free (mybuf); return ret; } } else if (lib->bridge == BRIDGE_SPCA500) { /* find the file index on the camera */ int index; index = (g_file->fat - lib->fats) / SPCA50X_FAT_PAGE_SIZE; spca50x_reset (lib); /* trigger upload of image at that index */ ret = gp_port_usb_msg_write (lib->gpdev, 0x06, 0x70FF - index, 0x01, NULL, 0); if (ret < GP_OK) { free (mybuf); return ret; } sleep (1); ret = gp_port_read (lib->gpdev, mybuf, size); if (ret < GP_OK) { free (mybuf); return ret; } /* the smallest ones are in a different format */ if ((p[20] & 0xff) == 2) format = 0x22; } /* now build a jpeg */ lp_jpg = malloc (file_size); if (!lp_jpg) { free (mybuf); return GP_ERROR_NO_MEMORY; } create_jpeg_from_data (lp_jpg, mybuf, qIndex, g_file->width, g_file->height, format, o_size, &file_size, 0, omit_escape); free (mybuf); lp_jpg = realloc (lp_jpg, file_size); *buf = lp_jpg; *len = file_size; return (GP_OK); } static int spca50x_get_avi (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file) { int i, j, length, ret; int frame_count = 0, frames_per_fat = 0, fn = 0; int size = 0; int file_size; int index_size; uint32_t frame_size = 0, frame_width = 0, frame_height = 0; uint32_t total_frame_size = 0; uint32_t start = 0; uint8_t *p, *mybuf, *avi, *start_of_file, *start_of_frame, *data; uint8_t qIndex; uint8_t *avi_index, *avi_index_ptr; uint8_t index_item[16]; /* FIXME */ if (lib->bridge == BRIDGE_SPCA500) return GP_ERROR_NOT_SUPPORTED; p = g_file->fat; if (lib->fw_rev == 2) qIndex = p[10] & 0x0f; else qIndex = p[7] & 0x0f; avi = mybuf = start_of_file = data = NULL; /* get the position in memory where the movie is */ start = (p[1] & 0xff) + (p[2] & 0xff) * 0x100; start *= 128; /* Frame w and h and qIndex dont change, so just use the values * of the first frame */ frame_width = (p[8] & 0xFF) * 16; frame_height = (p[9] & 0xFF) * 16; /* Each movie consists of a number of frames, and can have more than * one fat page. Iterate over all fat pages for this movie and count * all frames in all fats. Same for size. */ for (i = g_file->fat_start; i <= g_file->fat_end; i++) { frames_per_fat = (p[49] & 0xFF) * 0x100 + (p[48] & 0xFF); frame_count += frames_per_fat; size += (p[13] & 0xFF) * 0x10000 + (p[12] & 0xFF) * 0x100 + (p[11] & 0xFF); if (frames_per_fat < 60) break; p += SPCA50X_FAT_PAGE_SIZE; } /* align */ size = (size + 63) & 0xffffffc0; /* mem for index */ index_size = frame_count * 16; avi_index_ptr = avi_index = malloc (index_size); if (!avi_index) return GP_ERROR_NO_MEMORY; /* slurp in the movie */ mybuf = malloc (size); if (!mybuf) { free (avi_index); return GP_ERROR_NO_MEMORY; } ret = spca50x_download_data (lib, start, size, mybuf); if (ret < GP_OK) { free (avi_index); free (mybuf); return ret; } /* Now write our data to a file with an avi header */ file_size = size + SPCA50X_AVI_HEADER_LENGTH + (SPCA50X_JPG_DEFAULT_HEADER_LENGTH * frame_count) + 8 + index_size /* for index chunk */ + 1024 * 10 * frame_count; avi = malloc (file_size); if (!avi) { free (avi_index); free (mybuf); return GP_ERROR_NO_MEMORY; } start_of_file = avi; /* prepare index item */ put_dword (index_item, 0x63643030); /* 00dc */ put_dword (index_item + 4, 0x10); /* KEYFRAME */ /* copy the header from the template */ memcpy (avi, SPCA50xAviHeader, SPCA50X_AVI_HEADER_LENGTH); /* put the width and height into the riff header */ put_dword(avi + 0x40, frame_width); put_dword(avi + 0x44, frame_height); /* and at 0xb0 and 0xb4 */ put_dword(avi + 0xb0, frame_width); put_dword(avi + 0xb4, frame_height); avi += SPCA50X_AVI_HEADER_LENGTH; /* Reset to the first fat */ p = g_file->fat; data = mybuf; /* Iterate over fats and frames in each fat and build a jpeg for * each frame. Add the jpeg to the avi and write an index entry. */ for (i = g_file->fat_start; i <= g_file->fat_end; i++) { frames_per_fat = ((p[49] & 0xFF) * 0x100 + (p[48] & 0xFF)); /* frames per fat might be lying, so double check how many frames were already processed */ if (frames_per_fat > 60 || frames_per_fat == 0 || fn + frames_per_fat > frame_count) break; for (j = 0; j < frames_per_fat; j++) { frame_size = ((p[52 + j * 3] & 0xFF) * 0x10000) + ((p[51 + j * 3] & 0xFF) * 0x100) + (p[50 + j * 3] & 0xFF); memcpy (avi, SPCA50xAviFrameHeader, SPCA50X_AVI_FRAME_HEADER_LENGTH); avi += SPCA50X_AVI_FRAME_HEADER_LENGTH; start_of_frame = avi; /* jpeg starts here */ create_jpeg_from_data (avi, data, qIndex, frame_width, frame_height, 0x22, frame_size, &length, 1, 0); data += (frame_size + 7) & 0xfffffff8; avi += length; /* Make sure the next frame is aligned */ if ((avi - start_of_frame) % 2 != 0) avi++; /* Now we know the real frame size after escaping and * adding the EOI marker. Put it in the frame header. */ frame_size = avi - start_of_frame; put_dword (start_of_frame - 4, frame_size); put_dword (index_item + 8, start_of_frame - start_of_file - SPCA50X_AVI_HEADER_LENGTH - 4); put_dword (index_item + 12, frame_size); memcpy (avi_index_ptr, index_item, 16); avi_index_ptr += 16; fn++; } p += SPCA50X_FAT_PAGE_SIZE; } total_frame_size = avi - (start_of_file + SPCA50X_AVI_HEADER_LENGTH - 4); put_dword (start_of_file + SPCA50X_AVI_HEADER_LENGTH - 8, total_frame_size); avi = put_dword (avi, 0x31786469); /* idx1 */ avi = put_dword (avi, index_size); memcpy (avi, avi_index, index_size); avi += index_size; free (avi_index); put_dword (start_of_file + 0x30, frame_count); put_dword (start_of_file + 0x8c, frame_count); /* And reuse total_frame_size for the file size RIFF marker at offset * 4 */ total_frame_size = avi - (start_of_file + 4); put_dword (start_of_file + 4, total_frame_size); free (mybuf); start_of_file = realloc (start_of_file, avi - start_of_file); *buf = start_of_file; *len = avi - start_of_file; return (GP_OK); } int spca50x_sdram_request_thumbnail (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, unsigned int number, int *type) { struct SPCA50xFile *g_file; CHECK (spca50x_sdram_get_file_info (lib, number, &g_file)); *type = g_file->mime_type; if (g_file->mime_type == SPCA50X_FILE_TYPE_AVI) { return (spca50x_get_avi_thumbnail (lib, buf, len, g_file)); } else { /* the spca500 stores the quality in p[20], the rest of them * in [p40]. We need to check for the smallest resolution of * the mini, since resolution does not have thumbnails. * Download the full image instead. * Low: 320x240 2 * Middle: 640x480 0 * High: 1024x768 (interpolated) 1*/ if (lib->bridge == BRIDGE_SPCA500 && (g_file->fat[20] & 0xFF) == 2) { return (spca50x_get_image (lib, buf, len, g_file)); } else { return (spca50x_get_image_thumbnail (lib, buf, len, g_file)); } } } static int spca50x_get_avi_thumbnail (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file) { uint8_t *p, *lp_jpg; uint8_t qIndex; uint32_t start; uint8_t *mybuf; int size, o_size, file_size; int w, h, ret; /* FIXME */ if (lib->bridge == BRIDGE_SPCA500) return GP_ERROR_NOT_SUPPORTED; p = g_file->fat; /* get the position in memory where the image is */ start = (p[1] & 0xff) + (p[2] & 0xff) * 0x100; start *= 128; /* decode the image size */ o_size = size = (p[52] & 0xff) * 0x10000 + (p[51] & 0xff) * 0x100 + (p[50] & 0xff); qIndex = p[7] & 0x0f; w = (int) ((p[8] & 0xFF) * 16); h = (int) ((p[9] & 0xFF) * 16); /* align */ if (size % 64 != 0) size = ((size / 64) + 1) * 64; file_size = size + SPCA50X_JPG_DEFAULT_HEADER_LENGTH + 1024 * 10; /* slurp in the image */ mybuf = malloc (size); if (!mybuf) return GP_ERROR_NO_MEMORY; ret = spca50x_download_data (lib, start, size, mybuf); if (ret < GP_OK) { free (mybuf); return ret; } /* now build a jpeg */ lp_jpg = malloc (file_size); if (!lp_jpg) { free (mybuf); return GP_ERROR_NO_MEMORY; } create_jpeg_from_data (lp_jpg, mybuf, qIndex, g_file->width, g_file->height, 0x22, o_size, &file_size, 0, 0); free (mybuf); lp_jpg = realloc (lp_jpg, file_size); *buf = lp_jpg; *len = file_size; return (GP_OK); } static int spca50x_get_image_thumbnail (CameraPrivateLibrary * lib, uint8_t ** buf, unsigned int *len, struct SPCA50xFile *g_file) { unsigned int size; uint8_t *p; uint32_t start; uint8_t *mybuf = NULL; uint8_t *tmp; unsigned int t_width, t_height; uint8_t *yuv_p; uint8_t *rgb_p; int headerlength, ret; p = g_file->fat; start = (p[3] & 0xff) + (p[4] & 0xff) * 0x100; start *= 128; size = g_file->width * g_file->height * 2 / 64; t_width = g_file->width / 8; t_height = g_file->height / 8; /* Adjust the headerlenght */ headerlength = 13; if (t_width > 99) headerlength++; if (t_height > 99) headerlength++; /* align */ if (size % 64 != 0) size = ((size / 64) + 1) * 64; mybuf = malloc (size); if (lib->bridge == BRIDGE_SPCA504) { ret = spca50x_download_data (lib, start, size, mybuf); if (ret < GP_OK) { free (mybuf); return ret; } } else if (lib->bridge == BRIDGE_SPCA500) { /* find the file index on the camera */ int index; index = (g_file->fat - lib->fats) / SPCA50X_FAT_PAGE_SIZE; spca50x_reset (lib); /* trigger upload of thumbnail at that index */ ret = gp_port_usb_msg_write (lib->gpdev, 0x06, 0x70FF - index, 0x09, NULL, 0); if (ret < GP_OK) { free (mybuf); return ret; } sleep (1); ret = gp_port_read (lib->gpdev, mybuf, size); if (ret < GP_OK) { free (mybuf); return ret; } } *len = t_width * t_height * 3 + headerlength; *buf = malloc (*len); if (!*buf) { free (mybuf); return (GP_ERROR_NO_MEMORY); } tmp = *buf; snprintf (tmp, *len, "P6 %d %d 255\n", t_width, t_height); tmp += headerlength; yuv_p = mybuf; rgb_p = tmp; while (yuv_p < mybuf + (t_width * t_height * 2)) { unsigned int u, v, y, y2; unsigned int r, g, b; y = yuv_p[0]; y2 = yuv_p[1]; u = yuv_p[2]; v = yuv_p[3]; CHECK (yuv2rgb (y, u, v, &r, &g, &b)); *rgb_p++ = r; *rgb_p++ = g; *rgb_p++ = b; CHECK (yuv2rgb (y2, u, v, &r, &g, &b)); *rgb_p++ = r; *rgb_p++ = g; *rgb_p++ = b; yuv_p += 4; } free (mybuf); return (GP_OK); } int spca50x_sdram_get_info (CameraPrivateLibrary * lib) { unsigned int index; uint8_t dramtype = 0; uint8_t *p; uint32_t start_page, end_page; uint8_t file_type; GP_DEBUG ("* spca50x_sdram_get_info"); if (lib->bridge == BRIDGE_SPCA504) { if (!spca50x_is_idle (lib)) spca50x_mode_set_idle (lib); spca50x_mode_set_download (lib); CHECK (gp_port_usb_msg_write (lib->gpdev, 0x00, 0x0001, SPCA50X_REG_AutoPbSize, NULL, 0)); CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, SPCA50X_REG_DramType, (uint8_t *) & dramtype, 1)); dramtype &= 0xFF; } CHECK (spca50x_sdram_get_file_count_and_fat_count (lib, dramtype)); if (lib->num_files_on_sdram > 0) { CHECK (spca50x_get_FATs (lib, dramtype)); index = lib->files[lib->num_files_on_sdram - 1].fat_end; p = lib->fats + SPCA50X_FAT_PAGE_SIZE * index; /* p now points to the fat of the last image of the last file */ file_type = p[0]; start_page = ((p[2] & 0xFF) << 8) | (p[1] & 0xFF); end_page = start_page + (((p[6] & 0xFF) << 8) | (p[5] & 0xFF)); if (file_type == SPCA50X_FILE_TYPE_IMAGE) end_page = end_page + 0xA0; lib->size_used = (end_page - 0x2800) * SPCA50X_FAT_PAGE_SIZE; } else lib->size_used = 0; lib->size_free = 16 * 1024 * 1024 - 0x2800 * SPCA50X_FAT_PAGE_SIZE - lib->size_used; lib->dirty_sdram = 0; return GP_OK; } int spca50x_sdram_get_file_info (CameraPrivateLibrary * lib, unsigned int index, struct SPCA50xFile **g_file) { if (lib->dirty_sdram) CHECK (spca50x_sdram_get_info (lib)); *g_file = &(lib->files[index]); return GP_OK; } static int spca50x_mode_set_idle (CameraPrivateLibrary * lib) { CHECK (gp_port_usb_msg_write (lib->gpdev, 0, SPCA50X_CamMode_Idle, SPCA50X_REG_CamMode, NULL, 0)); return GP_OK; } static int spca50x_is_idle (CameraPrivateLibrary * lib) { int mode; CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, SPCA50X_REG_CamMode, (uint8_t *) & mode, 1)); return mode == SPCA50X_CamMode_Idle ? 1 : 0; } static int spca50x_mode_set_download (CameraPrivateLibrary * lib) { CHECK (gp_port_usb_msg_write (lib->gpdev, 0, SPCA50X_CamMode_Upload, SPCA50X_REG_CamMode, NULL, 0)); return GP_OK; } static int spca50x_download_data (CameraPrivateLibrary * lib, uint32_t start, unsigned int size, uint8_t * buf) { uint8_t foo; uint8_t vlcAddressL, vlcAddressM, vlcAddressH; if (!spca50x_is_idle (lib)) spca50x_mode_set_idle (lib); spca50x_mode_set_download (lib); foo = size & 0xFF; CHECK (gp_port_usb_msg_write (lib->gpdev, 0, foo, SPCA50X_REG_SdramSizeL, NULL, 0)); foo = (size >> 8) & 0xFF; CHECK (gp_port_usb_msg_write (lib->gpdev, 0, foo, SPCA50X_REG_SdramSizeM, NULL, 0)); foo = (size >> 16) & 0xFF; CHECK (gp_port_usb_msg_write (lib->gpdev, 0, foo, SPCA50X_REG_SdramSizeH, NULL, 0)); CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, SPCA50X_REG_VlcAddressL, (uint8_t *) & vlcAddressL, 1)); CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, SPCA50X_REG_VlcAddressM, (uint8_t *) & vlcAddressM, 1)); CHECK (gp_port_usb_msg_read (lib->gpdev, 0, 0, SPCA50X_REG_VlcAddressH, (uint8_t *) & vlcAddressH, 1)); foo = start & 0xFF; CHECK (gp_port_usb_msg_write (lib->gpdev, 0, foo, SPCA50X_REG_VlcAddressL, NULL, 0)); foo = (start >> 8) & 0xFF; CHECK (gp_port_usb_msg_write (lib->gpdev, 0, foo, SPCA50X_REG_VlcAddressM, NULL, 0)); foo = (start >> 16) & 0xFF; CHECK (gp_port_usb_msg_write (lib->gpdev, 0, foo, SPCA50X_REG_VlcAddressH, NULL, 0)); /* Set mode to ram -> usb */ CHECK (gp_port_usb_msg_write (lib->gpdev, 0, SPCA50X_DramUsb, SPCA50X_REG_PbSrc, NULL, 0)); /* and pull the trigger */ CHECK (gp_port_usb_msg_write (lib->gpdev, 0, SPCA50X_TrigDramFifo, SPCA50X_REG_Trigger, NULL, 0)); CHECK (gp_port_read (lib->gpdev, buf, size)); CHECK (gp_port_usb_msg_write (lib->gpdev, 0, vlcAddressL, SPCA50X_REG_VlcAddressL, NULL, 0)); CHECK (gp_port_usb_msg_write (lib->gpdev, 0, vlcAddressM, SPCA50X_REG_VlcAddressM, NULL, 0)); CHECK (gp_port_usb_msg_write (lib->gpdev, 0, vlcAddressH, SPCA50X_REG_VlcAddressH, NULL, 0)); spca50x_mode_set_idle (lib); return GP_OK; } static int spca50x_get_FATs (CameraPrivateLibrary * lib, int dramtype) { uint8_t type; unsigned int index = 0; unsigned int file_index = 0; uint8_t *p = NULL; uint8_t buf[14]; /* Reset image and movie counter */ lib->num_images = lib->num_movies = 0; if (lib->fats) { free (lib->fats); lib->fats = NULL; } if (lib->files) { free (lib->files); lib->files = NULL; } lib->fats = malloc (lib->num_fats * SPCA50X_FAT_PAGE_SIZE); lib->files = malloc (lib->num_files_on_sdram * sizeof (struct SPCA50xFile)); p = lib->fats; if (lib->bridge == BRIDGE_SPCA504) { while (index < lib->num_fats) { CHECK (spca50x_sdram_get_fat_page (lib, index, dramtype, p)); if (p[0] == 0xFF) break; index++; p += SPCA50X_FAT_PAGE_SIZE; } } else if (lib->bridge == BRIDGE_SPCA500) { /* for the spca500, download the whole fat in one go. */ spca50x_reset (lib); CHECK (gp_port_usb_msg_write (lib->gpdev, 0x05, 0x00, 0x07, NULL, 0)); sleep (1); CHECK (gp_port_read (lib->gpdev, lib->fats, lib->num_fats * SPCA50X_FAT_PAGE_SIZE)); } p = lib->fats; index = 0; while (index < lib->num_fats) { type = p[0]; /* While the spca504a indicates start of avi as 0x08 and cont. * of avi as 0x80, the spca500 uses 0x03 for both. Each frame * gets its own fat table with a sequence number at p[18]. */ if ((type == 0x80) || (type == 0x03 && (p[18] != 0x00))) { /* continuation of an avi */ lib->files[file_index - 1].fat_end = index; } else { /* its an image */ if (type == 0x00 || type == 0x01) { snprintf (buf, 13, "Image%03d.jpg", ++lib->num_images); lib->files[file_index].mime_type = SPCA50X_FILE_TYPE_IMAGE; } else if ((type == 0x08) || (type == 0x03)) { /* its the start of an avi */ snprintf (buf, 13, "Movie%03d.avi", ++lib->num_movies); lib->files[file_index].mime_type = SPCA50X_FILE_TYPE_AVI; } lib->files[file_index].fat = p; lib->files[file_index].fat_start = index; lib->files[file_index].fat_end = index; lib->files[file_index].name = strdup (buf); if (lib->bridge == BRIDGE_SPCA504) { lib->files[file_index].width = (p[8] & 0xFF) * 16; lib->files[file_index].height = (p[9] & 0xFF) * 16; } else if (lib->bridge == BRIDGE_SPCA500) { int w, h; if (p[20] == 2) { w = 320; h = 240; } else { w = 640; h = 480; } lib->files[file_index].width = w; lib->files[file_index].height = h; } lib->files[file_index].thumb = NULL; file_index++; } p += SPCA50X_FAT_PAGE_SIZE; index++; } return GP_OK; } static inline uint8_t * put_dword (uint8_t * ptr, uint32_t value) { ptr[0] = (value & 0xff); ptr[1] = (value & 0xff00) >> 8; ptr[2] = (value & 0xff0000) >> 16; ptr[3] = (value & 0xff000000) >> 24; return ptr + 4; }