Пример #1
0
uint16_t
ptp_usb_getresp (PTPParams* params, PTPContainer* resp)
{
	uint16_t 		ret;
	unsigned long		rlen;
	PTPUSBBulkContainer	usbresp;
	/*GPContext		*context = ((PTPData *)params->data)->context;*/

	gp_log (GP_LOG_DEBUG, "ptp2/ptp_usb_getresp", "reading response");
	PTP_CNT_INIT(usbresp);
	/* read response, it should never be longer than sizeof(usbresp) */
	ret = ptp_usb_getpacket(params, &usbresp, &rlen);

	if (ret!=PTP_RC_OK) {
		ret = PTP_ERROR_IO;
	} else
	if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) {
		ret = PTP_ERROR_RESP_EXPECTED;
	} else
	if (dtoh16(usbresp.code)!=resp->Code) {
		ret = dtoh16(usbresp.code);
	}
	if (ret!=PTP_RC_OK) {
		gp_log (GP_LOG_DEBUG, "ptp2/usb_getresp","request code 0x%04x getting resp error 0x%04x", resp->Code, ret);
		return ret;
	}
	/* build an appropriate PTPContainer */
	resp->Code=dtoh16(usbresp.code);
	resp->SessionID=params->session_id;
	resp->Transaction_ID=dtoh32(usbresp.trans_id);
	if (resp->Transaction_ID != params->transaction_id - 1) {
		if (MTP_ZEN_BROKEN_HEADER(params)) {
			gp_log (GP_LOG_DEBUG, "ptp2/ptp_usb_getresp", "Read broken PTP header (transid is %08x vs %08x), compensating.",
				resp->Transaction_ID, params->transaction_id - 1
			);
			resp->Transaction_ID=params->transaction_id-1;
		}
		/* else will be handled by ptp.c as error. */
	}
	resp->Nparam=(rlen-12)/4;
	resp->Param1=dtoh32(usbresp.payload.params.param1);
	resp->Param2=dtoh32(usbresp.payload.params.param2);
	resp->Param3=dtoh32(usbresp.payload.params.param3);
	resp->Param4=dtoh32(usbresp.payload.params.param4);
	resp->Param5=dtoh32(usbresp.payload.params.param5);
	return ret;
}
Пример #2
0
uint16_t
ptp_usb_getresp (PTPParams* params, PTPContainer* resp)
{
	uint16_t 		ret;
	uint32_t		rlen;
	PTPUSBBulkContainer	usbresp;
	/*GPContext		*context = ((PTPData *)params->data)->context;*/

	GP_LOG_D ("Reading PTP_OC 0x%0x (%s) response...", resp->Code, ptp_get_opcode_name(params, resp->Code));
	PTP_CNT_INIT(usbresp);
	/* read response, it should never be longer than sizeof(usbresp) */
	ret = ptp_usb_getpacket(params, &usbresp, &rlen);

	if (ret!=PTP_RC_OK) {
		ret = PTP_ERROR_IO;
	} else
	if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) {
		ret = PTP_ERROR_RESP_EXPECTED;
	} else
	if (dtoh16(usbresp.code)!=resp->Code) {
		ret = dtoh16(usbresp.code);
	}
	if (ret!=PTP_RC_OK) {
		GP_LOG_E ("PTP_OC 0x%04x receiving resp failed: %s (0x%04x)", resp->Code, ptp_strerror(ret, params->deviceinfo.VendorExtensionID), ret);
		return ret;
	}
	/* build an appropriate PTPContainer */
	resp->Code=dtoh16(usbresp.code);
	resp->SessionID=params->session_id;
	resp->Transaction_ID=dtoh32(usbresp.trans_id);
	if (resp->Transaction_ID != params->transaction_id - 1) {
		if (MTP_ZEN_BROKEN_HEADER(params)) {
			GP_LOG_D ("Read broken PTP header (transid is %08x vs %08x), compensating.",
				  resp->Transaction_ID, params->transaction_id - 1
			);
			resp->Transaction_ID=params->transaction_id-1;
		}
		/* else will be handled by ptp.c as error. */
	}
	resp->Nparam=(rlen-12)/4;
	resp->Param1=dtoh32(usbresp.payload.params.param1);
	resp->Param2=dtoh32(usbresp.payload.params.param2);
	resp->Param3=dtoh32(usbresp.payload.params.param3);
	resp->Param4=dtoh32(usbresp.payload.params.param4);
	resp->Param5=dtoh32(usbresp.payload.params.param5);
	return ret;
}
Пример #3
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;
}
Пример #4
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;
}