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