1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* vusb.c
3 *
4 * Copyright (c) 2015,2016 Marcus Meissner <marcus@jet.franken.de>
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 #include <gphoto2/gphoto2-port-library.h>
24
25 #include "vcamera.h"
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <sys/time.h>
32 #ifdef HAVE_SYS_PARAM_H
33 #include <sys/param.h>
34 #endif
35 #include <string.h>
36
37 #include <gphoto2/gphoto2-port.h>
38 #include <gphoto2/gphoto2-port-result.h>
39 #include <gphoto2/gphoto2-port-log.h>
40
41 #ifdef ENABLE_NLS
42 # include <libintl.h>
43 # undef _
44 # define _(String) dgettext (GETTEXT_PACKAGE, String)
45 # ifdef gettext_noop
46 # define N_(String) gettext_noop (String)
47 # else
48 # define N_(String) (String)
49 # endif
50 #else
51 # define textdomain(String) (String)
52 # define gettext(String) (String)
53 # define dgettext(Domain,Message) (Message)
54 # define dcgettext(Domain,Message,Type) (Message)
55 # define bindtextdomain(Domain,Directory) (Domain)
56 # define _(String) (String)
57 # define N_(String) (String)
58 #endif
59
60 #define CHECK(result) {int r=(result); if (r<0) return (r);}
61
62 struct _GPPortPrivateLibrary {
63 int isopen;
64 vcamera *vcamera;
65 };
66
67 GPPortType
gp_port_library_type(void)68 gp_port_library_type (void)
69 {
70 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
71 return GP_PORT_USB;
72 }
73
74 int
gp_port_library_list(GPPortInfoList * list)75 gp_port_library_list (GPPortInfoList *list)
76 {
77 GPPortInfo info;
78
79 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
80
81 CHECK (gp_port_info_new (&info));
82 gp_port_info_set_type (info, GP_PORT_USB);
83 gp_port_info_set_name (info, "");
84 gp_port_info_set_path (info, "^usb:");
85 gp_port_info_list_append (list, info); /* do not check, might be -1 */
86
87 gp_port_info_new (&info);
88 gp_port_info_set_type (info, GP_PORT_USB);
89 gp_port_info_set_name (info, "Universal Serial Bus");
90 gp_port_info_set_path (info, "usb:001,001");
91 CHECK (gp_port_info_list_append (list, info));
92
93 gp_port_info_new (&info);
94 gp_port_info_set_type (info, GP_PORT_USB_SCSI);
95 gp_port_info_set_name (info, "");
96 gp_port_info_set_path (info, "^usbscsi:");
97 CHECK (gp_port_info_list_append (list, info));
98
99 gp_port_info_new (&info);
100 gp_port_info_set_type (info, GP_PORT_USB_DISK_DIRECT);
101 gp_port_info_set_name (info, "");
102 gp_port_info_set_path (info, "^usbdiskdirect:");
103 CHECK (gp_port_info_list_append (list, info));
104 return GP_OK;
105 }
106
gp_port_vusb_init(GPPort * dev)107 static int gp_port_vusb_init (GPPort *dev)
108 {
109 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
110 C_MEM (dev->pl = calloc (1, sizeof (GPPortPrivateLibrary)));
111
112 dev->pl->vcamera = vcamera_new(NIKON_D750);
113 dev->pl->vcamera->init(dev->pl->vcamera);
114
115 return GP_OK;
116 }
117
118 static int
gp_port_vusb_exit(GPPort * port)119 gp_port_vusb_exit (GPPort *port)
120 {
121 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
122 port->pl->vcamera->exit(port->pl->vcamera);
123 free (port->pl->vcamera);
124 port->pl->vcamera = NULL;
125 free (port->pl);
126 port->pl = NULL;
127
128
129 return GP_OK;
130 }
131
132 static int
gp_port_vusb_open(GPPort * port)133 gp_port_vusb_open (GPPort *port)
134 {
135 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(%s)", port->settings.usb.port);
136 if (port->pl->isopen)
137 return GP_ERROR;
138 port->pl->vcamera->open(port->pl->vcamera, port->settings.usb.port);
139 port->pl->isopen = 1;
140 return GP_OK;
141 }
142
143 static int
gp_port_vusb_close(GPPort * port)144 gp_port_vusb_close (GPPort *port)
145 {
146 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
147 if (!port->pl->isopen)
148 return GP_ERROR;
149 port->pl->vcamera->close(port->pl->vcamera);
150 port->pl->isopen = 0;
151 return GP_OK;
152 }
153
154 static int
gp_port_vusb_write(GPPort * port,const char * bytes,int size)155 gp_port_vusb_write (GPPort *port, const char *bytes, int size)
156 {
157 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
158
159 C_PARAMS (port && port->pl && port->pl->vcamera);
160 return port->pl->vcamera->write(port->pl->vcamera, 0x02, (unsigned char*)bytes, size);
161 }
162
163 static int
gp_port_vusb_read(GPPort * port,char * bytes,int size)164 gp_port_vusb_read(GPPort *port, char *bytes, int size)
165 {
166 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
167 return port->pl->vcamera->read(port->pl->vcamera, 0x81, (unsigned char*)bytes, size);
168 }
169
170 static int
gp_port_vusb_send_scsi_cmd(GPPort * port,int to_dev,char * cmd,int cmd_size,char * sense,int sense_size,char * data,int data_size)171 gp_port_vusb_send_scsi_cmd (GPPort *port, int to_dev, char *cmd,
172 int cmd_size, char *sense, int sense_size, char *data, int data_size)
173 {
174 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(dev=%d, cmdsize %d, sense_size %d, data_size %d)", to_dev, cmd_size, sense_size, data_size);
175 return port->pl->vcamera->read(port->pl->vcamera, 0x81, (unsigned char*)data, data_size);
176 }
177
178 static int
gp_port_vusb_seek(GPPort * port,int offset,int whence)179 gp_port_vusb_seek (GPPort *port, int offset, int whence)
180 {
181 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(offset %d, whence %d)", offset, whence);
182 return GP_OK;
183 }
184
185 static int
gp_port_vusb_reset(GPPort * port)186 gp_port_vusb_reset(GPPort *port)
187 {
188 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
189 C_PARAMS (port && port->pl);
190
191 return GP_OK;
192 }
193
194 static int
gp_port_vusb_check_int(GPPort * port,char * bytes,int size,int timeout)195 gp_port_vusb_check_int (GPPort *port, char *bytes, int size, int timeout)
196 {
197 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
198 C_PARAMS (port && port->pl && timeout >= 0);
199
200 return port->pl->vcamera->readint(port->pl->vcamera, (unsigned char*)bytes, size, timeout);
201 }
202
203 static int
gp_port_vusb_update(GPPort * port)204 gp_port_vusb_update (GPPort *port)
205 {
206 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
207 return GP_OK;
208 }
209
210 static int
gp_port_vusb_clear_halt_lib(GPPort * port,int ep)211 gp_port_vusb_clear_halt_lib(GPPort *port, int ep)
212 {
213 unsigned char internal_ep;
214
215 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
216 C_PARAMS (port && port->pl);
217
218 switch (ep) {
219 case GP_PORT_USB_ENDPOINT_IN :
220 internal_ep = port->settings.usb.inep;
221 break;
222 case GP_PORT_USB_ENDPOINT_OUT :
223 internal_ep = port->settings.usb.outep;
224 break;
225 case GP_PORT_USB_ENDPOINT_INT :
226 internal_ep = port->settings.usb.intep;
227 break;
228 default:
229 gp_port_set_error (port, "Bad EndPoint argument 0x%x", ep);
230 return GP_ERROR_BAD_PARAMETERS;
231 }
232 gp_log(GP_LOG_DEBUG,"gp_port_vusb_clear_halt_lib","clearing halt on ep 0x%x", internal_ep);
233 /* now clear halt */
234 return GP_OK;
235 }
236
237 /* The next two functions support the nonstandard request types 0x41 (write)
238 * and 0xc1 (read), which are occasionally needed.
239 */
240 static int
gp_port_vusb_msg_interface_write_lib(GPPort * port,int request,int value,int index,char * bytes,int size)241 gp_port_vusb_msg_interface_write_lib(GPPort *port, int request,
242 int value, int index, char *bytes, int size)
243 {
244 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
245 return GP_OK;
246 }
247
248
249 static int
gp_port_vusb_msg_interface_read_lib(GPPort * port,int request,int value,int index,char * bytes,int size)250 gp_port_vusb_msg_interface_read_lib(GPPort *port, int request,
251 int value, int index, char *bytes, int size)
252 {
253 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(req=%x, value=%x, index=%d, size=%d)", request, value, index, size);
254 return port->pl->vcamera->read(port->pl->vcamera, 0x81, (unsigned char*)bytes, size);
255 }
256
257
258 /* The next two functions support the nonstandard request types 0x21 (write)
259 * and 0xa1 (read), which are occasionally needed.
260 */
261 static int
gp_port_vusb_msg_class_write_lib(GPPort * port,int request,int value,int index,char * bytes,int size)262 gp_port_vusb_msg_class_write_lib(GPPort *port, int request,
263 int value, int index, char *bytes, int size)
264 {
265 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
266 return GP_OK;
267 }
268
269
270
271 static int
gp_port_vusb_msg_class_read_lib(GPPort * port,int request,int value,int index,char * bytes,int size)272 gp_port_vusb_msg_class_read_lib(GPPort *port, int request,
273 int value, int index, char *bytes, int size)
274 {
275 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
276 return GP_OK; /* or bytes */
277 }
278
279
280 static int
gp_port_vusb_msg_write_lib(GPPort * port,int request,int value,int index,char * bytes,int size)281 gp_port_vusb_msg_write_lib(GPPort *port, int request, int value, int index,
282 char *bytes, int size)
283 {
284 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
285 return GP_OK;
286 }
287
288 static int
gp_port_vusb_msg_read_lib(GPPort * port,int request,int value,int index,char * bytes,int size)289 gp_port_vusb_msg_read_lib(GPPort *port, int request, int value, int index,
290 char *bytes, int size)
291 {
292 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(req=%x, value=%x, index=%x, size=%d)", request, value, index, size);
293 return port->pl->vcamera->read(port->pl->vcamera, index, (unsigned char*)bytes, size);
294 }
295
296 static int
gp_port_vusb_find_device_lib(GPPort * port,int idvendor,int idproduct)297 gp_port_vusb_find_device_lib(GPPort *port, int idvendor, int idproduct)
298 {
299 #ifdef FUZZ_PTP
300 if ((idvendor == 0x04b0) && (idproduct == 0x0437)) { /* Nikon D750 */
301 #else
302 GPPortInfo info;
303 char *path, *s;
304 static unsigned short vendor, product;
305 int fd;
306
307 static char *lastpath = NULL;
308
309 gp_port_get_info (port, &info);
310 gp_port_info_get_path (info, &path);
311
312 if (!lastpath || strcmp(path, lastpath)) {
313 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(path=%s)", path);
314 if (lastpath) {
315 free(lastpath);
316 }
317 lastpath = strdup(path);
318
319 s = strchr(path, ':')+1;
320 fd = open(s, O_RDONLY);
321 vendor = product = 0;
322 if (fd != -1) {
323 if (-1 == read( fd, &vendor, 2))
324 gp_log(GP_LOG_DEBUG,__FUNCTION__,"could not read vendor");
325 if (-1 == read( fd, &product, 2))
326 gp_log(GP_LOG_DEBUG,__FUNCTION__,"could not read product");
327 close(fd);
328 }
329 }
330
331 if ((idvendor == vendor) && (idproduct == product)) {
332 #endif
333 port->settings.usb.config = 1;
334 port->settings.usb.interface = 1;
335 port->settings.usb.altsetting = 1;
336
337 port->settings.usb.inep = 0x81;
338 port->settings.usb.outep = 0x02;
339 port->settings.usb.intep = 0x83;
340 port->settings.usb.maxpacketsize = 512;
341 return GP_OK;
342 }
343 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(0x%04x,0x%04x)", idvendor, idproduct);
344 return GP_ERROR_IO_USB_FIND;
345 }
346
347 static int
348 gp_port_vusb_find_device_by_class_lib(GPPort *port, int class, int subclass, int protocol)
349 {
350 gp_log(GP_LOG_DEBUG,__FUNCTION__,"(0x%02x,0x%02x,0x%02x)", class, subclass, protocol);
351
352 #ifdef FUZZ_PTP
353 if ((class == 6) && (subclass == 1) && (protocol == 1)) {
354 port->settings.usb.config = 1;
355 port->settings.usb.interface = 1;
356 port->settings.usb.altsetting = 1;
357
358 port->settings.usb.inep = 0x81;
359 port->settings.usb.outep = 0x02;
360 port->settings.usb.intep = 0x83;
361 port->settings.usb.maxpacketsize = 512;
362 return GP_OK;
363 }
364 #endif
365 return GP_ERROR_IO_USB_FIND;
366 }
367
368
369
370 GPPortOperations *
371 gp_port_library_operations (void)
372 {
373 GPPortOperations *ops;
374
375 gp_log(GP_LOG_DEBUG,__FUNCTION__,"()");
376 ops = calloc (1, sizeof (GPPortOperations));
377 if (!ops)
378 return NULL;
379
380 ops->init = gp_port_vusb_init;
381 ops->exit = gp_port_vusb_exit;
382 ops->open = gp_port_vusb_open;
383 ops->close = gp_port_vusb_close;
384 ops->read = gp_port_vusb_read;
385 ops->write = gp_port_vusb_write;
386 ops->reset = gp_port_vusb_reset;
387
388 ops->check_int = gp_port_vusb_check_int;
389 ops->update = gp_port_vusb_update;
390 ops->clear_halt = gp_port_vusb_clear_halt_lib;
391 ops->msg_write = gp_port_vusb_msg_write_lib;
392 ops->msg_read = gp_port_vusb_msg_read_lib;
393
394 ops->msg_interface_write = gp_port_vusb_msg_interface_write_lib;
395 ops->msg_interface_read = gp_port_vusb_msg_interface_read_lib;
396 ops->msg_class_write = gp_port_vusb_msg_class_write_lib;
397 ops->msg_class_read = gp_port_vusb_msg_class_read_lib;
398 ops->send_scsi_cmd = gp_port_vusb_send_scsi_cmd;
399 ops->seek = gp_port_vusb_seek;
400
401 ops->find_device = gp_port_vusb_find_device_lib;
402 ops->find_device_by_class = gp_port_vusb_find_device_by_class_lib;
403 return ops;
404 }
405