1 /*
2  * multican 0.0.5, USB remote control tool for Canon cameras.
3  *
4  * Copyright (C) 2006 Jindrich Novy (jnovy@users.sourceforge.net)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #define _GNU_SOURCE
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/endian.h>
26 #include <usb.h>
27 
28 #include "usbio.h"
29 
30 unsigned usb_sequence = 0;
31 int tolerate_error = 0, retries = 5000;
32 unsigned char usb_packet[0x1400];
33 
usb_hexdump(char * bytes,int size)34 void usb_hexdump( char *bytes, int size ) {
35 	int n, i;
36 
37 	fputs("         0  1  2  3  4  5  6  7| 8  9  A  B  C  D  E  F 01234567|89ABCDEF\n", stderr);
38 	for ( n=0; n<size; n+=i ) {
39 		fprintf(stderr, "0x%04X: ", n);
40 		for ( i=0; n+i<size && i<0x10; i++ ) {
41 			unsigned char b = bytes[n+i];
42 			fprintf(stderr, "%02X%c", b, i!=7?' ':'|');
43 		}
44 		for ( ; i<0x10; i++ )
45 			fputs("   ", stderr);
46 		for ( i=0; n+i<size && i<0x10; i++ ) {
47 			unsigned b = bytes[n+i];
48 			if ( i==8 )
49 				putc('|', stderr);
50 			putc(b>=0x20 && b<0x7f ? b : '.', stderr);
51 		}
52 		putc('\n', stderr);
53 	}
54 	putc('\n', stderr);
55 }
56 
get_le32(char * b)57 unsigned get_le32( char *b ) {
58 	unsigned char A, B, C, D;
59 #if __BYTE_ORDER == __LITTLE_ENDIAN
60 	A = b[0];
61 	B = b[1];
62 	C = b[2];
63 	D = b[3];
64 #elif __BYTE_ORDER == __BIG_ENDIAN
65 	A = b[3];
66 	B = b[2];
67 	C = b[1];
68 	D = b[0];
69 #else
70 #	error "Endianess of your machine is not supported."
71 #endif
72 	return A | (B<<8) | ((C)<<16) | ((D)<<24);
73 }
74 
75 /* Works only for little endian machines at the time! */
put_le32(char * b,unsigned v)76 void put_le32( char *b, unsigned v ) {
77 #if __BYTE_ORDER == __LITTLE_ENDIAN
78 	b[0] = v&0xff;
79 	b[1] = (v>>8)&0xff;
80 	b[2] = (v>>16)&0xff;
81 	b[3] = (v>>24)&0xff;
82 #elif __BYTE_ORDER == __BIG_ENDIAN
83 	b[3] = v&0xff;
84 	b[2] = (v>>8)&0xff;
85 	b[1] = (v>>16)&0xff;
86 	b[0] = (v>>24)&0xff;
87 #else
88 #	error "Endianess of you machine is not supported."
89 #endif
90 }
91 
usb_read_byte(usb_dev_handle * h,int value,char * byte)92 void usb_read_byte( usb_dev_handle *h, int value, char *byte ) {
93 	int ret;
94 #if DEBUG
95 	fprintf(stderr, "usb_read_byte: value=%d (0x%x)", value, value);
96 #endif
97 	while ( (ret=USB_READ_BYTE(h, value, byte)) == 0  ) {
98 #if DEBUG
99 		fprintf(stderr, "Read nothing, trying again.\n");
100 #endif
101 	}
102 
103 	if ( ret < 0 ) {
104 		fprintf(stderr, "Read failed, exiting...\n");
105 		exit(1);
106 	}
107 #if DEBUG
108     fprintf(stderr,", byte=%c (0x%02x)\n", *(unsigned char*)byte, *(unsigned char*)byte);
109 #endif
110 }
111 
usb_read_bytes(usb_dev_handle * h,int value,char * bytes,int size)112 void usb_read_bytes( usb_dev_handle *h, int value, char *bytes, int size ) {
113 	int ret;
114 #if DEBUG
115 	fprintf(stderr, "usb_read_bytes: value=%d (0x%x), size=%d (0x%x):\n", value, value, size, size);
116 #endif
117 	while ( (ret=USB_READ_BYTES(h, value, bytes, size)) < size  ) {
118 #if DEBUG
119 		fprintf(stderr, "Partial read, trying again.\n");
120 #endif
121 	}
122 
123 	if ( ret < 0 ) {
124 		fprintf(stderr, "Read failed, exiting...\n");
125 		exit(1);
126 	}
127 #if DEBUG
128 	usb_hexdump(bytes, size);
129 #endif
130 }
131 
usb_write_byte(usb_dev_handle * h,int value,char * byte)132 void usb_write_byte( usb_dev_handle *h, int value, char *byte ) {
133 	int ret = 0, retr = 0;
134 #if DEBUG
135 	fprintf(stderr, "usb_write_byte: value=%d (0x%x), byte=%c (0x%02x)\n", value, value, *byte, *byte);
136 #endif
137 
138 	while ( (ret=USB_WRITE_BYTE(h, value, byte)) == 0  ) {
139 #if DEBUG
140 		fprintf(stderr, "Wrote partially, trying again.\n");
141 #endif
142 		if ( tolerate_error && ++retr >= retries ) {
143 			fprintf(stderr,"Writing sequence tried %d times, giving up...\n", retr);
144 			return;
145 		}
146 	}
147 
148 	if ( ret < 0 ) {
149 		fprintf(stderr, "Write failed, exiting...\n");
150 		exit(1);
151 	}
152 }
153 
usb_write_bytes(usb_dev_handle * h,int value,char * bytes,int size)154 void usb_write_bytes( usb_dev_handle *h, int value, char *bytes, int size ) {
155 	int ret = 0, retr = 0;
156 #if DEBUG
157 	fprintf(stderr, "usb_write_bytes: value=%d (0x%x), size=%d (0x%x):\n", value, value, size, size);
158 	usb_hexdump(bytes, size);
159 #endif
160 	while ( (ret=USB_WRITE_BYTES(h, value, bytes, size)) < size  ) {
161 #if DEBUG
162 		fprintf(stderr, "Wrote partially, trying again.\n");
163 #endif
164 		if ( tolerate_error && ++retr >= retries ) {
165 			fprintf(stderr,"Writing sequence tried %d times, giving up...\n", retr);
166 			return;
167 		}
168 	}
169 
170 	if ( ret < 0 ) {
171 		fprintf(stderr, "Write failed, exiting...\n");
172 		exit(1);
173 	}
174 }
175 
usb_bulk_read_bytes(usb_dev_handle * h,int ep,char * bytes,int size)176 void usb_bulk_read_bytes( usb_dev_handle *h, int ep, char *bytes, int size ) {
177 	int ret = -1, pos = 0, retr = 0;
178 
179 	if ( !size ) {
180 		fprintf(stderr, "warning: bulk_read request of 0 bytes!\n");
181 		return;
182 	}
183 
184 	memset(bytes, 0, size);
185 	while ( pos != size && (ret = usb_bulk_read( h, ep, (char*)&bytes[pos], size-pos, USB_TIMEOUT )) >= 0 ) {
186 		pos += ret;
187 #if DEBUG
188 		fprintf(stderr, "usb_bulk_read: ep=%d (0x%x), size=%d (0x%x):\n", ep, ep, ret, ret);
189 #endif
190 		retr++;
191 		if ( tolerate_error && retr >= retries ) break;
192 	}
193 
194 	if ( pos != size || ret < 0 ) {
195 		fprintf(stderr, "Error in usb_bulk_read() request.\n");
196 		if ( !tolerate_error ) {
197 			exit(1);
198 		} else {
199 			fprintf(stderr, "Tolerating the above error for now.\n");
200 		}
201 	}
202 #if DEBUG
203 	usb_hexdump(bytes, size);
204 #endif
205 }
206 
usb_send_packet(camera * c,unsigned char cmd1,unsigned char cmd2,unsigned cmd3,char * arguments,int argsize)207 void usb_send_packet( camera *c, unsigned char cmd1, unsigned char cmd2, unsigned cmd3, char *arguments, int argsize ) {
208 #ifdef DEBUG
209 	fprintf(stderr, "usb_send_packet: cmd1=%d (0x%x), cmd2=%d (0x%x), cmd3=%d (0x%x):\n", cmd1, cmd1, cmd2, cmd2, cmd3, cmd3);
210 #endif
211 	memset(usb_packet, 0, 0x50);
212 	put_le32(usb_packet, 0x10+argsize);
213 	put_le32(usb_packet+0x48, 0x10+argsize);
214 	usb_packet[0x40] = 0x2;
215 	usb_packet[0x44] = cmd1;
216 	usb_packet[0x47] = cmd2;
217 	put_le32(usb_packet+4, cmd3);
218 
219 	if ( CANON_CLASS(c) >= 6 && !IS_TYPE(c,"1D") ) {
220 		usb_packet[0x46] = cmd3==0x202 ? 0x20 : 0x10;
221 	}
222 
223 	put_le32(usb_packet+0x4c, usb_sequence++);
224 
225 	if (argsize < 0 || argsize+0x50 > sizeof(usb_packet)) {
226 		fprintf(stderr, "Invalid argsize = %d (0x%x).\n\n", argsize, argsize);
227 		exit(1);
228 	}
229 
230 	if ( argsize > 0 ) {
231 		memcpy(usb_packet+0x50, arguments, argsize);
232 	}
233 
234 	usb_write_bytes(c->h, 0x10, usb_packet, 0x50+argsize);
235 }
236 
usb_receive_packet(camera * c,char * bytes,int size)237 void usb_receive_packet( camera *c, char *bytes, int size ) {
238 #ifdef DEBUG
239 	fprintf(stderr, "usb_receive_packet: ep=%d (0x%x), size=%d (0x%x):\n", c->bulk_in, c->bulk_in, size, size);
240 #endif
241 	usb_bulk_read_bytes(c->h, c->bulk_in, bytes, size);
242 
243 	{
244 		int i;
245 		unsigned code = get_le32(&bytes[0x50]);
246 #ifdef DEBUG
247 		unsigned cmd3 = ((bytes[5]-1)<<8)+bytes[4];
248 
249 		if (cmd3==0x202) { /* Format of response block is different in case cmd3==0x202*/
250 			fprintf(stderr,"usb_receive_packet sanity check: unformatted binary data of size=%d follows\n", get_le32(&bytes[6]));
251 		} else {
252 			fprintf(stderr,"usb_receive_packet sanity check: cmd1=0x%02x, cmd2=0x%02x, cmd3=0x%03x, 2==%d, size=0x%04x\n",
253 			bytes[0x44],
254 			bytes[0x47]-0x10,
255 			cmd3,
256 			bytes[0x40],
257 			get_le32(&bytes[0x48])+0x40);
258 		}
259 #endif
260 		if ( !code ) return;
261 
262 		for ( i=0; canon_status[i].code; i++ )
263 			if ( canon_status[i].code == code ) {
264 				fprintf(stderr, "usb_receive_packet status code: 0x%08x -> %s.\n", code, canon_status[i].text);
265 				return;
266 			}
267 		fprintf(stderr, "usb_receive_packet exit code: 0x%08x -> UNKNOWN !!!\n", code);
268 	}
269 }
270