Beispiel #1
0
uint16_t
ptp_usb_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *handler)
{
	uint16_t ret;
	PTPUSBBulkContainer usbdata;
	unsigned char	*data;
	unsigned long	bytes_to_read, written, curread, oldsize;
	Camera		*camera = ((PTPData *)params->data)->camera;
	int usecontext, progressid = 0, tries = 0, res;
	GPContext *context = ((PTPData *)params->data)->context;

	gp_log (GP_LOG_DEBUG, "ptp2/ptp_usb_getdata", "reading data");
	PTP_CNT_INIT(usbdata);
	do {
		unsigned long len, rlen;

		ret = ptp_usb_getpacket(params, &usbdata, &rlen);
		if (ret!=PTP_RC_OK) {
			ret = PTP_ERROR_IO;
			break;
		}
		if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) {
			/* We might have got a response instead. On error for instance. */
			if (dtoh16(usbdata.type) == PTP_USB_CONTAINER_RESPONSE) {
				params->response_packet = malloc(dtoh32(usbdata.length));
				if (!params->response_packet) return PTP_RC_GeneralError;
				memcpy(params->response_packet,
				       (uint8_t *) &usbdata, dtoh32(usbdata.length));
				params->response_packet_size = dtoh32(usbdata.length);
				ret = PTP_RC_OK;
			} else {
				ret = PTP_ERROR_DATA_EXPECTED;
			}
			break;
		}
		if (dtoh16(usbdata.code)!=ptp->Code) {
			/* A creative Zen device breaks down here, by leaving out
			 * Code and Transaction ID */
			if (MTP_ZEN_BROKEN_HEADER(params)) {
				gp_log (GP_LOG_DEBUG, "ptp2/ptp_usb_getdata", "Read broken PTP header (Code is %04x vs %04x), compensating.",
					dtoh16(usbdata.code), ptp->Code
				);
				usbdata.code = dtoh16(ptp->Code);
				usbdata.trans_id = htod32(ptp->Transaction_ID);
			} else {
				gp_log (GP_LOG_ERROR, "ptp2/ptp_usb_getdata", "Read broken PTP header (Code is %04x vs %04x).",
					dtoh16(usbdata.code), ptp->Code
				);
				ret = PTP_ERROR_IO;
				break;
			}
		}
		if (usbdata.length == 0xffffffffU) {
			unsigned char	*data = malloc (PTP_USB_BULK_HS_MAX_PACKET_LEN_READ);
			if (!data) return PTP_RC_GeneralError;
			/* Copy first part of data to 'data' */
			handler->putfunc(
				params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data,
				&written
			);
			/* stuff data directly to passed data handler */
			while (1) {
				unsigned long written;
				int result = gp_port_read (camera->port, (char*)data, PTP_USB_BULK_HS_MAX_PACKET_LEN_READ);
				if (result < 0) {
					free (data);
					return PTP_ERROR_IO;
				}
				handler->putfunc (params, handler->priv, result, data, &written);
				if (result < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) 
					break;
			}
			free (data);
			return PTP_RC_OK;
		}
		if (rlen > dtoh32(usbdata.length)) {
			/*
			 * Buffer the surplus response packet if it is >=
			 * PTP_USB_BULK_HDR_LEN
			 * (i.e. it is probably an entire package)
			 * else discard it as erroneous surplus data.
			 * This will even work if more than 2 packets appear
			 * in the same transaction, they will just be handled
			 * iteratively.
			 *
			 * Marcus observed stray bytes on iRiver devices;
			 * these are still discarded.
			 */
			unsigned int packlen = dtoh32(usbdata.length);
			unsigned int surplen = rlen - packlen;

			if (surplen >= PTP_USB_BULK_HDR_LEN) {
				params->response_packet = malloc(surplen);
				if (!params->response_packet) return PTP_RC_GeneralError;
				memcpy(params->response_packet,
				       (uint8_t *) &usbdata + packlen, surplen);
				params->response_packet_size = surplen;
			} else {
				gp_log (GP_LOG_DEBUG, "ptp2/ptp_usb_getdata", "read %ld bytes too much, expect problems!", rlen - dtoh32(usbdata.length));
			}
			rlen = packlen;
		}

		/* For most PTP devices rlen is 512 == sizeof(usbdata)
		 * here. For MTP devices splitting header and data it might
		 * be 12.
		 */
		/* Evaluate full data length. */
		len=dtoh32(usbdata.length)-PTP_USB_BULK_HDR_LEN;

		/* autodetect split header/data MTP devices */
		if (dtoh32(usbdata.length) > 12 && (rlen==12))
			params->split_header_data = 1;

		/* Copy first part of data to 'data' */
		handler->putfunc(
			params, handler->priv, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data,
			&written
		);
		/* Is that all of data? */
		if (len+PTP_USB_BULK_HDR_LEN<=rlen) break;

		/* If not read the rest of it. */
retry:
		oldsize = 0;
		data = malloc(READLEN);
		if (!data) return PTP_RC_GeneralError;
		bytes_to_read = len - (rlen - PTP_USB_BULK_HDR_LEN);
		usecontext = (bytes_to_read > CONTEXT_BLOCK_SIZE);
		ret = PTP_RC_OK;
		if (usecontext)
			progressid = gp_context_progress_start (context, (bytes_to_read/CONTEXT_BLOCK_SIZE), _("Downloading..."));
		curread = 0; res = 0;
		while (bytes_to_read > 0) {
			unsigned long toread = bytes_to_read;

			/* read in large blobs.
			 * if smaller than large blob, read all but the last short packet
			 * depending on EP packetsize.
			 */
			if (toread > READLEN)
				toread = READLEN;
			else if (toread > params->maxpacketsize)
				toread = toread - (toread % params->maxpacketsize);
			res = gp_port_read (camera->port, (char*)data, toread);
			if (res <= 0) {
				ret = PTP_ERROR_IO;
				break;
			}
			ret = handler->putfunc (params, handler->priv,
				res, data, &written
			);
			if (ret != PTP_RC_OK)
				break;
			if (written != res) {
				ret = PTP_ERROR_IO;
				break;
			}
			bytes_to_read -= res;
			curread += res;
			if (usecontext && (oldsize/CONTEXT_BLOCK_SIZE < curread/CONTEXT_BLOCK_SIZE))
				gp_context_progress_update (context, progressid, curread/CONTEXT_BLOCK_SIZE);
			/* Only cancel transfers larger than 1MB. as
			 * canceling did not work on eos_get_viewfinder of 200kb */
			if ((rlen > 1024*1024) && gp_context_cancel(context) == GP_CONTEXT_FEEDBACK_CANCEL) {
				ret = PTP_ERROR_CANCEL;
				break;
			}
			oldsize = curread;
		}
		free (data);
		if (usecontext)
			gp_context_progress_stop (context, progressid);
		if (res == GP_ERROR_IO_READ) {
			gp_log (GP_LOG_DEBUG, "ptp2/usbread", "Clearing halt on IN EP and retrying once.");
			gp_port_usb_clear_halt (camera->port, GP_PORT_USB_ENDPOINT_IN);
			/* retrying only makes sense if we did not read anything yet */
			if ((tries++ < 1) && (curread == 0))
				goto retry;
		}

		if ((ret!=PTP_RC_OK) && (ret!=PTP_ERROR_CANCEL)) {
			ret = PTP_ERROR_IO;
			break;
		}
	} while (0);

	if ((ret!=PTP_RC_OK) && (ret!=PTP_ERROR_CANCEL)) {
		gp_log (GP_LOG_DEBUG, "ptp2/usb_getdata",
		"request code 0x%04x getting data error 0x%04x",
			ptp->Code, ret);
	}
	return ret;
}
int
gp_abilities_list_load_dir (CameraAbilitiesList *list, const char *dir,
			    GPContext *context)
{
	CameraLibraryIdFunc id;
	CameraLibraryAbilitiesFunc ab;
	CameraText text;
	int ret, x, old_count, new_count;
	unsigned int i, p;
	const char *filename;
	CameraList *flist;
	int count;
	lt_dlhandle lh;

	CHECK_NULL (list && dir);

	gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
		"Using ltdl to load camera libraries from '%s'...", dir);
	CHECK_RESULT (gp_list_new (&flist));
	ret = gp_list_reset (flist);
	if (ret < GP_OK) {
		gp_list_free (flist);
		return ret;
	}
	if (1) { /* a new block in which we can define a temporary variable */
		foreach_data_t foreach_data = { NULL, GP_OK };
		foreach_data.list = flist;
		lt_dlinit ();
		lt_dladdsearchdir (dir);
		ret = lt_dlforeachfile (dir, foreach_func, &foreach_data);
		lt_dlexit ();
		if (ret != 0) {
			gp_list_free (flist);
			gp_log (GP_LOG_ERROR, "gp-abilities-list", 
				"Internal error looking for camlibs (%d)", ret);
			gp_context_error (context,
					  _("Internal error looking for camlibs. "
					    "(path names too long?)"));
			return (foreach_data.result!=GP_OK)?foreach_data.result:GP_ERROR;
		}
	}
	count = gp_list_count (flist);
	if (count < GP_OK) {
		gp_list_free (flist);
		return ret;
	}
	gp_log (GP_LOG_DEBUG, "gp-abilities-list", "Found %i "
		"camera drivers.", count);
	lt_dlinit ();
	p = gp_context_progress_start (context, count,
		_("Loading camera drivers from '%s'..."), dir);
	for (i = 0; i < count; i++) {
		ret = gp_list_get_name (flist, i, &filename);
		if (ret < GP_OK) {
			gp_list_free (flist);
			return ret;
		}
		lh = lt_dlopenext (filename);
		if (!lh) {
			gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
				"Failed to load '%s': %s.", filename,
				lt_dlerror ());
			continue;
		}

		/* camera_id */
		id = lt_dlsym (lh, "camera_id");
		if (!id) {
			gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
				"Library '%s' does not seem to "
				"contain a camera_id function: %s",
				filename, lt_dlerror ());
			lt_dlclose (lh);
			continue;
		}

		/*
		 * Make sure the camera driver hasn't been
		 * loaded yet.
		 */
		if (id (&text) != GP_OK) {
			lt_dlclose (lh);
			continue;
		}
		if (gp_abilities_list_lookup_id (list, text.text) >= 0) {
			lt_dlclose (lh);
			continue;
		} 

		/* camera_abilities */
		ab = lt_dlsym (lh, "camera_abilities");
		if (!ab) {
			gp_log (GP_LOG_DEBUG, "gphoto2-abilities-list",
				"Library '%s' does not seem to "
				"contain a camera_abilities function: "
				"%s", filename, lt_dlerror ());
			lt_dlclose (lh);
			continue;
		}

		old_count = gp_abilities_list_count (list);
		if (old_count < 0) {
			lt_dlclose (lh);
			continue;
		}

		if (ab (list) != GP_OK) {
			lt_dlclose (lh);
			continue;
		}

		lt_dlclose (lh);

		new_count = gp_abilities_list_count (list);
		if (new_count < 0)
			continue;

		/* Copy in the core-specific information */
		for (x = old_count; x < new_count; x++) {
			strcpy (list->abilities[x].id, text.text);
			strcpy (list->abilities[x].library, filename);
		}

		gp_context_progress_update (context, p, i);
		if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
			lt_dlexit ();
			gp_list_free (flist);
			return (GP_ERROR_CANCEL); 
		}
	}
	gp_context_progress_stop (context, p);
	lt_dlexit ();
	gp_list_free (flist);

	return (GP_OK);
}
Beispiel #3
0
uint16_t
ptp_usb_senddata (PTPParams* params, PTPContainer* ptp,
		  uint64_t size, PTPDataHandler *handler
) {
	uint16_t ret = PTP_RC_OK;
	int res, wlen, datawlen;
	PTPUSBBulkContainer usbdata;
	unsigned long bytes_left_to_transfer, written;
	Camera *camera = ((PTPData *)params->data)->camera;
	unsigned char *bytes;
	int progressid = 0;
	int usecontext = (size > CONTEXT_BLOCK_SIZE);
	GPContext *context = ((PTPData *)params->data)->context;

	/* build appropriate USB container */
	usbdata.length	= htod32(PTP_USB_BULK_HDR_LEN+size);
	usbdata.type	= htod16(PTP_USB_CONTAINER_DATA);
	usbdata.code	= htod16(ptp->Code);
	usbdata.trans_id= htod32(ptp->Transaction_ID);

	if (params->split_header_data) {
		datawlen = 0;
		wlen = PTP_USB_BULK_HDR_LEN;
	} else {
		unsigned long gotlen;
		/* For all camera devices. */
		datawlen = (size<PTP_USB_BULK_PAYLOAD_LEN_WRITE)?size:PTP_USB_BULK_PAYLOAD_LEN_WRITE;
		wlen = PTP_USB_BULK_HDR_LEN + datawlen;
		ret = handler->getfunc(params, handler->priv, datawlen, usbdata.payload.data, &gotlen);
		if (ret != PTP_RC_OK)
			return ret;
		if (gotlen != datawlen)
			return PTP_RC_GeneralError;
	}
	res = gp_port_write (camera->port, (char*)&usbdata, wlen);
	if (res != wlen) {
		gp_log (GP_LOG_DEBUG, "ptp2/usb_senddata",
		"request code 0x%04x sending data error 0x%04x",
			ptp->Code,ret);
		return PTP_ERROR_IO;
	}
	if (size <= datawlen) { /* nothing more to do */
		written = wlen;
		goto finalize;
	}
	if (usecontext)
		progressid = gp_context_progress_start (context, (size/CONTEXT_BLOCK_SIZE), _("Uploading..."));
	bytes = malloc (4096);
	if (!bytes)
		return PTP_RC_GeneralError;
	/* if everything OK send the rest */
	bytes_left_to_transfer = size-datawlen;
	ret = PTP_RC_OK;
	written = 0;
	while(bytes_left_to_transfer > 0) {
		unsigned long readlen, toread, oldwritten = written;
		int res;

		toread = 4096;
		if (toread > bytes_left_to_transfer)
			toread = bytes_left_to_transfer;
		ret = handler->getfunc (params, handler->priv, toread, bytes, &readlen);
		if (ret != PTP_RC_OK)
			break;
		res = gp_port_write (camera->port, (char*)bytes, readlen);
		if (res < 0) {
			ret = PTP_ERROR_IO;
			break;
		}
		bytes_left_to_transfer -= res;
		written += res;
		if (usecontext && (oldwritten/CONTEXT_BLOCK_SIZE < written/CONTEXT_BLOCK_SIZE))
			gp_context_progress_update (context, progressid, written/CONTEXT_BLOCK_SIZE);
#if 0 /* Does not work this way... Hmm. */
		if (gp_context_cancel(context) == GP_CONTEXT_FEEDBACK_CANCEL) {
			ret = ptp_usb_control_cancel_request (params,ptp->Transaction_ID);
			if (ret == PTP_RC_OK)
				ret = PTP_ERROR_CANCEL;
			break;
		}
#endif
	}
	if (usecontext)
		gp_context_progress_stop (context, progressid);
	free (bytes);
finalize:
	if ((ret == PTP_RC_OK) && ((written % params->maxpacketsize) == 0))
		gp_port_write (camera->port, "x", 0);
	if ((ret!=PTP_RC_OK) && (ret!=PTP_ERROR_CANCEL))
		ret = PTP_ERROR_IO;
	return ret;
}
Beispiel #4
0
static int get_file_func (CameraFilesystem *fs, const char *folder,
			  const char *filename, CameraFileType type,
			  CameraFile *file, void *user_data, GPContext *context)
{
	Camera *camera = user_data;
	char *raw, *ppm;
	unsigned char gtable[256];
	char *ptr;
	int size = 0, n = 0;
	int width, height;
	struct jamcam_file *jc_file;

	GP_DEBUG ("* camera_file_get");
	GP_DEBUG ("*** folder: %s", folder);
	GP_DEBUG ("*** filename: %s",filename);
	GP_DEBUG ("*** type: %d", type);

	CHECK (n = gp_filesystem_number (camera->fs, folder,
					 filename, context));

	if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL)
		return (GP_ERROR_CANCEL);

	raw = malloc(640*480 * 3);
	ppm = malloc(640*480 * 3 + 200);
	
	switch (type) {
	case GP_FILE_TYPE_PREVIEW:

		CHECK_free (jamcam_request_thumbnail (camera, file, raw, &size, n, context));


		width = 80;
		height = 60;

		sprintf( ppm,
			"P6\n"
			"# CREATOR: gphoto2, jamcam library\n"
			"%d %d\n"
			"255\n", width, height );

		ptr = ppm + strlen( ppm );

		size = strlen( ppm ) + ( height * width * 3 );

		gp_bayer_decode(raw, width, height, ptr, BAYER_TILE_GBRG );
		gp_gamma_fill_table( gtable, 0.5 );
		gp_gamma_correct_single( gtable, ptr, height * width );

		CHECK_free (gp_file_set_mime_type (file, GP_MIME_PPM));
		CHECK_free (gp_file_append (file, ppm, size));
		break;

	case GP_FILE_TYPE_NORMAL:
		CHECK_free (jamcam_request_image (camera, file, raw, &size, n, context));

		jc_file = jamcam_file_info (camera, n);

		sprintf( ppm,
			"P6\n"
			"# CREATOR: gphoto2, jamcam library\n"
			"%d %d\n"
			"255\n", jc_file->width, jc_file->height );

		ptr = ppm + strlen( ppm );

		size = strlen( ppm ) + ( jc_file->width * jc_file->height * 3 );

		gp_bayer_decode( raw, jc_file->width, jc_file->height, ptr,
			BAYER_TILE_GBRG );
		gp_gamma_fill_table( gtable, 0.5 );
		gp_gamma_correct_single( gtable, ptr, jc_file->width * jc_file->height );

		CHECK_free (gp_file_set_mime_type (file, GP_MIME_PPM));
		CHECK_free (gp_file_append (file, ppm, size));
		break;

	case GP_FILE_TYPE_RAW:
		CHECK_free (jamcam_request_image (camera, file, raw, &size, n, context));
		CHECK_free (gp_file_set_mime_type (file, GP_MIME_RAW));
		CHECK_free (gp_file_append (file, raw, size));
		break;
	default:
		free(raw); free(ppm);
		return (GP_ERROR_NOT_SUPPORTED);
	}
	free(raw); free(ppm);
	return (GP_OK);
}
Beispiel #5
0
/* Download a raw Bayer image from the camera and return it in a malloced
buffer */
static uint8_t *
Dimera_Get_Full_Image (int picnum, long *size, int *width, int *height,
			Camera *camera, GPContext *context)
{
	static struct mesa_image_arg	ia;
	int32_t				r;
	uint8_t			*b, *rbuffer = NULL;
	int				hires, s, retry;
	unsigned int id;

	*size = 0;
	*width = 0;
	*height = 0;

	if ( picnum != RAM_IMAGE_NUM )
	{
		GP_DEBUG("Getting Image Info");
		if ( (r = mesa_read_image_info( camera->port, picnum, NULL )) < 0 )
		{
			ERROR("Can't get Image Info");
			gp_context_error (context, _("Problem getting image information"));
			return NULL;
		}
		if ( r )
		{
			hires = FALSE;
			*height = 240;
			*width = 320;
		} else {
			hires = TRUE;
			*height = 480;
			*width = 640;
		}

		GP_DEBUG("Loading Image");
		if ( mesa_load_image( camera->port, picnum ) != GP_OK )
		{
			ERROR("Image Load failed");
			gp_context_error (context, _("Problem reading image from flash"));
			return NULL;
		}

	} else {
			/* load the snapped image */
		hires = TRUE;
		*height = 480;
		*width = 640;
	}

	*size = *height * *width;	/* 8 bits per pixel in raw CCD format */

	GP_DEBUG("Downloading Image");

	rbuffer = (uint8_t *)malloc( *size );
	if ( rbuffer == NULL )
	{
		gp_context_error (context, _("Out of memory"));
		return NULL;
	}

	ia.start = 28;
	ia.send = 4;
	ia.skip = 0;
	ia.repeat = ( hires ? 160 : 80 );
	ia.row_cnt = 40;
	ia.inc1 = 1;
	ia.inc2 = 128;
	ia.inc3 = ia.inc4 = 0;

	/* due to reports of mesa_read_image not working for some cameras */
	/* this is changed to use mesa_read_row */
#if 0
	id = gp_context_progress_start (context, *height + 4,
					_("Downloading image..."));
	for ( ia.row = 4, b = rbuffer; ia.row < (height + 4) ;
			ia.row += ia.row_cnt, b += s )
	{
		GP_DEBUG("Downloading Image");
		for ( retry = 10;; )
		{

			s = mesa_read_image( camera->port, b, &ia );
			if( s > 0)
				break;

			if ( (s == GP_ERROR_TIMEOUT || s == GP_ERROR_CORRUPTED_DATA) && --retry > 0)
			{
				GP_DEBUG( "Dimera_Get_Full_Image: retrans"); 
				continue;
			}
			GP_DEBUG(
				"Dimera_Get_Full_Image: read error %d (retry %d)",s,retry);
				/* retry count exceeded, or other error */
			free( rbuffer );
			*size = 0;
			gp_context_error (context, _("Problem downloading image"));
			return NULL;
		}
		gp_context_progress_update (context, id, ia.row);
		if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL)
		{
			free( rbuffer );
			*size = 0;
			gp_context_error (context, _("User canceled download"));
			return NULL;
		}
	}
