fe63975d |
1 | /* hiddata_libusb01.c |
2 | * Variant for libusb v 0.1 (old simple version, found in many PC Linux distros) |
3 | */ |
4 | |
5 | /* Inspired by hiddata.c|h by Christian Starkjohann |
6629800a |
6 | * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH |
6629800a |
7 | */ |
8 | |
fe63975d |
9 | |
6629800a |
10 | #include "hiddata.h" |
b60fbf7e |
11 | #include <stdio.h> |
12 | #include <string.h> |
28f22397 |
13 | #include <errno.h> |
fe63975d |
14 | #include <usb.h> |
6629800a |
15 | |
16 | #if 0 //ifdef DEBUG |
17 | #define DEBUG_PRINT(arg) printf arg |
18 | #else |
19 | #define DEBUG_PRINT(arg) |
20 | #endif |
21 | |
6629800a |
22 | |
28f22397 |
23 | // USBDEVHANDLE is same as struct usb_device * |
24 | // Open handles are stored in struct usb_device (HACK! revise for new libusb) |
25 | |
26 | static inline struct usb_device * usbDevStruct(USBDEVHANDLE usbh) { |
27 | return (struct usb_device *)usbh; |
28 | } |
29 | |
30 | static inline usb_dev_handle * usbDevHandle(USBDEVHANDLE usbh) { |
31 | return (usb_dev_handle *)(usbDevStruct(usbh)->children); |
32 | } |
33 | |
34 | // TO DO: for devices that prepend report ID, implement this somehow |
35 | static inline int usesReportIDs(USBDEVHANDLE usbh) { |
36 | /* return 1 if 1st byte of get/set report buffer is report ID */ |
37 | return 0; |
38 | } |
6629800a |
39 | |
40 | /* ------------------------------------------------------------------------- */ |
41 | |
42 | #define USBRQ_HID_GET_REPORT 0x01 |
43 | #define USBRQ_HID_SET_REPORT 0x09 |
6629800a |
44 | #define USB_HID_REPORT_TYPE_FEATURE 3 |
45 | |
28f22397 |
46 | #define A_REPORT_REQUEST_TIMEOUT 5000 /* in milliseconds */ |
6629800a |
47 | |
48 | /* ------------------------------------------------------------------------- */ |
49 | |
28f22397 |
50 | int usbhidEnumDevices(int vendor, int product, |
51 | void *context, |
52 | int (*usbhidEnumFunc)(USBDEVHANDLE usbh, void *ctx)) |
6629800a |
53 | |
6629800a |
54 | { |
28f22397 |
55 | struct usb_bus *bus; |
56 | struct usb_device *dev; |
57 | usb_dev_handle *handle = NULL; |
58 | int errorCode = USBOPEN_ERR_NOTFOUND; |
59 | static int didUsbInit = 0; |
6629800a |
60 | |
61 | if(!didUsbInit){ |
62 | usb_init(); |
63 | didUsbInit = 1; |
64 | } |
65 | usb_find_busses(); |
66 | usb_find_devices(); |
28f22397 |
67 | for (bus=usb_get_busses(); bus; bus=bus->next) { |
68 | for (dev=bus->devices; dev; dev=dev->next) { |
69 | if (dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product) { |
6629800a |
70 | handle = usb_open(dev); /* we need to open the device in order to query strings */ |
28f22397 |
71 | if ( !handle ) { |
6629800a |
72 | errorCode = USBOPEN_ERR_ACCESS; |
73 | fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror()); |
74 | continue; |
75 | } |
28f22397 |
76 | |
77 | errorCode = 0; |
78 | |
79 | // printf("Probing: [%s] nc=%u %p\n", dev->filename, dev->num_children, dev->children); |
80 | // Assume our devices are leaf, so we can use dev->children to store the handle |
81 | if ( dev->children ) { |
82 | fprintf(stderr, "ERROR: assertion failed for usb dev %p\n", dev); |
83 | usb_close(handle); |
84 | handle = NULL; |
85 | continue; |
6629800a |
86 | } |
28f22397 |
87 | |
88 | dev->children = (void*)handle; |
89 | if ( 0 == usbhidEnumFunc((void*)dev, context) ) |
90 | { |
91 | break; /* stop enumeration */ |
6629800a |
92 | } |
28f22397 |
93 | |
94 | /* Now the handle is owned by the callback */ |
95 | handle = 0; |
6629800a |
96 | } |
97 | } |
6629800a |
98 | } |
28f22397 |
99 | |
6629800a |
100 | return errorCode; |
101 | } |
102 | |
103 | /* ------------------------------------------------------------------------- */ |
104 | |
28f22397 |
105 | void usbhidCloseDevice(USBDEVHANDLE usbh) |
6629800a |
106 | { |
28f22397 |
107 | if (usbh != NULL) { |
108 | usb_close(usbDevHandle(usbh)); |
109 | usbDevStruct(usbh)->children = NULL; |
110 | } |
6629800a |
111 | } |
112 | |
113 | /* ------------------------------------------------------------------------- */ |
114 | |
28f22397 |
115 | static int usbhidGetStringAscii(struct usb_dev_handle *dev, int index, char *buf, int buflen) |
116 | { |
117 | int rval; |
118 | if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ |
119 | return rval; |
120 | if (errno == EPERM) |
121 | fprintf(stderr, "usbhid: Access denied to USB device. Run as root or adjust device permissions.\n"); |
122 | else |
123 | fprintf(stderr, "usbhid: %s error %s\n", __FUNCTION__, usb_strerror()); |
124 | return -1; |
125 | } |
126 | |
127 | int usbhidGetVendorString(USBDEVHANDLE usbh, char *buffer, int len) |
128 | { |
129 | int len2 = usbhidGetStringAscii(usbDevHandle(usbh), usbDevStruct(usbh)->descriptor.iManufacturer, buffer, len); |
130 | if (len2 < 0) { |
131 | fprintf(stderr, "Warning: cannot query vendor for device\n"); |
132 | return USBOPEN_ERR_IO; |
133 | } |
134 | return 0; |
135 | } |
136 | |
137 | int usbhidGetProductString(USBDEVHANDLE usbh, char *buffer, int len) |
138 | { |
139 | int len2 = usbhidGetStringAscii(usbDevHandle(usbh), usbDevStruct(usbh)->descriptor.iProduct, buffer, len); |
140 | if (len2 < 0) { |
141 | fprintf(stderr, "Warning: cannot query product for device\n"); |
142 | return USBOPEN_ERR_IO; |
143 | } |
144 | return 0; |
145 | } |
146 | |
147 | |
148 | |
149 | |
150 | int usbhidSetReport(USBDEVHANDLE usbh, char *buffer, int len) |
6629800a |
151 | { |
28f22397 |
152 | int bytesSent, reportId = buffer[0]; |
6629800a |
153 | |
28f22397 |
154 | if ( !usesReportIDs(usbh) ) { |
6629800a |
155 | buffer++; /* skip dummy report ID */ |
156 | len--; |
157 | } |
28f22397 |
158 | bytesSent = usb_control_msg(usbDevHandle(usbh), |
159 | USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | (reportId & 0xff), |
160 | 0, buffer, len, A_REPORT_REQUEST_TIMEOUT); |
161 | if (bytesSent != len) { |
162 | if (bytesSent < 0) |
6629800a |
163 | fprintf(stderr, "Error sending message: %s\n", usb_strerror()); |
164 | return USBOPEN_ERR_IO; |
165 | } |
166 | return 0; |
167 | } |
168 | |
169 | /* ------------------------------------------------------------------------- */ |
170 | |
28f22397 |
171 | int usbhidGetReport(USBDEVHANDLE usbh, int reportNumber, char *buffer, int *len) |
6629800a |
172 | { |
173 | int bytesReceived, maxLen = *len; |
174 | |
28f22397 |
175 | if (!usesReportIDs(usbh)) { |
6629800a |
176 | buffer++; /* make room for dummy report ID */ |
177 | maxLen--; |
178 | } |
28f22397 |
179 | bytesReceived = usb_control_msg(usbDevHandle(usbh), |
180 | USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | reportNumber, |
181 | 0, buffer, maxLen, A_REPORT_REQUEST_TIMEOUT); |
6629800a |
182 | if(bytesReceived < 0){ |
183 | fprintf(stderr, "Error sending message: %s\n", usb_strerror()); |
184 | return USBOPEN_ERR_IO; |
185 | } |
186 | *len = bytesReceived; |
28f22397 |
187 | if (!usesReportIDs(usbh)) { |
6629800a |
188 | buffer[-1] = reportNumber; /* add dummy report ID */ |
189 | (*len)++; |
190 | } |
191 | return 0; |
192 | } |
193 | |
28f22397 |
194 | |
195 | void usbhidSetUsesReportId(USBDEVHANDLE usbh) |
196 | { |
197 | //TODO Implement if some devices prepend report IDs |
fe63975d |
198 | //This differs among several versions of Linux HID libraries... |
28f22397 |
199 | } |
200 | |
728ea86e |
201 | int usbhidStrerror_r( int err, char *buf, int len) |
202 | { |
203 | const char *s; |
204 | switch (err) { |
205 | case USBHID_ERR_ACCESS: s = "Access to device denied"; |
206 | case USBHID_ERR_NOTFOUND: s = "The specified device was not found"; |
207 | case USBHID_ERR_IO: s = "Communication error with device"; |
208 | case USBHID_ERR_IO_HID: s = "HID I/O error with device"; |
209 | default: |
210 | s = ""; |
211 | } |
212 | |
213 | return snprintf(buf, len, "%s", s); |
214 | } |