示例#1
0
/**
 * Sends the PC client's status.
 * 
 * @param device a pointer to the device.
 * @param status the client's status
 * @return the PTP result code that the Vita returns.
 * @see VITA_HOST_STATUS
 */
uint16_t VitaMTP_SendHostStatus(LIBMTP_mtpdevice_t *device, uint32_t status){
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = PTP_OC_VITA_SendHostStatus;
    ptp.Nparam = 1;
    ptp.Param1 = status;
    return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, 0);
}
示例#2
0
/**
 * Tell the Vita that the current event is being processed and not 
 * to time out on us.
 * 
 * @param device a pointer to the device.
 * @param event_id the unique ID sent by the Vita with the event.
 */
uint16_t VitaMTP_KeepAlive(LIBMTP_mtpdevice_t *device, uint32_t event_id){
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = PTP_OC_VITA_KeepAlive;
    ptp.Nparam = 1;
    ptp.Param1 = event_id;
    
    return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, 0);
}
示例#3
0
/**
 * Sends a command with a data send phase and a event id
 * 
 * The Vita uses the PC as a slave. It sends an event asking the PC to 
 * send a command, and it complies, sending the command with the event_id 
 * as its first parameter. Most commands only has this paramater, so this 
 * function it called internally to make our lives easier.
 * @param device a pointer to the device.
 * @param event_id the unique ID sent by the Vita with the event.
 * @param code the command to send.
 * @param data the array of data to send.
 * @param len the length of "data".
 * @return the PTP result code that the Vita returns.
 * @see VitaMTP_GetData()
 */
uint16_t VitaMTP_SendData(LIBMTP_mtpdevice_t *device, uint32_t event_id, uint32_t code, unsigned char* data, unsigned int len){
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = code;
    ptp.Nparam = 1;
    ptp.Param1 = event_id;
    
    uint16_t ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, len, &data, 0);
    return ret;
}
示例#4
0
/**
 * Same as VitaMTP_ReportResult(), but also sends another integer
 * as a parameter.
 * 
 * @param device a pointer to the device.
 * @param event_id the unique ID sent by the Vita with the event.
 * @param result a PTP result code to send
 * @param param a parameter to send
 * @return the PTP result code that the Vita returns.
 * @see VitaMTP_ReportResult()
 */
uint16_t VitaMTP_ReportResultWithParam(LIBMTP_mtpdevice_t *device, uint32_t event_id, uint16_t result, uint32_t param){
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = PTP_OC_VITA_ReportResult;
    ptp.Nparam = 3;
    ptp.Param1 = event_id;
    ptp.Param2 = result;
    ptp.Param3 = param;
    return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, 0);
}
示例#5
0
/**
 * Sends the number of objects to list.
 * 
 * @param device a pointer to the device.
 * @param event_id the unique ID sent by the Vita with the event.
 * @param num the number of objects to list.
 * @return the PTP result code that the Vita returns.
 * @see VitaMTP_SendObjectMetadata()
 */
uint16_t VitaMTP_SendNumOfObject(LIBMTP_mtpdevice_t *device, uint32_t event_id, uint32_t num){
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = PTP_OC_VITA_SendNumOfObject;
    ptp.Nparam = 2;
    ptp.Param1 = event_id;
    ptp.Param2 = num;
    
    return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, 0);
}
示例#6
0
/**
 * Called during initialization to send information abouthe PC.
 * 
 * @param device a pointer to the device.
 * @param info a pointer to the initiator_info structure.
 *  You should get this with new_initiator_info()
 * @return the PTP result code that the Vita returns.
 * @see new_initiator_info()
 */
uint16_t VitaMTP_SendInitiatorInfo(LIBMTP_mtpdevice_t *device, initiator_info_t *info){
    char *data;
    int len = 0;
    if(initiator_info_to_xml(info, &data, &len) < 0)
        return PTP_RC_GeneralError;
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = PTP_OC_VITA_SendInitiatorInfo;
    ptp.Nparam = 0;
    uint16_t ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, len, (unsigned char**)&data, 0); // plus one for null terminator, which is required on the vita's side
    free(data);
    return ret;
}
示例#7
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;
}
示例#8
0
文件: usb.c 项目: msmeissn/libgphoto2
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;
}
示例#9
0
/**
 * Called during initialization to get Vita information.
 * 
 * @param device a pointer to the device.
 * @param info a pointer to the vita_info struct to fill
 * @return the PTP result code that the Vita returns.
 */
uint16_t VitaMTP_GetVitaInfo(LIBMTP_mtpdevice_t *device, vita_info_t *info){
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    int ret;
    unsigned char *data;
    unsigned int len;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = PTP_OC_VITA_GetVitaInfo;
    ptp.Nparam = 0;
    ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &len);
    if(ret != PTP_RC_OK || len == 0){
        return ret;
    }
    if(vita_info_from_xml(info, (char*)data+sizeof(uint32_t), len-sizeof(uint32_t)) != 0){ // strip header
        return PTP_RC_GeneralError;
    }
    free(data);
    return ret;
}
示例#10
0
/**
 * Gets a MTP properties list for an object
 * 
 * @param device a pointer to the device.
 * @param handle a object handle.
 * @param props a pointer to a MTPProperties array to be created.
 *  Dynamically allocated.
 * @param nrofprops number of elements in the props array.
 */