#else
	id = gp_context_progress_start (context, *height + 4,
					_("Downloading image..."));
	for ( ia.row = 4, b = rbuffer; ia.row < (*height + 4) ;
			ia.row++, b += s )
	{
		GP_DEBUG("Downloading Image");
		for ( retry = 10;; )
		{

			s = mesa_read_row( camera->port, b, &ia );
			if( s > 0)
				break;

			if ( (s == GP_ERROR_TIMEOUT || s == GP_ERROR_CORRUPTED_DATA) && --retry > 0)
			{
				GP_DEBUG("Dimera_Get_Full_Image: retrans"); 
				continue;
			}
			GP_DEBUG(
				"Dimera_Get_Full_Image: read error %d (retry %d)",s,retry);
				/* retry count exceeded, or other error */
			free( rbuffer );
			*size = 0;
			gp_context_error (context, _("Problem downloading image"));
			return NULL;
		}
		gp_context_progress_update (context, id, ia.row);
		if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL)
		{
			free( rbuffer );
			*size = 0;
			return NULL;
		}
	}
	gp_context_progress_stop (context, id);
#endif

	return (rbuffer);
}
Beispiel #6
0
static int
get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
	       CameraFileType type, CameraFile *file, void *user_data,
	       GPContext *context)
{
        char path[1024];
	int result = GP_OK;
	struct stat stbuf;
	int fd, id;
	unsigned int curread, toread;
	unsigned char *buf;
#ifdef HAVE_LIBEXIF
	ExifData *data;
	unsigned int buf_len;
#endif /* HAVE_LIBEXIF */
	Camera *camera = (Camera*)user_data;

	result = _get_path (camera->port, folder, filename, path, sizeof(path));
	gp_log (GP_LOG_DEBUG, "directory/get_file_func", "%s %s",folder,filename);
	if (result < GP_OK)
		return result;
	gp_log (GP_LOG_DEBUG, "directory/get_file_func", "->%s",path);
	

	switch (type) {
	case GP_FILE_TYPE_NORMAL:
#ifdef DEBUG
	case GP_FILE_TYPE_PREVIEW:
#endif
		fd = open (path,O_RDONLY);
		if (fd == -1)
			return GP_ERROR_IO_READ;
		break;
#ifdef HAVE_LIBEXIF
	case GP_FILE_TYPE_EXIF:
		data = exif_data_new_from_file (path);
		if (!data) {
			gp_context_error (context, _("Could not open '%s'."),
					  path);
			return (GP_ERROR);
		}
		exif_data_save_data (data, &buf, &buf_len);
		exif_data_unref (data);
		gp_file_set_data_and_size (file, buf, buf_len);
		return (GP_OK);
#endif /* HAVE_LIBEXIF */
	default:
		return (GP_ERROR_NOT_SUPPORTED);
	}

	if (-1 == fstat(fd,&stbuf)) {
		close (fd);
		return GP_ERROR_IO_READ;
	}
#define BLOCKSIZE 65536
	/* do it in 64kb blocks */
	buf = malloc(BLOCKSIZE);
	if (!buf) {
		close (fd);
		return GP_ERROR_NO_MEMORY;
	}

	curread = 0;
	id = gp_context_progress_start (context, (1.0*stbuf.st_size/BLOCKSIZE), _("Getting file..."));
	GP_DEBUG ("Progress id: %i", id);
	result = GP_OK;
	while (curread < stbuf.st_size) {
		int ret;

		toread = stbuf.st_size-curread;
		if (toread>BLOCKSIZE) toread = BLOCKSIZE;
		ret = read(fd,buf,toread);
		if (ret == -1) {
			result = GP_ERROR_IO_READ;
			break;
		}
		curread += ret;
		gp_file_append (file, buf, ret);
		gp_context_progress_update (context, id, (1.0*curread/BLOCKSIZE));
		gp_context_idle (context);
		if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
			result = GP_ERROR_CANCEL;
			break;
		}
#if 0
		/* We could take 2 seconds to download this image. everytime. */
		/* But actually this driver is used in production by some frontends,
		 * so do not delay at all
		 */
		usleep(2000000/(stbuf.st_size/BLOCKSIZE));
#endif
	}
	gp_context_progress_stop (context, id);
	free (buf);
	close (fd);
	return (GP_OK);
}
Beispiel #7
0
static int
get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
	       CameraFileType type, CameraFile *file, void *user_data,
	       GPContext *context)
{
	Camera *camera = user_data;
	int result;
	int havefirst = 0;
	unsigned char buffer[SDSC_BLOCKSIZE], first[SDSC_BLOCKSIZE];
	long int size, curread;
	unsigned int pid;

	if (type != GP_FILE_TYPE_NORMAL)
		return (GP_ERROR_NOT_SUPPORTED);

	/* Seek the header of our file */
	while (1) {
		CHECK_RESULT (SDSC_send (camera->port, SDSC_NEXT));
		CHECK_RESULT (SDSC_send (camera->port, SDSC_START));
		CHECK_RESULT (SDSC_receive (camera->port, buffer, SDSC_INFOSIZE));
		if (!strcmp(buffer,filename))
		    break;
		if (is_null(buffer)) { /* skipped to the end of the camera? */
		    /* Since we start at a random position, we wrap around. */
		    continue;
	        }
		/* We are at the first item again, so break. */
		if (havefirst && !strcmp(first,buffer))
			return GP_ERROR_BAD_PARAMETERS;
		if (!havefirst) {
			havefirst = 1;
			strcpy(first,buffer);
		}
	}
	/* The buffer header has
	 * filename (8.3 DOS format and \0)
	 * filesize (as ascii number) and \0
	 */
	/* Extract the size of the file */
	sscanf(buffer+12,"%ld",&size);
	/* Put the camera into image mode */
	CHECK_RESULT (SDSC_send (camera->port, SDSC_BINARY));
	CHECK_RESULT (SDSC_send (camera->port, SDSC_START));

	pid = gp_context_progress_start(context,size,_("Downloading image..."));

	curread = 0;
	/* Read data */
	while (1) {
		/* Read data and check for EOF */
		result = SDSC_receive (camera->port, buffer, SDSC_BLOCKSIZE);
		if (result == SDSC_ERROR_EOF)
			break;
		if (result < 0)
			return result;
		gp_file_append(file,buffer,SDSC_BLOCKSIZE);
		curread += SDSC_BLOCKSIZE;
	        gp_context_progress_update(context, pid, curread);
		if (gp_context_cancel(context) == GP_CONTEXT_FEEDBACK_CANCEL)
		    return GP_ERROR_CANCEL;
		CHECK_RESULT (SDSC_send (camera->port, SDSC_BINARY));
	}
	gp_context_progress_stop(context, pid);
	CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_JPEG));
	return (GP_OK);
}
Beispiel #8
0
/* This function reads all thumbnails at once and initializes the whole
 * camera filesystem. This can be done, because finding out how much 
 * pictures are on the camera is done by reading the whole preview picture
 * stream anyway.
 * And since the file infos are static mostly, why not just set them too at
 * the same time.
 */
