1 /*
2  * Copyright (c) 2010 Linux Hotplug Project
3  *
4  *    This source code is free software; you can redistribute it
5  *    and/or modify it in source code form under the terms of the GNU
6  *    General Public License as published by the Free Software
7  *    Foundation; either version 2 of the License, or (at your option)
8  *    any later version.
9  *
10  *    This program is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *    GNU General Public License for more details.
14  *
15  *    You should have received a copy of the GNU General Public License
16  *    along with this program; if not, write to the Free Software
17  *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  */
19 /*
20  * This code is based on fxload-libusb for Microsoft Windows project done
21  * by Claudio Favi.
22  */
23 # if !defined(__linux__) || defined(LIBUSB_SUPPORT)
24 
25 # include  <assert.h>
26 # include  <stdio.h>
27 # include  <errno.h>
28 # include  <limits.h>
29 
30 # include  <sys/ioctl.h>
31 
32 # include  <usb.h>
33 
34 # include "ezusb.h"
35 
36 static int ezusb_libusb_debug = 0;
37 #define DEBUG(...) do {					\
38       if (ezusb_libusb_debug) {				\
39 	  printf("%s(%d): ", __func__, __LINE__);	\
40 	  printf(__VA_ARGS__);				\
41 	  printf("\n");					\
42       }							\
43 } while (0)
44 
45 /*
46  * Issue a control request to the specified device.
47  * This is O/S specific ...
48  */
ctrl_msg_libusb(struct ezusb_backend * backend,unsigned char requestType,unsigned char request,unsigned short value,unsigned short index,unsigned char * data,size_t length)49 int ctrl_msg_libusb (
50     struct ezusb_backend		*backend,
51     unsigned char			requestType,
52     unsigned char			request,
53     unsigned short			value,
54     unsigned short			index,
55     unsigned char			*data,
56     size_t				length
57 ) {
58     usb_dev_handle *device;
59     int error;
60 
61     assert(backend != NULL && "internal error: no backend");
62     assert(backend->priv_data != NULL && "no private data!");
63 
64     device = backend->priv_data;
65     if (requestType == EZUSB_INPUT)
66 	requestType = USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
67     else if (requestType == EZUSB_OUTPUT)
68 	requestType = USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
69 
70     error = usb_control_msg(device, (int)requestType, (int)request,
71         (int)value, (int)index, (char*)data, (int)length, 10000);
72     if (error < 0)
73         logerror("problem with usb_control_msg(), returned %d, errno=%d\n",
74 	    error, errno);
75     return error;
76 }
77 
ezusb_libusb_open(struct ezusb_backend * be,const char * device,int mode)78 int ezusb_libusb_open(struct ezusb_backend *be, const char *device, int mode)
79 {
80       struct usb_bus *bus = NULL;
81       struct usb_device *dev = NULL;
82       struct usb_device *found_dev = NULL;
83       usb_dev_handle *devhandle = NULL;
84       int ret = 0;
85       unsigned int vid, pid;
86 
87       /*
88        * For this backend, format for device is "vid=<VID>,pid=<PID>"
89        */
90       ret = sscanf(device, "vid=%x,pid=%x", &vid, &pid);
91       if (ret != 2)
92           ret = sscanf(device, "pid=%x,vid=%x", &pid, &vid);
93       if (ret != 2) {
94           logerror("wrong format; expected 'vid=<VID>,pid=<PID>' but got"
95               " '%s'\n", device);
96 	  return -EINVAL;
97       }
98 
99       usb_init();
100       usb_set_debug(0);
101       usb_find_busses();
102       usb_find_devices();
103       for (bus = usb_get_busses(); bus; bus = bus->next) {
104            for (dev = bus->devices; dev; dev = dev->next) {
105                 DEBUG("USB device found: vendor: %#x product: %#x",
106                         dev->descriptor.idVendor,
107                         dev->descriptor.idProduct);
108 	        if (dev->descriptor.idProduct == pid &&
109 		    dev->descriptor.idVendor == vid) {
110 		    found_dev = dev;
111 		    break;
112 		}
113            }
114       }
115       if (found_dev == NULL) {
116           logerror("no device found");
117 	  return -ENOENT;
118       }
119 
120       devhandle = usb_open(found_dev);
121       if (devhandle == NULL) {
122           logerror("couldn't open device handler!");
123 	  return -ENXIO;
124       }
125       be->priv_data = devhandle;
126       return (0);
127 }
128 
ezusb_libusb_close(struct ezusb_backend * be)129 int ezusb_libusb_close(struct ezusb_backend *be)
130 {
131       usb_dev_handle *devhandle = NULL;
132       int error;
133 
134       assert(be != NULL && "no backend pointer (NULL)");
135       assert(be->priv_data != NULL && "priv_data can't be NULL here");
136       devhandle = be->priv_data;
137       error = usb_close(devhandle);
138       return error;
139 }
140 
141 struct ezusb_backend ezusb_backend_libusb = {
142       .name = "libusb",
143       .priv_data = NULL,
144       .open = ezusb_libusb_open,
145       .close = ezusb_libusb_close,
146       .ctrl_msg = ctrl_msg_libusb,
147 };
148 
149 #endif /* LIBUSB_SUPPORT */
150