uint16_t VitaMTP_GetObjectPropList(LIBMTP_mtpdevice_t *device, uint32_t handle, MTPProperties** props, int* nrofprops){
    uint16_t ret;
    PTPParams *params = (PTPParams*)device->params;
    PTPContainer ptp;
    unsigned char* opldata = NULL;
    unsigned int oplsize;
    
    PTP_CNT_INIT(ptp);
    ptp.Code = PTP_OC_MTP_GetObjPropList;
    ptp.Param1 = handle;
    ptp.Param2 = 0x00000000;
    ptp.Param3 = 0x00000000;
    ptp.Param4 = 0x00000001;
    ptp.Param5 = 0x00000000;
    ptp.Nparam = 5;
    ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &opldata, &oplsize);  
    if(ret == PTP_RC_OK){
        *nrofprops = ptp_unpack_MTPProperties(params, opldata, props, oplsize);
    }
    if(opldata){
        free(opldata);
    }
    return ret;
}
示例#11
0
static inline uint16_t
ptp_usb_event (PTPParams* params, PTPContainer* event, int wait)
{
	int			result, timeout, fasttimeout;
	unsigned long		rlen;
	PTPUSBEventContainer	usbevent;
	Camera			*camera = ((PTPData *)params->data)->camera;

	if (params->deviceinfo.VendorExtensionID == PTP_VENDOR_CANON)
		fasttimeout = PTP2_FAST_TIMEOUT*2;
	else
		fasttimeout = PTP2_FAST_TIMEOUT;

	PTP_CNT_INIT(usbevent);

	if (event==NULL)
		return PTP_ERROR_BADPARAM;

	switch(wait) {
	case PTP_EVENT_CHECK:
		result = gp_port_check_int (camera->port, (char*)&usbevent, sizeof(usbevent));
		if (result <= 0) result = gp_port_check_int (camera->port, (char*)&usbevent, sizeof(usbevent));
		break;
	case PTP_EVENT_CHECK_FAST:
		gp_port_get_timeout (camera->port, &timeout);
		gp_port_set_timeout (camera->port, fasttimeout);
		result = gp_port_check_int (camera->port, (char*)&usbevent, sizeof(usbevent));
		if (result <= 0) result = gp_port_check_int (camera->port, (char*)&usbevent, sizeof(usbevent));
		gp_port_set_timeout (camera->port, timeout);
		break;
	default:
		return PTP_ERROR_BADPARAM;
	}
	if (result < 0) {
		gp_log (GP_LOG_DEBUG, "ptp2/usb_event", "reading event an error %d occurred", result);
		if (result == GP_ERROR_TIMEOUT)
			return PTP_ERROR_TIMEOUT;
		return PTP_ERROR_IO;
	}
	if (result == 0) {
		gp_log (GP_LOG_DEBUG, "ptp2/usb_event", "reading event an 0 read occurred, assuming timeout.");
		return PTP_ERROR_TIMEOUT;
	}
	rlen = result;
	if (rlen < 8) {
		gp_log (GP_LOG_ERROR, "ptp2/usb_event",
			"reading event an short read of %ld bytes occurred", rlen);
		return PTP_ERROR_IO;
	}

	/* Only do the additional reads for "events". Canon IXUS 2 likes to
	 * send unrelated data.
	 */
	if (	(dtoh16(usbevent.type) == PTP_USB_CONTAINER_EVENT) &&
		(dtoh32(usbevent.length) > rlen)
	) {
		gp_log (GP_LOG_DEBUG, "ptp2/usb_event","Canon incremental read (done: %ld, todo: %d)", rlen, dtoh32(usbevent.length));
		gp_port_get_timeout (camera->port, &timeout);
		gp_port_set_timeout (camera->port, PTP2_FAST_TIMEOUT);
		while (dtoh32(usbevent.length) > rlen) {
			result = gp_port_check_int (camera->port, ((char*)&usbevent)+rlen, sizeof(usbevent)-rlen);
			if (result <= 0)
				break;
			rlen += result;
		}
		gp_port_set_timeout (camera->port, timeout);
	}
	/* if we read anything over interrupt endpoint it must be an event */
	/* build an appropriate PTPContainer */
	event->Nparam  = (rlen-12)/4;
	event->Code   = dtoh16(usbevent.code);
	event->SessionID=params->session_id;
	event->Transaction_ID=dtoh32(usbevent.trans_id);
	event->Param1 = dtoh32(usbevent.param1);
	event->Param2 = dtoh32(usbevent.param2);
	event->Param3 = dtoh32(usbevent.param3);
	return PTP_RC_OK;
}
示例#12
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;
}
示例#13
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;
}