int
jd11_index_reader(GPPort *port, CameraFilesystem *fs, GPContext *context) {
    int		i, id, count, xsize, curread=0, ret=0;
    unsigned char	*indexbuf;

    ret = jd11_select_index(port);
    if (ret != GP_OK)
	return ret;
    xsize = jd11_imgsize(port);
    if (!xsize) { /* shortcut, no reading needed */
	return GP_OK;
    }
    count = xsize/(64*48);
    xsize = count * (64*48);
    indexbuf = malloc(xsize);
    if (!indexbuf) return GP_ERROR_NO_MEMORY;
    id = gp_context_progress_start (context, xsize,
				    _("Downloading thumbnail..."));
    _send_cmd(port,0xfff1);
    while (curread < xsize) {
	    int readsize = xsize-curread;
	    if (readsize>200) readsize = 200;
	    ret=getpacket(port,indexbuf+curread,readsize);
	    if (ret==0)
		    break;
	    curread+=ret;
	    if (ret<200)
		    break;
	    gp_context_progress_update (context, id, curread);
	    if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
		/* What to do...Just free the stuff we allocated for now.*/
		free(indexbuf);
		return GP_ERROR_CANCEL;
	    }
	    _send_cmd(port,0xfff1);
    }
    gp_context_progress_stop (context, id);
    for (i=0;i<count;i++) {
	CameraFile	*file;
	char		fn[20];
	unsigned char *src;
	unsigned char thumb[64*48];
	int y;
	CameraFileInfo	info;
	
	ret = gp_file_new(&file);
	if (ret!=GP_OK) {
	    free(indexbuf);
	    return ret;
	}
	sprintf(fn,"image%02i.pgm",i);
	gp_file_set_mime_type(file, GP_MIME_PGM);
	gp_file_append(file, THUMBHEADER, strlen(THUMBHEADER));
	src = indexbuf+(i*64*48);
	for (y=0;y<48;y++) {
	    int x,off = 64*y;
	    for (x=0;x<64;x++)
		thumb[47*64-off+(63-x)] = src[off+x];
	}
	ret = gp_file_append(file,(char*)thumb,sizeof(thumb));
	if (ret != GP_OK) {
		gp_file_free (file);
		return ret;
	}
	ret = gp_filesystem_append(fs, "/", fn, context);
	if (ret != GP_OK) {
		/* should perhaps remove the entry again */
		gp_file_free (file);
		return ret;
	}
	ret = gp_filesystem_set_file_noop(fs, "/", fn, GP_FILE_TYPE_PREVIEW, file, context);
	if (ret != GP_OK) return ret;

	/* we also get the fs info for free, so just set it */
	info.file.fields = GP_FILE_INFO_TYPE |
			GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | 
			GP_FILE_INFO_SIZE;
	strcpy(info.file.type,GP_MIME_PNM);
	info.file.width		= 640;
	info.file.height	= 480;
	info.file.size		= 640*480*3+strlen(IMGHEADER);
	info.preview.fields = GP_FILE_INFO_TYPE |
			GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | 
			GP_FILE_INFO_SIZE;
	strcpy(info.preview.type,GP_MIME_PGM);
	info.preview.width	= 64;
	info.preview.height	= 48;
	info.preview.size	= 64*48+strlen(THUMBHEADER);
	ret = gp_filesystem_set_info_noop(fs, "/", fn, info, context);
    }
    free(indexbuf);
    return GP_OK;
}
Beispiel #9
0
static int
folder_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
		  void *data, GPContext *context)
{
	gp_system_dir dir;
	gp_system_dirent de;
	char buf[1024], f[1024];
	unsigned int id, n;
	struct stat st;
	Camera *camera = (Camera*)data;

	if (camera->port->type == GP_PORT_DISK) {
		char		*path;
		GPPortInfo	info;
		int		ret;

		ret = gp_port_get_info (camera->port, &info);
		if (ret < GP_OK)
			return ret;
		path = strchr (info.path,':');
		if (!path) path = info.path; else path++;

		snprintf (f, sizeof(f), "%s/%s/", path, folder);
		gp_log (GP_LOG_DEBUG, "directory/folder_list_func", "%s", f);
		/* UNIX / is empty, or we recurse through the whole fs */
		if (	(!strcmp(path, "") || !strcmp(path, "/")) &&
			!strcmp(folder,"/")
		)
			return GP_OK;
	} else {
		/* old style access */
		/* Make sure we have 1 delimiter */
		if (folder[strlen(folder)-1] != '/') {
			snprintf (f, sizeof(f), "%s%c", folder, '/');
		} else {
			strncpy (f, folder, sizeof(f));
		}
	}
	dir = gp_system_opendir ((char*) f);
	if (!dir)
		return GP_ERROR;
	/* Count the files */
	n = 0;
	while (gp_system_readdir (dir))
		n++;
	gp_system_closedir (dir);

	dir = gp_system_opendir (f);
	if (!dir)
		return GP_ERROR;
	id = gp_context_progress_start (context, n, _("Listing folders in '%s'..."), folder);
	n = 0;
	while ((de = gp_system_readdir (dir))) {
		const char * filename = NULL;

		/* Give some feedback */
		gp_context_progress_update (context, id, n + 1);
		gp_context_idle (context);
		if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
			gp_system_closedir (dir);
			return GP_ERROR_CANCEL;
		}
		filename = gp_system_filename (de);
		if (*filename != '.') {
			snprintf (buf, sizeof(buf), "%s%s", f, filename);
			
			/* lstat ... do not follow symlinks */
			if (lstat (buf, &st) != 0) {
				gp_context_error (context, _("Could not get information about '%s' (%m)."), buf);
				return GP_ERROR;
			}
			if (S_ISDIR (st.st_mode)) {
				gp_list_append(list,	filename,	NULL);
			}
		}
		n++;
	}
	gp_system_closedir (dir);
	gp_context_progress_stop (context, id);
	return (GP_OK);
}
Beispiel #10
0
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		index;
	int		size;
	int		i;
	int		s;
	char	buffer[112];
	int		bufIndex;
	unsigned int id;

	GP_DEBUG ("Get File %s", filename);

	/* index is the 0-based image number on the camera */
	index = gp_filesystem_number (camera->fs, folder, filename, context);
	if (index < 0)
		return (index);

	switch (type) {
	case GP_FILE_TYPE_NORMAL:
		size = l859_selectimage(camera, index);
		break;
	case GP_FILE_TYPE_PREVIEW:
		size = l859_selectimage_preview(camera, index);
	default:
		return (GP_ERROR_NOT_SUPPORTED);
	}
	if (size < 0)
		return (size);

	id = gp_context_progress_start (context, size,
		_("Downloading '%s'..."), filename);
	for (i = 0, s = 0; s < size; i++) {

		if (l859_sendcmd(camera, L859_CMD_ACK) != GP_OK)
			return GP_ERROR;
		if (l859_retrcmd(camera) == GP_ERROR)
			return GP_ERROR;

		for (bufIndex = 3; bufIndex < 115 && s < size; bufIndex++) {
			buffer[bufIndex - 3] = camera->pl->buf[bufIndex];
			s += 1;
		}
		GP_DEBUG ("Packet Size: %i Data Size: %i", bufIndex - 3, s);

		/* Append data to the file */
		gp_file_append (file, buffer, bufIndex - 3);

		/* Check for cancellation */
		gp_context_progress_update (context, id, s);
		if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
			l859_disconnect (camera);
			l859_connect    (camera);
			return (GP_ERROR_CANCEL);
		}
	}

	gp_file_set_mime_type (file, GP_MIME_JPEG); 
	GP_DEBUG ("Camera Get File Done");
	return (GP_OK);
}
Beispiel #11
0
static int
file_list_func (CameraFilesystem *fs, const char *folder,
		CameraList *list, void *data, GPContext *context)
{
	Camera *camera = data;
	unsigned int i, id, size, type;
	int filecount;
	CameraFile *file;
	CameraFileInfo info;
	unsigned char *buffer = NULL;
	int ret, n_img=0, n_avi=0, n_wav=0;
	char fn[100];

	CHECK (pccam300_get_filecount (camera->port, &filecount));

	id = gp_context_progress_start (context, filecount,
			_("Getting file list..."));
	
	for (i = 0; i < filecount; i++) {
		/* Get information */
		gp_file_new (&file);
	
		ret = pccam300_get_file (camera->port, context, i,
		                          &buffer, &size, &type);
		if (ret < GP_OK) {
			gp_file_free (file);
			return ret;
		}

		info.audio.fields = GP_FILE_INFO_NONE;
		info.preview.fields = GP_FILE_INFO_NONE;

		info.file.fields = GP_FILE_INFO_SIZE | GP_FILE_INFO_TYPE;
		info.file.size = size;

		switch (type) {
			case PCCAM300_MIME_JPEG:
				strcpy (info.file.type, GP_MIME_JPEG);
				sprintf (fn, "Image%03i.jpeg", n_img++);
				break;
			case PCCAM300_MIME_AVI:
				strcpy (info.file.type, GP_MIME_AVI);
				sprintf (fn, "Movie%03i.UNUSABLE", n_avi++);
				break;
			case PCCAM300_MIME_WAV:
				strcpy (info.file.type, GP_MIME_WAV);
				sprintf (fn, "Audio%03i.UNUSABLE", n_wav++);
				break;
			default:
				break;
		}

		if (file)
			gp_file_set_data_and_size (file, (char *)buffer, size);
		else
			free (buffer);
		
		/*
		 * Append directly to the filesystem instead of to the list,
		 * because we have additional information. 
		 * */
		gp_filesystem_append (camera->fs, folder, fn, context);
		gp_filesystem_set_info_noop (camera->fs, folder, fn, info, context);
		gp_filesystem_set_file_noop (camera->fs, folder, fn, GP_FILE_TYPE_NORMAL,
					file, context);
		gp_file_unref (file);

		gp_context_idle (context);
		gp_context_progress_update (context, id, i + 1);
		if (gp_context_cancel(context) == GP_CONTEXT_FEEDBACK_CANCEL)
			return (GP_ERROR_CANCEL);
	}
	gp_context_progress_stop (context, id);
	return GP_OK;
}
Beispiel #12
0
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 result = GP_ERROR_IO;
	enum {
		START,
		DATA,
		ABORT
	} state;
	int r, pid = 0, update = 0;
	uint64_t byteCount = 0;
	struct utimbuf mod_utime_buf = { 0, 0 };
	char *path;
	struct tf_packet reply;

	if (type != GP_FILE_TYPE_NORMAL)
		return GP_ERROR_NOT_SUPPORTED;

	do_cmd_turbo (camera, "ON", context);

	path = get_path(camera, folder, filename);
	r = send_cmd_hdd_file_send(camera, GET, path, context);
	free (path);
	if(r < 0)
		goto out;

	state = START;
	while(0 < (r = get_tf_packet(camera, &reply, context)))
	{
		update = (update + 1) % 4;
		switch (get_u32(&reply.cmd)) {
		case DATA_HDD_FILE_START:
			if(state == START) {
				struct typefile *tf = (struct typefile *) reply.data;

				byteCount = get_u64(&tf->size);
				pid = gp_context_progress_start (context, byteCount, _("Downloading %s..."), filename);
				mod_utime_buf.actime = mod_utime_buf.modtime =
				tfdt_to_time(&tf->stamp);

				send_success(camera,context);
				state = DATA;
			} else {
				gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unexpected DATA_HDD_FILE_START packet in state %d\n", state);
				send_cancel(camera,context);
				state = ABORT;
			}
			break;

		case DATA_HDD_FILE_DATA:
			if(state == DATA) {
				uint64_t offset = get_u64(reply.data);
				uint16_t dataLen = get_u16(&reply.length) - (PACKET_HEAD_SIZE + 8);
				int w;

				if (!update) { /* avoid doing it too often */
					gp_context_progress_update (context, pid, offset + dataLen);
					if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
						send_cancel(camera,context);
						state = ABORT;
					}
				}

				if(r < get_u16(&reply.length)) {
					gp_log (GP_LOG_ERROR, "topfield", "ERROR: Short packet %d instead of %d\n", r, get_u16(&reply.length));
					/* TODO: Fetch the rest of the packet */
				}

				w = gp_file_append (file, (char*)&reply.data[8], dataLen);

				if(w < GP_OK) {
					/* Can't write data - abort transfer */
					gp_log (GP_LOG_ERROR, "topfield", "ERROR: Can not write data: %d\n", w);
					send_cancel(camera,context);
					state = ABORT;
				}
			} else {
				gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unexpected DATA_HDD_FILE_DATA packet in state %d\n", state);
				send_cancel(camera,context);
				state = ABORT;
			}
			break;

		case DATA_HDD_FILE_END:
			send_success(camera,context);
			result = GP_OK;
			goto out;
			break;

		case FAIL:
			gp_log (GP_LOG_ERROR, "topfield", "ERROR: Device reports %s\n", decode_error(&reply));
			send_cancel(camera,context);
			state = ABORT;
			break;

		case SUCCESS:
			goto out;
			break;

		default:
			gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unhandled packet (cmd 0x%x)\n", get_u32(&reply.cmd));
			break;
		}
	}
	if (pid) gp_context_progress_stop (context, pid);
