1 /* library.c
2 
3  *
4  * Copyright (C) 2006-2010 Theodore Kilgore <kilgota@auburn.edu>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA  02110-1301  USA
20  */
21 
22 #include <config.h>
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include "jl2005bcd_decompress.h"
29 #include <gphoto2/gphoto2.h>
30 
31 
32 #ifdef ENABLE_NLS
33 #  include <libintl.h>
34 #  undef _
35 #  define _(String) dgettext (PACKAGE, String)
36 #  ifdef gettext_noop
37 #    define N_(String) gettext_noop (String)
38 #  else
39 #    define N_(String) (String)
40 #  endif
41 #else
42 #  define _(String) (String)
43 #  define N_(String) (String)
44 #endif
45 
46 #include "jl2005c.h"
47 #include <gphoto2/gphoto2-port.h>
48 
49 #define GP_MODULE "jl2005c"
50 
51 struct {
52 	char *name;
53 	CameraDriverStatus status;
54 	unsigned short idVendor;
55 	unsigned short idProduct;
56 } models[] = {
57 	{" JL2005B/C/D camera", GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
58 	{"Argus DC1512e",       GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
59 	{"Amazing Spiderman",   GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
60 	{"Aries ATC-0017",      GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
61 	{"Sakar no. 75379",     GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
62 	{"Sakar no. 81890",     GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
63 	{"Sakar Nickelodeon iCarly no. 88061", GP_DRIVER_STATUS_EXPERIMENTAL,
64 							0x0979, 0x0227},
65 	{"Sakar Dora the Explorer no. 88067", GP_DRIVER_STATUS_EXPERIMENTAL,
66 							0x0979, 0x0227},
67 	{"Sakar no. 91379",     GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
68 	{"Sakar no. 98379",     GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
69 	{"Sakar Kidz-Cam no. 88379", GP_DRIVER_STATUS_EXPERIMENTAL,
70 							       0x0979, 0x0227},
71 	{"Sakar clipshot no. 1169x", GP_DRIVER_STATUS_EXPERIMENTAL,
72 							       0x0979, 0x0227},
73 	{"Sakar Sticker Wizard no. 59379", GP_DRIVER_STATUS_EXPERIMENTAL,
74 							       0x0979, 0x0227},
75 	{"Sakar Star Wars kit no. 92022", GP_DRIVER_STATUS_EXPERIMENTAL,
76 							       0x0979, 0x0227},
77 	{"Jazwares Star Wars no. 15256", GP_DRIVER_STATUS_EXPERIMENTAL,
78 							       0x0979, 0x0227},
79 	{"Argus Bean Sprout",   GP_DRIVER_STATUS_EXPERIMENTAL,
80 							       0x0979, 0x0227},
81 	{"Global Point Clipster", GP_DRIVER_STATUS_EXPERIMENTAL,
82 							       0x0979, 0x0227},
83 	{"Global Point 3 in 1 Digital Fun Graffiti 00044",
84 				GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
85 	{"Jazz JDK235", 	GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
86 	{"DIGITAL MID#0020509 (no-name camera)",
87 				GP_DRIVER_STATUS_EXPERIMENTAL, 0x0979, 0x0227},
88 	{"Vivitar Freelance", GP_DRIVER_STATUS_EXPERIMENTAL,
89 							       0x0979, 0x0227},
90 	{"Sakar Hello Kitty no. 94009", GP_DRIVER_STATUS_EXPERIMENTAL,
91 							       0x0979, 0x0227},
92 	{NULL,0,0,0}
93 };
94 
95 int
camera_id(CameraText * id)96 camera_id (CameraText *id)
97 {
98 	strcpy (id->text, "JL2005B/C/D camera");
99 	return GP_OK;
100 }
101 
102 int
camera_abilities(CameraAbilitiesList * list)103 camera_abilities (CameraAbilitiesList *list)
104 {
105 	int i;
106 	CameraAbilities a;
107 
108 	for (i = 0; models[i].name; i++) {
109 		memset (&a, 0, sizeof(a));
110 		strcpy (a.model, models[i].name);
111 		a.status = models[i].status;
112 		a.port   = GP_PORT_USB;
113 		a.speed[0] = 0;
114 		a.usb_vendor = models[i].idVendor;
115 		a.usb_product= models[i].idProduct;
116 		if (a.status == GP_DRIVER_STATUS_EXPERIMENTAL)
117 			a.operations = GP_OPERATION_NONE;
118 		else
119 			a.operations = GP_OPERATION_CAPTURE_IMAGE;
120 		a.folder_operations = GP_FOLDER_OPERATION_DELETE_ALL;
121 		a.file_operations   = GP_FILE_OPERATION_PREVIEW
122 					+ GP_FILE_OPERATION_RAW;
123 		gp_abilities_list_append (list, a);
124 	}
125 	return GP_OK;
126 }
127 
128 static int
camera_summary(Camera * camera,CameraText * summary,GPContext * context)129 camera_summary (Camera *camera, CameraText *summary, GPContext *context)
130 {
131 	int num_pics;
132 	num_pics = camera->pl->nb_entries;
133 	GP_DEBUG("camera->pl->nb_entries = %i\n",camera->pl->nb_entries);
134 	sprintf(summary->text,
135 			_("This camera contains a Jeilin JL2005%c chipset.\n"
136 			"The number of photos in it is %i. \n"),
137 			camera->pl->model, num_pics);
138 	return GP_OK;
139 }
140 
141 static int
camera_manual(Camera * camera,CameraText * manual,GPContext * context)142 camera_manual (Camera *camera, CameraText *manual, GPContext *context)
143 {
144 	strcpy(manual->text,
145 	_(
146 	"This driver supports cameras with Jeilin JL2005B or C or D  chip \n"
147 	"These cameras do not support deletion of photos, nor uploading\n"
148 	"of data. \n"
149 	"If present on the camera, video clip frames are downloaded \n"
150 	"as consecutive still photos.\n"
151 	"For more details please consult libgphoto2/camlibs/README.jl2005c\n"
152 	));
153 
154 	return (GP_OK);
155 }
156 
157 
158 static int
camera_about(Camera * camera,CameraText * about,GPContext * context)159 camera_about (Camera *camera, CameraText *about, GPContext *context)
160 {
161 	strcpy (about->text, _("jl2005bcd camera library\n"
162 			    "Theodore Kilgore <kilgota@auburn.edu>\n"));
163 	return GP_OK;
164 }
165 
166 /*************** File and Downloading Functions *******************/
167 
168 static int
file_list_func(CameraFilesystem * fs,const char * folder,CameraList * list,void * data,GPContext * context)169 file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
170 				void *data, GPContext *context)
171 {
172 	Camera *camera = data;
173 	int n;
174 	n = camera->pl->nb_entries;
175 	gp_list_populate (list, "jl_%03i.ppm", n);
176 	return GP_OK;
177 }
178 
179 static int
get_info_func(CameraFilesystem * fs,const char * folder,const char * filename,CameraFileInfo * info,void * data,GPContext * context)180 get_info_func (CameraFilesystem *fs, const char *folder, const char *filename,
181 		CameraFileInfo *info, void *data, GPContext *context)
182 {
183 	info->file.fields = GP_FILE_INFO_TYPE;
184 	strcpy (info->file.type, GP_MIME_PPM);
185 
186 	return (GP_OK);
187 }
188 
189 static int
get_file_func(CameraFilesystem * fs,const char * folder,const char * filename,CameraFileType type,CameraFile * file,void * user_data,GPContext * context)190 get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
191 		CameraFileType type, CameraFile *file, void *user_data,
192 		GPContext *context)
193 {
194 	Camera *camera = user_data;
195 	int w, h = 0, b = 0, k;
196 	unsigned char *pic_data, *pic_buffer, *pic_output = NULL;
197 	int HEADERSIZE=16;
198 	int outputsize;
199 	unsigned long start_of_photo;
200 	unsigned int downloadsize = 0;
201 	int filled = 0;
202 
203 	GP_DEBUG ("Downloading pictures!\n");
204 	if(!camera->pl->data_reg_opened)
205 	jl2005c_open_data_reg (camera, camera->port);
206 	/* These are cheap cameras. There ain't no EXIF data. */
207 	if (GP_FILE_TYPE_EXIF == type) return GP_ERROR_FILE_EXISTS;
208 
209 	/* Get the number of the photo on the camera */
210 	k = gp_filesystem_number (camera->fs, "/", filename, context);
211 	h = camera->pl->table[16 * k + 4] << 3;
212 	w = camera->pl->table[16 * k + 5] << 3;
213 
214 	GP_DEBUG ("height is %i\n", h);
215 
216 	b = jl2005c_get_pic_data_size(camera->pl, camera->pl->table, k);
217 	GP_DEBUG("b = %i = 0x%x bytes\n", b, b);
218 	start_of_photo = jl2005c_get_start_of_photo(camera->pl,
219 						    camera->pl->table, k);
220 	GP_DEBUG("start_of_photo number %i = 0x%lx \n", k,start_of_photo);
221 	pic_buffer = malloc(b + HEADERSIZE);
222 	if (!pic_buffer) return GP_ERROR_NO_MEMORY;
223 	memset(pic_buffer, 0, b + HEADERSIZE);
224 	GP_DEBUG("buffersize b + 16 = %i = 0x%x bytes\n", b + 16, b + 16);
225 	/* Copy info line for photo from allocation table, as header */
226 	memcpy(pic_buffer, camera->pl->table + 16 * k, 16);
227 	pic_data = pic_buffer + HEADERSIZE;
228 
229 	/*
230 	 * Camera can download in blocks of 0xfa00, with only the last block
231 	 * possibly smaller. So first we set up a cache of that size
232 	 * (if it is not set up already) to hold raw data. If one tries
233 	 * instead to download one photo at a time, the camera will misbehave;
234 	 * data will be lost or corrupted. The dog will bite you, too.
235 	 */
236 
237 	if (!(camera->pl->data_cache)) {
238 		camera->pl->data_cache = malloc (MAX_DLSIZE);
239 	}
240 	if (!(camera->pl->data_cache)) {
241 		GP_DEBUG ("no cache memory allocated!\n");
242 		free (pic_buffer);
243 		return GP_ERROR_NO_MEMORY;
244 	}
245 
246 	/* Is there data in the cache, or not? If yes, read from it into the
247 	 * current photo, immediately. Update settings. But first two sanity
248 	 * checks.
249 	 */
250 
251 	if (start_of_photo < camera->pl->bytes_put_away) {
252 		GP_DEBUG("photo number %i starts in a funny place!\n",k);
253 		/* We need to start all over again to get this photo. */
254 		jl2005c_reset (camera, camera->port);
255 		jl2005c_init (camera, camera->port, camera->pl);
256 	}
257 	if (start_of_photo + b > camera->pl->total_data_in_camera) {
258 		GP_DEBUG ("Photo runs past end of data. Exiting. \n");
259 		GP_DEBUG ("Block size may be wrong for this camera\n");
260 		free (pic_buffer);
261 		return (GP_ERROR);
262 	}
263 	/*
264 	 * This while loop is entered if the photo number k-1 was not requested
265 	 * and thus has not been downloaded. The camera's rudimentary hardware
266 	 * obliges us to download all data consecutively and toss whatever
267 	 * portion of said data that we do not intend to use. The rudimentary
268 	 * hardware also does not like to stop downloading at the end of one
269 	 * photo and then to start on the next. It wants to keep getting data
270 	 * in size 0xfa00 increments, and only the last block can be smaller.
271 	 * To do otherwise will cause data to be lost or corrupted.
272 	 *
273 	 * Whoever tries to simplify this convoluted and ugly procedure is
274 	 * warned that the obvious simplifications, while much prettier,
275 	 * just won't work. A kutya harap.
276 	 */
277 	while (camera->pl->bytes_read_from_camera <= start_of_photo) {
278 		camera->pl->data_to_read = camera->pl->total_data_in_camera
279 			    - camera->pl->bytes_read_from_camera;
280 		downloadsize = MAX_DLSIZE;
281 		if (camera->pl->data_to_read < downloadsize)
282 			downloadsize = camera->pl->data_to_read;
283 		GP_DEBUG("downloadsize = 0x%x\n", downloadsize);
284 		if (downloadsize)
285 			jl2005c_read_data (
286 					    camera->port,
287 					    (char *) camera->pl->data_cache,
288 					    downloadsize);
289 		camera->pl->bytes_read_from_camera += downloadsize;
290 	}
291 
292 	camera->pl->bytes_put_away = start_of_photo;
293 
294 	if (camera->pl->bytes_read_from_camera > start_of_photo) {
295 		if(start_of_photo + b <= camera->pl->bytes_read_from_camera) {
296 			memcpy(pic_data, camera->pl->data_cache
297 					+ (start_of_photo % MAX_DLSIZE)
298 								, b);
299 			camera->pl->bytes_put_away += b;
300 			/*
301 			 * Photo data is contained in what is already
302 			 * downloaded.
303 			 * Jump immediately to process the photo.
304 			 */
305 		} else {
306 			/* Photo starts in one 0xfa00-sized download and ends
307 			 * in another */
308 			filled = camera->pl->bytes_read_from_camera
309 				    - start_of_photo;
310 
311 			memcpy(pic_data, camera->pl->data_cache
312 					+ (start_of_photo % MAX_DLSIZE),
313 							filled);
314 
315 			camera->pl->bytes_put_away += filled;
316 		}
317 	}
318 	while (camera->pl->bytes_put_away < start_of_photo + b ) {
319 
320 		camera->pl->data_to_read = camera->pl->total_data_in_camera
321 			    - camera->pl->bytes_read_from_camera;
322 		downloadsize = MAX_DLSIZE;
323 		if (camera->pl->data_to_read < downloadsize)
324 			downloadsize = camera->pl->data_to_read;
325 		GP_DEBUG("downloadsize = 0x%x\n", downloadsize);
326 		if (downloadsize)
327 			jl2005c_read_data (
328 					    camera->port,
329 					    (char *) camera->pl->data_cache,
330 					    downloadsize);
331 		camera->pl->bytes_read_from_camera += downloadsize;
332 
333 		if (camera->pl->bytes_read_from_camera >=
334 						start_of_photo + b ) {
335 			GP_DEBUG("THIS ONE?\n");
336 			memcpy(pic_data + filled, camera->pl->data_cache,
337 						b - filled);
338 			camera->pl->bytes_put_away += b - filled;
339 			break;
340 		} else {
341 			GP_DEBUG("THIS ONE??\n");
342 			if (!downloadsize)
343 				break;
344 			memcpy(pic_data + filled,
345 					camera->pl->data_cache, downloadsize);
346 			camera->pl->bytes_put_away += downloadsize;
347 			filled += downloadsize;
348 		}
349 	}
350 
351 	if (type == GP_FILE_TYPE_RAW) {
352 		gp_file_set_mime_type(file, GP_MIME_RAW);
353 		gp_file_set_data_and_size(file, (char *)pic_buffer, b + 16);
354 		return GP_OK;
355 #ifdef HAVE_LIBJPEG
356 	} else if (type == GP_FILE_TYPE_PREVIEW) {
357 		if (!camera->pl->can_do_capture) {
358 			free (pic_buffer);
359 			return GP_ERROR_NOT_SUPPORTED;
360 		}
361 		outputsize = (pic_buffer[9] & 0xf0) * 192 + 256;
362 		GP_DEBUG("pic_buffer[9] is 0x%02x\n", pic_buffer[9]);
363 		GP_DEBUG("Thumbnail outputsize = 0x%x = %d\n", outputsize,
364 								outputsize);
365 		if (outputsize == 256) {
366 			GP_DEBUG("Frame %d has no thumbnail.\n", k);
367 			free (pic_buffer);
368 			return GP_OK;
369 		}
370 		pic_output = calloc(outputsize, 1);
371 		if (!pic_output) {
372 			free (pic_buffer);
373 			return GP_ERROR_NO_MEMORY;
374 		}
375 		outputsize = jl2005bcd_decompress(pic_output, pic_buffer,
376 								b + 16, 1);
377 		free (pic_buffer);
378 		if (outputsize < GP_OK) {
379 			free (pic_output);
380 			return outputsize;
381 		}
382 		GP_DEBUG("Thumbnail outputsize recalculated is 0x%x = %d\n",
383 						outputsize, outputsize);
384 		gp_file_set_mime_type(file, GP_MIME_PPM);
385 		gp_file_set_data_and_size(file, (char *)pic_output,
386 								outputsize);
387 	} else if (type == GP_FILE_TYPE_NORMAL) {
388 		outputsize = 3 * w * h + 256;
389 		pic_output = calloc(outputsize, 1);
390 		if (!pic_output) {
391 			free (pic_buffer);
392 			return GP_ERROR_NO_MEMORY;
393 		}
394 		outputsize = jl2005bcd_decompress(pic_output, pic_buffer,
395 								b + 16, 0);
396 		free (pic_buffer);
397 		if (outputsize < GP_OK) {
398 			free (pic_output);
399 			return outputsize;
400 		}
401 		gp_file_set_mime_type(file, GP_MIME_PPM);
402 		gp_file_set_data_and_size(file, (char *)pic_output,
403 								outputsize);
404 #endif
405 	} else {
406 		free (pic_buffer);
407 		return GP_ERROR_NOT_SUPPORTED;
408 	}
409 
410 	return GP_OK;
411 }
412 
413 static int
delete_all_func(CameraFilesystem * fs,const char * folder,void * data,GPContext * context)414 delete_all_func (CameraFilesystem *fs, const char *folder, void *data,
415                  GPContext *context)
416 {
417 	Camera *camera = data;
418 
419 	GP_DEBUG(" * delete_all_func()");
420 	jl2005c_delete_all(camera, camera->port);
421 
422 	return (GP_OK);
423 }
424 
425 
426 
427 /*************** Exit and Initialization Functions ******************/
428 
429 static int
camera_exit(Camera * camera,GPContext * context)430 camera_exit (Camera *camera, GPContext *context)
431 {
432 	GP_DEBUG ("jl2005c camera_exit");
433 	jl2005c_reset(camera, camera->port);
434 	gp_port_close(camera->port);
435 	if (camera->pl) {
436 		free (camera->pl);
437 		camera->pl = NULL;
438 	}
439 	return GP_OK;
440 }
441 
442 static CameraFilesystemFuncs fsfuncs = {
443 	.file_list_func = file_list_func,
444 	.get_file_func = get_file_func,
445 	.get_info_func = get_info_func,
446 	.delete_all_func = delete_all_func
447 };
448 
449 int
camera_init(Camera * camera,GPContext * context)450 camera_init (Camera *camera, GPContext *context)
451 {
452 	GPPortSettings settings;
453 	int ret = 0;
454 
455 	/* First, set up all the function pointers */
456         camera->functions->manual	= camera_manual;
457 	camera->functions->summary	= camera_summary;
458 	camera->functions->about	= camera_about;
459 	camera->functions->exit		= camera_exit;
460 
461 	GP_DEBUG ("Initializing the camera\n");
462 	ret = gp_port_get_settings(camera->port,&settings);
463 	if (ret < 0) return ret;
464 
465 	switch (camera->port->type) {
466 		case GP_PORT_SERIAL:
467 			return ( GP_ERROR );
468 		case GP_PORT_USB:
469 			settings.usb.config = 1;
470 			settings.usb.altsetting = 0;
471 			settings.usb.interface = 0;
472 		/* inep 0x84 used to initialize. Then switch to 0x82! */
473 			settings.usb.inep = 0x84;
474 			settings.usb.outep = 0x03;
475 			break;
476 		default:
477 			return ( GP_ERROR );
478 	}
479 
480 	ret = gp_port_set_settings(camera->port,settings);
481 	if (ret < 0) return ret;
482 
483 	GP_DEBUG("interface = %i\n", settings.usb.interface);
484 	GP_DEBUG("inep = %x\n", settings.usb.inep);
485 	GP_DEBUG("outep = %x\n", settings.usb.outep);
486 
487 	/* Tell the CameraFilesystem where to get lists from */
488 	gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
489 
490 	camera->pl = malloc (sizeof (CameraPrivateLibrary));
491 	if (!camera->pl) return GP_ERROR_NO_MEMORY;
492 	memset (camera->pl, 0, sizeof (CameraPrivateLibrary));
493 	/* Connect to the camera */
494 	camera->pl->total_data_in_camera=0;
495 	camera->pl->data_to_read = 0;
496 	camera->pl->bytes_put_away = 0;
497 	camera->pl->data_reg_opened = 0;
498 	camera->pl->data_cache = NULL;
499 	camera->pl->init_done = 0;
500 	jl2005c_init (camera, camera->port, camera->pl);
501 
502 	return GP_OK;
503 }
504