1 /****************************************************************/
2 /* library.c - Gphoto2 library for the Creative PC-CAM600      */
3 /*                                                              */
4 /*                                                              */
5 /* Author: Peter Kajberg <pbk@odense.kollegienet.dk>            */
6 /*                                                              */
7 /* This library is free software; you can redistribute it       */
8 /* and/or modify it under the terms of the GNU Library General  */
9 /* Public License as published by the Free Software Foundation; */
10 /* either version 2 of the License, or (at your option) any     */
11 /* later version.                                               */
12 /*                                                              */
13 /* This library is distributed in the hope that it will be      */
14 /* useful, but WITHOUT ANY WARRANTY; without even the implied   */
15 /* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      */
16 /* PURPOSE.  See the GNU Library General Public License for     */
17 /* more details.                                                */
18 /*                                                              */
19 /* Please notice that camera commands was sniffed by use of a   */
20 /* usbsniffer under windows. This is an experimental driver and */
21 /* a work in progess(I hope :))                                 */
22 /*                                                              */
23 /* You should have received a copy of the GNU Library General   */
24 /* Public License along with this library; if not, write to the */
25 /* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,*/
26 /* Boston, MA  02110-1301  USA					*/
27 /****************************************************************/
28 
29 #include "config.h"
30 
31 #include "pccam600.h"
32 
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <string.h>
38 
39 #include <gphoto2/gphoto2.h>
40 #include <gphoto2/gphoto2-port.h>
41 
42 #define GP_MODULE "pccam600"
43 
44 #ifdef ENABLE_NLS
45 #  include <libintl.h>
46 #  undef _
47 #  define _(String) dgettext (GETTEXT_PACKAGE, String)
48 #  ifdef gettext_noop
49 #    define N_(String) gettext_noop (String)
50 #  else
51 #    define N_(String) (String)
52 #  endif
53 #else
54 #  define _(String) (String)
55 #  define N_(String) (String)
56 #endif
57 
58 
59 #define QUALITY_LO   0x56
60 #define QUALITY_ME   0x58
61 #define QUALITY_HI   0x45
62 
63 static const struct models{
64   char *name;
65   unsigned short idVendor;
66   unsigned short idProduct;
67   char serial;
68 } models[] = {
69   {"Creative:PC-CAM600",0x041e,0x400b,0},
70   {"Creative:PC-CAM750",0x041e,0x4013,0},
71   {"Creative PC-CAM350",0x041e,0x4012,0},
72   {NULL,0,0,0}
73 };
74 
camera_id(CameraText * id)75 int camera_id(CameraText *id)
76 {
77   strcpy(id->text, "Creative PC-CAM600/750/350");
78   return (GP_OK);
79 }
80 
camera_abilities(CameraAbilitiesList * list)81 int camera_abilities(CameraAbilitiesList *list)
82 {
83   int i;
84   CameraAbilities a;
85   for(i=0; models[i].name; i++) {
86     memset(&a , 0, sizeof(CameraAbilities));
87     strcpy(a.model, models[i].name);
88     a.status      = GP_DRIVER_STATUS_EXPERIMENTAL;
89     a.port        = GP_PORT_USB;
90     a.speed[0]    = 0;
91     a.usb_vendor  = models[i].idVendor;
92     a.usb_product = models[i].idProduct;
93     a.operations        = 	GP_OPERATION_NONE;
94     a.folder_operations = 	GP_FOLDER_OPERATION_NONE;
95     a.file_operations   =     GP_FILE_OPERATION_DELETE;
96     gp_abilities_list_append(list, a);
97   }
98   return GP_OK;
99 }
100 
camera_exit(Camera * camera,GPContext * context)101 static int camera_exit(Camera *camera, GPContext *context){
102   return pccam600_close(camera->port, context);
103 }
104 
file_list_func(CameraFilesystem * fs,const char * folder,CameraList * list,void * data,GPContext * context)105 static int file_list_func (CameraFilesystem *fs, const char *folder,
106 			   CameraList *list, void *data, GPContext *context){
107 
108   Camera *camera = data;
109   CameraFileInfo info;
110   int n,i,nr_of_blocks;
111   int offset = 64;
112   char *temp;
113   char buffer[512];
114   FileEntry *file_entry;
115 
116   file_entry = malloc(sizeof(FileEntry));
117   if ( (nr_of_blocks = pccam600_get_file_list(camera->port, context)) < 0 ){
118     gp_log(GP_LOG_DEBUG,"pccam600","pccam600->get_file_list return <0");
119     free (file_entry);
120     return GP_ERROR;
121   }
122   for (n = 0; n != nr_of_blocks; n++)
123     {
124       CHECK(pccam600_read_data(camera->port, (unsigned char *)buffer));
125       for (i = offset; i <= 512-32; i=i+32)
126 	{
127 	  memcpy(file_entry,&(buffer)[i],32);
128 	  file_entry->name[8] = 0;
129 	  /*Fileentry valid? */
130 	  if( !((file_entry->state & 0x02) != 2)  &&
131 	      !((file_entry->state & 0x08) == 8) )
132 	    {
133 	      info.file.fields = 0;
134 	      temp = (char *)&(file_entry->name)[5];
135 	      if (strncmp(temp,"JPG",3) == 0)
136 		{
137 		  memcpy(&(file_entry->name)[5],".jpg",4);
138 		  strcpy(info.file.type,GP_MIME_JPEG);
139 		  info.file.fields = GP_FILE_INFO_TYPE;
140 		}
141 	      else if (strncmp(temp,"AVI",3) == 0)
142 		{
143 		  memcpy(&(file_entry->name)[5],".avi",4);
144 		  info.file.fields = GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | GP_FILE_INFO_TYPE;
145 		  info.file.height = 352;
146 		  info.file.width = 288;
147 		  strcpy(info.file.type, GP_MIME_AVI);
148 		}
149 	      else if (strncmp(temp,"WAV",3) == 0)
150 		{
151 		  memcpy(&(file_entry->name)[5],".wav",4);
152 		  strcpy(info.file.type, GP_MIME_WAV);
153 		  info.file.fields = GP_FILE_INFO_TYPE;
154 		  info.file.height = 0;
155 		}
156 	      else if (strncmp(temp,"RAW",3) == 0)
157 		{
158 		  memcpy(&(file_entry->name)[5],".raw",4);
159 		  info.file.width = 1280;
160 		  info.file.height = 960;
161 		  info.file.fields = GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | GP_FILE_INFO_TYPE;
162 		  strcpy(info.file.type, GP_MIME_RAW);
163 		}
164 	      gp_filesystem_append(fs,folder,(char *)file_entry->name,context);
165 	      info.preview.fields = 0;
166 	      info.file.size = (file_entry->size[1]*256+
167 				file_entry->size[0]) * 256;
168 	      info.file.permissions = GP_FILE_PERM_READ | GP_FILE_PERM_DELETE;
169 	      info.file.fields |= GP_FILE_INFO_SIZE | GP_FILE_INFO_PERMISSIONS
170 		|GP_FILE_INFO_TYPE;
171 	      CHECK(gp_filesystem_set_info_noop(fs, folder, (char *)file_entry->name, info, context));
172 	    }
173 	}
174 	offset = 0;
175     }
176   return GP_OK;
177 }
178 
camera_get_file(Camera * camera,GPContext * context,int index,unsigned char ** data,int * size)179 static int camera_get_file (Camera *camera, GPContext *context, int index,
180 			    unsigned char **data, int *size)
181 {
182   unsigned char buffer[512];
183   int nr_of_blocks = 0;
184   int n,id,canceled=0;
185   int picturebuffersize = 0;
186   int offset = 0;
187   nr_of_blocks = pccam600_get_file(camera->port,context,index);
188   if (nr_of_blocks < 0)
189     return GP_ERROR_FILE_NOT_FOUND;
190   picturebuffersize = nr_of_blocks * 512;
191   id = gp_context_progress_start(context,nr_of_blocks,_("Downloading file..."));
192   *data= malloc(picturebuffersize+1);
193   memset(*data,0,picturebuffersize+1);
194   for (n = 0; n != nr_of_blocks; n++){
195     pccam600_read_data(camera->port, buffer);
196     memmove(&(*data)[offset],buffer,512);
197     offset = offset + 512;
198     gp_context_progress_update(context,id,n);
199     if (gp_context_cancel(context) == GP_CONTEXT_FEEDBACK_CANCEL)
200       {
201 	/* Keep reading data or else data will be invalid next time*/
202 	canceled = 1;
203       }
204   }
205   *size = offset;
206   gp_context_progress_stop(context,id);
207   if (canceled) return GP_ERROR_CANCEL;
208   return GP_OK;
209 }
210 
get_file_func(CameraFilesystem * fs,const char * folder,const char * filename,CameraFileType type,CameraFile * file,void * user_data,GPContext * context)211 static int get_file_func (CameraFilesystem *fs, const char *folder,
212 			  const char *filename, CameraFileType type,
213 			  CameraFile *file, void *user_data,
214 			  GPContext *context)
215 {
216   Camera *camera =  user_data;
217   unsigned char *data = NULL;
218   int size,index;
219   size = 0;
220   index = gp_filesystem_number(fs, folder, filename, context);
221   if (index < 0)
222     return index;
223   switch(type)
224     {
225     case GP_FILE_TYPE_NORMAL:
226       CHECK(camera_get_file(camera, context, index, &data, &size));
227       break;
228     default:
229       return GP_ERROR_NOT_SUPPORTED;
230     }
231   return gp_file_set_data_and_size(file, (char *)data, size);
232 }
233 
camera_summary(Camera * camera,CameraText * summary,GPContext * context)234 static int camera_summary(Camera *camera, CameraText *summary, GPContext *context)
235 {
236   int totalmem;
237   int  freemem;
238   char summary_text[256];
239   CHECK(pccam600_get_mem_info(camera->port,context,&totalmem,&freemem));
240   snprintf(summary_text,sizeof(summary_text),
241   	   (" Total memory is %8d bytes.\n Free memory is  %8d bytes."),
242 	   totalmem,freemem );
243   strcat(summary->text,summary_text);
244   return GP_OK;
245 }
246 
camera_about(Camera * camera,CameraText * about,GPContext * context)247 static int camera_about(Camera *camera, CameraText *about, GPContext *context)
248 {
249   strcpy(about->text,
250 	 _("Creative PC-CAM600\nAuthor: Peter Kajberg <pbk@odense.kollegienet.dk>\n"));
251   return GP_OK;
252 }
253 
delete_file_func(CameraFilesystem * fs,const char * folder,const char * filename,void * data,GPContext * context)254 static int delete_file_func(CameraFilesystem *fs, const char *folder,
255 			    const char *filename, void *data, GPContext *context){
256   int index;
257 
258   Camera *camera = data;
259   index = gp_filesystem_number(fs, folder, filename, context);
260   gp_log(GP_LOG_DEBUG,"pccam","deleting '%s' in '%s'.. index:%d",filename, folder,index);
261   CHECK(pccam600_delete_file(camera->port, context, index));
262   return GP_OK;
263 }
264 
265 static CameraFilesystemFuncs fsfuncs = {
266 	.get_file_func = get_file_func,
267 	.file_list_func = file_list_func,
268 	.del_file_func = delete_file_func,
269 };
270 
camera_init(Camera * camera,GPContext * context)271 int camera_init(Camera *camera, GPContext *context){
272   GPPortSettings settings;
273   camera->functions->exit         = camera_exit;
274   camera->functions->summary      = camera_summary;
275   camera->functions->about        = camera_about;
276   gp_log (GP_LOG_DEBUG, "pccam", "Initializing the camera\n");
277   switch (camera->port->type)
278     {
279     case GP_PORT_USB:
280       CHECK(gp_port_get_settings(camera->port,&settings));
281       settings.usb.inep = 0x82;
282       settings.usb.outep = 0x03;
283       settings.usb.config = 1;
284       settings.usb.interface = 1;
285       settings.usb.altsetting = 0;
286       CHECK(gp_port_set_settings(camera->port,settings));
287       break;
288     case GP_PORT_SERIAL:
289       return GP_ERROR_IO_SUPPORTED_SERIAL;
290     default:
291       return GP_ERROR_NOT_SUPPORTED;
292     }
293   CHECK(pccam600_init(camera->port, context));
294   return gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
295 }
296