out:
	do_cmd_turbo (camera, "OFF", context);
	return result;
}
Beispiel #13
0
static int 
l_receive (GPPort *p, GPContext *context,
	   unsigned char **rb, unsigned int *rbs,
	   unsigned int timeout)
{
	unsigned char c, d, progress = 0;
	int error_flag;
	unsigned int i, j, rbs_internal, id = 0;
	unsigned char checksum;
	int result;
	KCommand command;

	CHECK_NULL (p && rb && rbs);

	for (i = 0; ; ) {
		CHECK (gp_port_set_timeout (p, timeout));
		CHECK (gp_port_read (p, (char *)&c, 1));
		CHECK (gp_port_set_timeout (p, DEFAULT_TIMEOUT));
		switch (c) {
		case ENQ:

			/* ENQ received. We can proceed. */
			break;

		case ACK:

			/* ACK received. We'll try again at most ten times. */
			if (i == 9) {

				/*
				 * The camera hangs! Although it could be
				 * that the camera accepts one of the
				 * commands
				 *  - KONICA_CANCEL,
				 *  - KONICA_GET_IO_CAPABILITY, and
				 *  - KONICA_SET_IO_CAPABILITY,
				 * we can not get the camera back to working
				 * correctly.
				 */
				return (GP_ERROR_CORRUPTED_DATA);

			}
			i++;
			break;
		default:
			/*
			 * We'll dump this data until we get ENQ (then, we'll
			 * proceed) or nothing any more (then, we'll report
			 * error).
			 */
			for (;;) {
				CHECK (gp_port_read (p, (char *)&c, 1));
				if (c == ENQ)
					break;
			}
			break;
		}
		if (c == ENQ)
			break;
	}

	/* Start progress */
	if (*rbs > 1000) {
		id = gp_context_progress_start (context, *rbs,
						_("Downloading..."));
		progress = 1;
	}

	/* Write ACK. */
	CHECK (gp_port_write (p, "\6", 1));
	for (*rbs = 0; ; ) {
		for (j = 0; ; j++) {
			CHECK (gp_port_read (p, (char *)&c, 1));
			switch (c) {
			case STX:

				/* STX received. We can proceed. */
				break;

			default:

				/* We'll dump this data and try again. */
				continue;

			}

			/*
			 * Read 2 bytes for size (low order byte, high order
			 * byte) plus ESC quotes.
			 */
			CHECK (l_esc_read (p, &c));
			checksum = c;
			CHECK (l_esc_read (p, &d));
			checksum += d;
			rbs_internal = (d << 8) | c;
			if (*rbs == 0)
				*rb = malloc (rbs_internal * sizeof (char));
			else
				*rb = realloc (*rb,
					sizeof (char) * (*rbs + rbs_internal));

			/* Read 'rbs_internal' bytes data plus ESC quotes. */
			error_flag = 0;
{
unsigned int read = 0, r = 0;
while (read < rbs_internal) {

	/*
	 * Read the specified amount of bytes. We will probably read more
	 * because some bytes will be quoted.
	 */
	GP_DEBUG ("Reading %i bytes (%i of %i already read)...", 
		  rbs_internal - read, read, rbs_internal);
	result = gp_port_read (p, (char *)&((*rb)[*rbs + read]),
			       rbs_internal - read);
	if (result < 0) {
		error_flag = 1;
		break;
	}
	r = rbs_internal - read;

	/* Unescape the data we just read */
	for (i = read; i < read + r; i++) {
		unsigned char *c = &(*rb)[*rbs + i];

		 /* The HP PhotoSmart does not escape every special code, only
		  * some and it gets confused if we do this checks. By relaxing
		  * these, it now downloads images etc.
		  */
#ifndef LESSER_ESCAPES
	        if ((*c == STX) || (*c == ETX) || (*c == ENQ ) ||
		    (*c == ACK) || (*c == XOFF) || (*c == XON) ||
		    (*c == NACK) || (*c == ETB)) {
#else /* LESSER_ESCAPES */
	        if ((*c == STX) ||  (*c == XOFF) || (*c == XON)) {
#endif /* LESSER_ESCAPES */
			GP_DEBUG ("Wrong ESC masking!");
			error_flag = 1;
			break;
		} else if (*c == ESC) {
			if (i == read + r - 1) {
				/* ESC is last char of packet */
				CHECK (gp_port_read (p, (char *)c, 1));
			} else {
				memmove (c, c + 1, read + r - i - 1);
				r--;
			}
			*c = ~*c & 0xff;
			if ((*c != STX ) && (*c != ETX ) && (*c != ENQ) &&
			    (*c != ACK ) && (*c != XOFF) && (*c != XON) &&
			    (*c != NACK) && (*c != ETB ) && (*c != ESC)) {
				GP_DEBUG ("Wrong ESC masking!");
				error_flag = 1;
				break;
			}
		}
		checksum += (*rb)[*rbs + i];
	}
	if (error_flag)
		break;
	read += r;
}}
			if (!error_flag) {
				CHECK (gp_port_read (p, (char *)&d, 1));
				switch (d) {
				case ETX:

					/*
					 * ETX received. This is the last
					 * packet.
					 */
					GP_DEBUG ("Last packet.");
					break;

				case ETB:

					/*
					 * ETB received. There are more
					 * packets to come.
					 */
					GP_DEBUG ("More packets coming.");
					break;

				default:

					/*
					 * We get more bytes than expected.
					 * Nothing serious, as we will simply
					 * dump all bytes until we receive
					 * ETX or ETB. Later, we'll read the
					 * checksum with ESC quotes and
					 * reject the packet.
					 */
					while ((d != ETX) && (d != ETB)) {
						CHECK (gp_port_read (p,
								     (char *)&d, 1));
					}
					error_flag = 1;
					break;
				}
			}
			checksum += d;

			/* Read 1 byte for checksum plus ESC quotes. */
			CHECK (l_esc_read (p, &c));
			if ((c == checksum) && (!error_flag)) {
				*rbs += rbs_internal;

				/* Write ACK. */
				CHECK (gp_port_write (p, "\6", 1));
				break;

			} else {

				/*
				 * Checksum wrong or transmission error. The
				 * camera will send us the data at the most
				 * three times.
				 */
				GP_DEBUG ("Checksum wrong: expected %i, "
					  "got %i.", c, checksum);
				if (j == 2)
					return (GP_ERROR_CORRUPTED_DATA);

				/* Write NACK. */
				c = NACK;
				CHECK (gp_port_write (p, (char *)&c, 1));
				continue;
			}
		}
		CHECK (gp_port_read (p, (char *)&c, 1));
		switch (c) {
			case EOT:

				/* EOT received. We can proceed. */
				break;

			default:

				/* Should not happen. */
				return (GP_ERROR_CORRUPTED_DATA);
		}
		/*
		 * Depending on d, we will either continue to receive data or
		 * stop.
		 * 
		 *  - ETX:  We are all done.
		 *  - ETB:  We expect more data.
		 *  - else: Should not happen.
		 */
		switch (d) {
		case ETX:

			/* We are all done. */
			if (progress)
				gp_context_progress_stop (context, id);
			return (GP_OK);

		case ETB:

			/* We expect more data. Read ENQ. */
			CHECK (gp_port_read (p, (char *)&c, 1));
			switch (c) {
			case ENQ:

				/* ENQ received. We can proceed. */
				break;

			default:

				/* Should not happen. */
				return (GP_ERROR_CORRUPTED_DATA);
			}

			if (gp_context_cancel (context) ==
						GP_CONTEXT_FEEDBACK_CANCEL) {
				GP_DEBUG ("Trying to cancel operation...");
				CHECK (k_cancel (p, context, &command));
				GP_DEBUG ("Operation 0x%x cancelled.",
					  command);
				return (GP_ERROR_CANCEL);
			}

			/* Write ACK. */
			CHECK (gp_port_write (p, "\6", 1));
			break;

		default:

			/* Should not happen. */
			return (GP_ERROR_CORRUPTED_DATA);
		}
		if (progress)
			gp_context_progress_update (context, id, *rbs);
	}
}

int 
l_send_receive (
	GPPort *p, GPContext *c,
	unsigned char *send_buffer, unsigned int send_buffer_size, 
	unsigned char **receive_buffer, unsigned int *receive_buffer_size,
	unsigned int timeout,
	unsigned char **image_buffer, unsigned int *image_buffer_size)
{
	if (!timeout)
		timeout = DEFAULT_TIMEOUT;

	/* Send data. */
	CHECK (l_send (p, c, send_buffer, send_buffer_size));

        /* Receive data. */
	if (image_buffer_size)
		*receive_buffer_size = *image_buffer_size;
	CHECK (l_receive (p, c, receive_buffer, receive_buffer_size,
			  timeout));

	/* Check if we've received the control data. */
	if ((*receive_buffer_size > 1) &&
	    (((*receive_buffer)[0] == send_buffer[0]) &&
	     ((*receive_buffer)[1] == send_buffer[1])))
	    return (GP_OK);

	/* We didn't receive control data yet. */
	*image_buffer = *receive_buffer; 
	*image_buffer_size = *receive_buffer_size;
	*receive_buffer = NULL;
	
	/* Receive control data. */
	CHECK (l_receive (p, c, receive_buffer, receive_buffer_size,
			  DEFAULT_TIMEOUT));

	/* Sanity check: Did we receive the right control data? */
	if (((*receive_buffer)[0] != send_buffer[0]) ||
	    ((*receive_buffer)[1] != send_buffer[1]))
		return (GP_ERROR_CORRUPTED_DATA);
	
	return (GP_OK);
}
Beispiel #14
0
uint16_t
ptp_usb_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *handler)
{
	uint16_t ret;
	PTPUSBBulkContainer usbdata;
	unsigned char	*data = NULL;
	uint32_t	bytes_to_read, bytes_read;
	Camera		*camera = ((PTPData *)params->data)->camera;
	int		report_progress, progress_id = 0, do_retry = TRUE, res = GP_OK;
	GPContext *context = ((PTPData *)params->data)->context;

	GP_LOG_D ("Reading PTP_OC 0x%0x (%s) data...", ptp->Code, ptp_get_opcode_name(params, ptp->Code));
	PTP_CNT_INIT(usbdata);

	ret = ptp_usb_getpacket (params, &usbdata, &bytes_read);
	if (ret != PTP_RC_OK)
		goto exit;
	if (dtoh16(usbdata.type) != PTP_USB_CONTAINER_DATA) {
		/* We might have got a response instead. On error for instance. */
		/* TODO: check if bytes_read == usbdata.length */
		if (dtoh16(usbdata.type) == PTP_USB_CONTAINER_RESPONSE) {
			params->response_packet = malloc(dtoh32(usbdata.length));
			if (!params->response_packet) return PTP_RC_GeneralError;
			memcpy(params->response_packet, (uint8_t *) &usbdata, dtoh32(usbdata.length));
			params->response_packet_size = dtoh32(usbdata.length);
			ret = PTP_RC_OK;
		} else {
			ret = PTP_ERROR_DATA_EXPECTED;
		}
		goto exit;
	}
	if (dtoh16(usbdata.code)!=ptp->Code) {
		/* A creative Zen device breaks down here, by leaving out
			 * Code and Transaction ID */
		if (MTP_ZEN_BROKEN_HEADER(params)) {
			GP_LOG_D ("Read broken PTP header (Code is %04x vs %04x), compensating.",
				  dtoh16(usbdata.code), ptp->Code);
			usbdata.code = dtoh16(ptp->Code);
			usbdata.trans_id = htod32(ptp->Transaction_ID);
		} else {
			GP_LOG_E ("Read broken PTP header (Code is %04x vs %04x).",
				  dtoh16(usbdata.code), ptp->Code );
			ret = PTP_ERROR_IO;
			goto exit;
		}
	}
	if (bytes_read > dtoh32(usbdata.length)) {
		/*
		 * Buffer the surplus response packet if it is >=
		 * PTP_USB_BULK_HDR_LEN
		 * (i.e. it is probably an entire package)
		 * else discard it as erroneous surplus data.
		 * This will even work if more than 2 packets appear
		 * in the same transaction, they will just be handled
		 * iteratively.
		 *
		 * Marcus observed stray bytes on iRiver devices;
		 * these are still discarded.
		 */
		uint32_t surplen = bytes_read - dtoh32(usbdata.length);

		if (surplen >= PTP_USB_BULK_HDR_LEN) {
			params->response_packet = malloc(surplen);
			if (!params->response_packet) return PTP_RC_GeneralError;
			memcpy(params->response_packet, (uint8_t *) &usbdata + dtoh32(usbdata.length), surplen);
			params->response_packet_size = surplen;
		} else {
			GP_LOG_D ("Read %ld bytes too much, expect problems!",
				  (long)(bytes_read - dtoh32(usbdata.length)));
		}
		bytes_read = dtoh32(usbdata.length);
	}

	/* For most PTP devices rlen is 512 == sizeof(usbdata)
	 * here. For MTP devices splitting header and data it might
	 * be PTP_USB_BULK_HDR_LEN (12).
	 */
	/* autodetect split header/data MTP devices */
	if (dtoh32(usbdata.length) > PTP_USB_BULK_HDR_LEN && (bytes_read==PTP_USB_BULK_HDR_LEN))
		params->split_header_data = 1;

	/* Copy the payload bytes we already read (with the first usb packet) */
	ret = handler->putfunc (params, handler->priv, bytes_read - PTP_USB_BULK_HDR_LEN, usbdata.payload.data);
	if (ret != PTP_RC_OK)
		goto exit;

	/* Check if we are done already... */
	if (bytes_read >= dtoh32(usbdata.length))
		goto exit;

	/* If not read the rest of it. */
	/* Make bytes_to_read contain the number of remaining payload-bytes to read. */
	bytes_to_read = dtoh32(usbdata.length) - bytes_read;
	/* Make bytes_read contain the number of payload-bytes already read. */
	bytes_read -= PTP_USB_BULK_HDR_LEN;

	data = malloc(READLEN);
	if (!data) return PTP_RC_GeneralError;

	report_progress = (bytes_to_read > 2*CONTEXT_BLOCK_SIZE) && (dtoh32(usbdata.length) != 0xffffffffU);
	if (report_progress)
		progress_id = gp_context_progress_start (context, (bytes_to_read/CONTEXT_BLOCK_SIZE), _("Downloading..."));
	while (bytes_to_read > 0) {
		unsigned long chunk_to_read = bytes_to_read;

		/* if in read-until-short-packet mode, read one packet at a time */
		/* else read in large blobs */
		/* else read all but the last short packet depending on EP packetsize. */
		if (dtoh32(usbdata.length) == 0xffffffffU)
			chunk_to_read = PTP_USB_BULK_HS_MAX_PACKET_LEN_READ;
		else if (chunk_to_read > READLEN)
			chunk_to_read = READLEN;
		else if (chunk_to_read > params->maxpacketsize)
			chunk_to_read = chunk_to_read - (chunk_to_read % params->maxpacketsize);
		res = gp_port_read (camera->port, (char*)data, chunk_to_read);
		if (res == GP_ERROR_IO_READ && do_retry) {
			GP_LOG_D ("Clearing halt on IN EP and retrying once.");
			gp_port_usb_clear_halt (camera->port, GP_PORT_USB_ENDPOINT_IN);
			/* retrying only once and only if we did not read anything yet */
			do_retry = FALSE;
			continue;
		} else if (res <= 0) {
			ret = PTP_ERROR_IO;
			break;
		} else
			do_retry = FALSE; /* once we have succesfully read any data, don't try again */
		ret = handler->putfunc (params, handler->priv, res, data);
		if (ret != PTP_RC_OK)
			break;
		if (dtoh32(usbdata.length) == 0xffffffffU) {
			/* once we have read a short packet, we are done. */
			if (res < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ)
				bytes_to_read = 0;
		} else
			bytes_to_read -= res;
		bytes_read += res;
		if (report_progress && ((bytes_read-res)/CONTEXT_BLOCK_SIZE < bytes_read/CONTEXT_BLOCK_SIZE))
			gp_context_progress_update (context, progress_id, bytes_read/CONTEXT_BLOCK_SIZE);
		/* Only cancel transfers larger than 1MB. as
		 * canceling did not work on eos_get_viewfinder of 200kb */
		if ((bytes_read > 1024*1024) && gp_context_cancel(context) == GP_CONTEXT_FEEDBACK_CANCEL) {
			ret = PTP_ERROR_CANCEL;
			break;
		}
	}
	if (report_progress)
		gp_context_progress_stop (context, progress_id);

exit:
	free (data);

	if ((ret!=PTP_RC_OK) && (ret!=PTP_ERROR_CANCEL)) {
		GP_LOG_E ("PTP_OC 0x%04x receiving data failed: %s (0x%04x)", ptp->Code, ptp_strerror(ret, params->deviceinfo.VendorExtensionID), ret);
		return PTP_ERROR_IO;
	}
	return ret;
}