⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ptp.c

📁 Media transfer protocol implementation on POSIX. Have detailed readme on how to move to windows
💻 C
📖 第 1 页 / 共 5 页
字号:
/* ptp.c * * Copyright (C) 2001-2004 Mariusz Woloszyn <emsi@ipartners.pl> * Copyright (C) 2003-2006 Marcus Meissner <marcus@jet.franken.de> * Copyright (C) 2006 Linus Walleij <triad@df.lth.se> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <config.h>#include "ptp.h"#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <string.h>#include <unistd.h>#ifdef ENABLE_NLS#  include <libintl.h>#  undef _#  define _(String) dgettext (PACKAGE, String)#  ifdef gettext_noop#    define N_(String) gettext_noop (String)#  else#    define N_(String) (String)#  endif#else#  define textdomain(String) (String)#  define gettext(String) (String)#  define dgettext(Domain,Message) (Message)#  define dcgettext(Domain,Message,Type) (Message)#  define bindtextdomain(Domain,Directory) (Domain)#  define _(String) (String)#  define N_(String) (String)#endif#define CHECK_PTP_RC(result)	{uint16_t r=(result); if (r!=PTP_RC_OK) return r;}#define PTP_CNT_INIT(cnt) {memset(&cnt,0,sizeof(cnt));}static voidptp_debug (PTPParams *params, const char *format, ...){          va_list args;        va_start (args, format);        if (params->debug_func!=NULL)                params->debug_func (params->data, format, args);        else	{                vfprintf (stderr, format, args);		fprintf (stderr,"\n");		fflush (stderr);	}        va_end (args);}  static voidptp_error (PTPParams *params, const char *format, ...){          va_list args;        va_start (args, format);        if (params->error_func!=NULL)                params->error_func (params->data, format, args);        else	{                vfprintf (stderr, format, args);		fprintf (stderr,"\n");		fflush (stderr);	}        va_end (args);}/* Pack / unpack functions */#include "ptp-pack.c"/* send / receive functions */uint16_tptp_usb_sendreq (PTPParams* params, PTPContainer* req){	uint16_t ret;	PTPUSBBulkContainer usbreq;	/* 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 */	ret=params->write_func((unsigned char *)&usbreq,		PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam)),		params->data);	if (ret!=PTP_RC_OK) {		ret = PTP_ERROR_IO;/*		ptp_error (params,			"PTP: request code 0x%04x sending req error 0x%04x",			req->Code,ret); */	}	return ret;}/* Used for file transactions */#define FILE_BUFFER_SIZE 0x10000uint16_tptp_usb_senddata (PTPParams* params, PTPContainer* ptp,		  unsigned char *data, unsigned int size,		  int from_fd){	uint16_t ret;	int wlen, datawlen;	size_t written;	PTPUSBBulkContainer usbdata;	/* 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 {		/* For all camera devices. */		datawlen = (size<PTP_USB_BULK_PAYLOAD_LEN)?size:PTP_USB_BULK_PAYLOAD_LEN;		wlen = PTP_USB_BULK_HDR_LEN + datawlen;		if (from_fd == -1) {			memcpy(usbdata.payload.data, data, datawlen);		} else {			written = read(from_fd, usbdata.payload.data, datawlen);			if (written != datawlen)				return PTP_ERROR_IO;		}	}	/* send first part of data */	ret = params->write_func((unsigned char *)&usbdata, wlen, params->data);	if (ret!=PTP_RC_OK) {		ret = PTP_ERROR_IO;/*		ptp_error (params,		"PTP: request code 0x%04x sending data error 0x%04x",			ptp->Code,ret);*/		return ret;	}	if (size <= datawlen) return ret;	/* if everything OK send the rest */	if (from_fd == -1) {		ret=params->write_func (data + datawlen, size - datawlen, params->data);	} else {		uint32_t bytes_to_transfer;		uint32_t bytes_left_to_transfer;		void *temp_buf;		written = 0;		bytes_left_to_transfer = size-datawlen;		temp_buf = malloc(FILE_BUFFER_SIZE);		if (temp_buf == NULL)			return PTP_ERROR_IO;		ret = PTP_RC_OK;		while(bytes_left_to_transfer > 0) {			if (bytes_left_to_transfer > FILE_BUFFER_SIZE) {				bytes_to_transfer = FILE_BUFFER_SIZE;			} else {				bytes_to_transfer = bytes_left_to_transfer;			}			written = read(from_fd, temp_buf, bytes_to_transfer);			if (written != bytes_to_transfer) {				ret = PTP_ERROR_IO;				break;			}			ret=params->write_func (temp_buf, bytes_to_transfer, params->data);			bytes_left_to_transfer -= bytes_to_transfer;		}		free(temp_buf);			}	if (ret!=PTP_RC_OK) {		ret = PTP_ERROR_IO;/*		ptp_error (params,		"PTP: request code 0x%04x sending data error 0x%04x",			ptp->Code,ret); */	}	return ret;}static uint16_t ptp_usb_getpacket(PTPParams *params,		PTPUSBBulkContainer *packet, unsigned int *rlen){	/* read the header and potentially the first data */	if (params->response_packet_size > 0) {		/* 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;	} else {		return params->read_func((unsigned char *)packet,					 sizeof(*packet), params->data, rlen);	}}uint16_tptp_usb_getdata (PTPParams* params, PTPContainer* ptp,                 unsigned char **data, unsigned int *readlen,                 int to_fd){	uint16_t ret;	PTPUSBBulkContainer usbdata;	PTP_CNT_INIT(usbdata);	if (to_fd == -1 &&  *data != NULL)		return PTP_ERROR_BADPARAM;	do {		unsigned int len, rlen;		ret = ptp_usb_getpacket(params, &usbdata, &rlen);		if (ret!=PTP_RC_OK) {			ret = PTP_ERROR_IO;			break;		} else		if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) {			ret = PTP_ERROR_DATA_EXPECTED;			break;		} else		if (dtoh16(usbdata.code)!=ptp->Code) {			ret = dtoh16(usbdata.code);			break;		}		if (usbdata.length == 0xffffffffU) {			/* This only happens for MTP_GetObjPropList */			uint32_t	tsize = PTP_USB_BULK_HS_MAX_PACKET_LEN;			unsigned char	*tdata = malloc(tsize);			uint32_t	curoff = 0;			while (1) {				ret=params->read_func(tdata+curoff,						PTP_USB_BULK_HS_MAX_PACKET_LEN, params->data, &rlen);				if (ret!=PTP_RC_OK) {					ret = PTP_ERROR_IO;					break;				}				if (rlen < PTP_USB_BULK_HS_MAX_PACKET_LEN) {					tsize += rlen;					break;				}				tsize += PTP_USB_BULK_HS_MAX_PACKET_LEN;				curoff+= PTP_USB_BULK_HS_MAX_PACKET_LEN;				tdata	= realloc(tdata, tsize);			}			if (to_fd == -1) {				*data = tdata;			} else {				write (to_fd, tdata, tsize);				free (tdata);			}			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);				memcpy(params->response_packet,				       (uint8_t *) &usbdata + packlen, surplen);				params->response_packet_size = surplen;			} else {				ptp_debug (params, "ptp2/ptp_usb_getdata: read %d 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;		if (to_fd == -1) {			/* Allocate memory for data. */			*data=calloc(len,1);			if (readlen)				*readlen = len;			/* Copy first part of data to 'data' */			memcpy(*data,usbdata.payload.data,rlen - PTP_USB_BULK_HDR_LEN);			/* Is that all of data? */			if (len+PTP_USB_BULK_HDR_LEN<=rlen) break;			/* If not read the rest of it. */			ret=params->read_func(((unsigned char *)(*data))+					      rlen - PTP_USB_BULK_HDR_LEN,					      len-(rlen - PTP_USB_BULK_HDR_LEN),					      params->data, &rlen);			if (ret!=PTP_RC_OK) {				ret = PTP_ERROR_IO;				break;			}		} else {			uint32_t bytes_to_write, written;			uint32_t bytes_left_to_transfer;			void *temp_buf;									if (readlen)				*readlen = len;			bytes_to_write = rlen - PTP_USB_BULK_HDR_LEN;			ret = write(to_fd, usbdata.payload.data, bytes_to_write);			if (ret != bytes_to_write) {				ret = PTP_ERROR_IO;				break;			}			if (len + PTP_USB_BULK_HDR_LEN <= rlen)				break;						temp_buf = malloc(FILE_BUFFER_SIZE);			if (temp_buf == NULL) {				ret = PTP_ERROR_IO;				break;			}			ret = PTP_RC_OK;							bytes_left_to_transfer = len - (rlen - PTP_USB_BULK_HDR_LEN);			while (bytes_left_to_transfer > 0) {				bytes_to_write = ((bytes_left_to_transfer > FILE_BUFFER_SIZE) ?						  FILE_BUFFER_SIZE : bytes_left_to_transfer);								ret = params->read_func(temp_buf,							bytes_to_write,							params->data, &rlen);				if (ret != PTP_RC_OK) {					ret = PTP_ERROR_IO;					break;				}				written = write(to_fd, temp_buf, bytes_to_write);				if (written != bytes_to_write) {					ret = PTP_ERROR_IO;					break;				} else {					ret = PTP_RC_OK;				}				bytes_left_to_transfer -= bytes_to_write;			}			free(temp_buf);			if (ret != PTP_RC_OK)				break;		}	} while (0);/*	if (ret!=PTP_RC_OK) {		ptp_error (params,		"PTP: request code 0x%04x getting data error 0x%04x",			ptp->Code, ret);	}*/	return ret;}uint16_tptp_usb_getresp (PTPParams* params, PTPContainer* resp){	uint16_t ret;	unsigned int rlen;	PTPUSBBulkContainer usbresp;	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) {/*		ptp_error (params,		"PTP: 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);	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;}/* major PTP functions *//* Transaction data phase description */#define PTP_DP_NODATA		0x0000	/* no data phase */#define PTP_DP_SENDDATA		0x0001	/* sending data */#define PTP_DP_GETDATA		0x0002	/* receiving data */#define PTP_DP_DATA_MASK	0x00ff	/* data phase mask *//** * ptp_transaction: * params:	PTPParams* * 		PTPContainer* ptp	- general ptp container * 		uint16_t flags		- lower 8 bits - data phase description * 		unsigned int sendlen	- senddata phase data length * 		char** data		- send or receive data buffer pointer * 		int* recvlen		- receive data length * * Performs PTP transaction. ptp is a PTPContainer with appropriate fields * filled in (i.e. operation code and parameters). It's up to caller to do * so. * The flags decide thether the transaction has a data phase and what is its * direction (send or receive).  * If transaction is sending data the sendlen should contain its length in * bytes, otherwise it's ignored. * The data should contain an address of a pointer to data going to be sent * or is filled with such a pointer address if data are received depending * od dataphase direction (send or received) or is beeing ignored (no * dataphase). * The memory for a pointer should be preserved by the caller, if data are * beeing retreived the appropriate amount of memory is beeing allocated * (the caller should handle that!). * * Return values: Some PTP_RC_* code. * Upon success PTPContainer* ptp contains PTP Response Phase container with * all fields filled in. **/static uint16_t_ptp_transaction (PTPParams* params, PTPContainer* ptp, 		  uint16_t flags, unsigned int sendlen, unsigned char** data,		  int fd, unsigned int *recvlen){	if ((params==NULL) || (ptp==NULL)) 		return PTP_ERROR_BADPARAM;	ptp->Transaction_ID=params->transaction_id++;	ptp->SessionID=params->session_id;	/* send request */	CHECK_PTP_RC(params->sendreq_func (params, ptp));	/* is there a dataphase? */	switch (flags&PTP_DP_DATA_MASK) {	case PTP_DP_SENDDATA:		CHECK_PTP_RC(params->senddata_func(params, ptp,			*data, sendlen, fd));		break;	case PTP_DP_GETDATA:		CHECK_PTP_RC(params->getdata_func(params, ptp,			(unsigned char**)data, recvlen, fd));		break;	case PTP_DP_NODATA:		break;	default:		return PTP_ERROR_BADPARAM;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -