示例#1
0
int
camera_init (Camera *camera, GPContext *context) 
{
	char *curloc;
	/* First, set up all the function pointers */
	camera->functions->get_config	= camera_config_get;
	camera->functions->set_config	= camera_config_set;
	camera->functions->summary	= camera_summary;
	camera->functions->about	= camera_about;
	camera->functions->exit		= camera_exit;

	/* Now, tell the filesystem where to get lists, files and info */
	gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);

	gp_port_set_timeout (camera->port, TF_PROTOCOL_TIMEOUT);
	gp_port_usb_clear_halt (camera->port, GP_PORT_USB_ENDPOINT_IN);

	camera->pl = calloc (sizeof (CameraPrivateLibrary),1);
	if (!camera->pl) return GP_ERROR_NO_MEMORY;

#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
	curloc = nl_langinfo (CODESET);
	if (!curloc) curloc="UTF-8";
	cd_latin1_to_locale = iconv_open(curloc, "iso-8859-1");
	if (!cd_latin1_to_locale) return GP_ERROR_NO_MEMORY;
	cd_locale_to_latin1 = iconv_open("iso-8859-1", curloc);
	if (!cd_locale_to_latin1) return GP_ERROR_NO_MEMORY;
#endif

	do_cmd_ready (camera, context);
	return GP_OK;
}
示例#2
0
static uint16_t
ptp_usb_getpacket(PTPParams *params,
		PTPUSBBulkContainer *packet, unsigned long *rlen)
{
	int		tries = 0, result;
	Camera		*camera = ((PTPData *)params->data)->camera;

	gp_log (GP_LOG_DEBUG, "ptp2/ptp_usb_getpacket", "getting next ptp packet");
	/* read the header and potentially the first data */
	if (params->response_packet_size > 0) {
		gp_log (GP_LOG_DEBUG, "ptp2/ptp_usb_getpacket", "queuing buffered response packet");
		/* If there is a buffered packet, just use it. */
		memcpy(packet, params->response_packet, params->response_packet_size);
		*rlen = params->response_packet_size;
		free(params->response_packet);
		params->response_packet = NULL;
		params->response_packet_size = 0;
		/* Here this signifies a "virtual read" */
		return PTP_RC_OK;
	}
retry:
	/* A packet should come in a single read always. */
	result = gp_port_read (camera->port, (char*)packet, sizeof(*packet));
	/* This might be a left over zero-write of the device at the end of the previous transmission */
	if (result == 0)
		result = gp_port_read (camera->port, (char*)packet, sizeof(*packet));
	if (result > 0) {
		*rlen = result;
		return PTP_RC_OK;
	}
	if (result == 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)
			goto retry;
	}
	return PTP_ERROR_IO;
}
示例#3
0
文件: usb.c 项目: msmeissn/libgphoto2
uint16_t
ptp_usb_sendreq (PTPParams* params, PTPContainer* req)
{
	int res, towrite, do_retry = TRUE;
	PTPUSBBulkContainer usbreq;
	Camera *camera = ((PTPData *)params->data)->camera;

	GP_LOG_D ("Sending PTP_OC 0x%0x (%s) request...", req->Code, ptp_get_opcode_name(params, req->Code));

	/* build appropriate USB container */
	usbreq.length=htod32(PTP_USB_BULK_REQ_LEN-
		(sizeof(uint32_t)*(5-req->Nparam)));
	usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND);
	usbreq.code=htod16(req->Code);
	usbreq.trans_id=htod32(req->Transaction_ID);
	usbreq.payload.params.param1=htod32(req->Param1);
	usbreq.payload.params.param2=htod32(req->Param2);
	usbreq.payload.params.param3=htod32(req->Param3);
	usbreq.payload.params.param4=htod32(req->Param4);
	usbreq.payload.params.param5=htod32(req->Param5);
	/* send it to responder */
	towrite = PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam));
retry:
	res = gp_port_write (camera->port, (char*)&usbreq, towrite);
	if (res != towrite) {
		if (res < 0) {
			GP_LOG_E ("PTP_OC 0x%04x sending req failed: %s (%d)", req->Code, gp_port_result_as_string(res), res);
			if (res == GP_ERROR_IO_WRITE && do_retry) {
				GP_LOG_D ("Clearing halt on OUT EP and retrying once.");
				gp_port_usb_clear_halt (camera->port, GP_PORT_USB_ENDPOINT_OUT);
				do_retry = FALSE;
				goto retry;
			}
		} else
			GP_LOG_E ("PTP_OC 0x%04x sending req failed: wrote only %d of %d bytes", req->Code, res, towrite);
		return PTP_ERROR_IO;
	}
	return PTP_RC_OK;
}
示例#4
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);
			if (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;
}
示例#5
0
文件: usb.c 项目: msmeissn/libgphoto2
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;
}