Added OS X, split hiddata.c files
[usb-relay-hid.git] / commandline / hiddata_libusb01.c
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
6 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
7 */
8
9
10 #include "hiddata.h"
11 #include <stdio.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <usb.h>
15
16 #if 0 //ifdef DEBUG
17 #define DEBUG_PRINT(arg) printf arg
18 #else
19 #define DEBUG_PRINT(arg)
20 #endif
21
22
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 }
39
40 /* ------------------------------------------------------------------------- */
41
42 #define USBRQ_HID_GET_REPORT 0x01
43 #define USBRQ_HID_SET_REPORT 0x09
44 #define USB_HID_REPORT_TYPE_FEATURE 3
45
46 #define A_REPORT_REQUEST_TIMEOUT 5000 /* in milliseconds */
47
48 /* ------------------------------------------------------------------------- */
49
50 int usbhidEnumDevices(int vendor, int product,
51 void *context,
52 int (*usbhidEnumFunc)(USBDEVHANDLE usbh, void *ctx))
53
54 {
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;
60
61 if(!didUsbInit){
62 usb_init();
63 didUsbInit = 1;
64 }
65 usb_find_busses();
66 usb_find_devices();
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) {
70 handle = usb_open(dev); /* we need to open the device in order to query strings */
71 if ( !handle ) {
72 errorCode = USBOPEN_ERR_ACCESS;
73 fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror());
74 continue;
75 }
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;
86 }
87
88 dev->children = (void*)handle;
89 if ( 0 == usbhidEnumFunc((void*)dev, context) )
90 {
91 break; /* stop enumeration */
92 }
93
94 /* Now the handle is owned by the callback */
95 handle = 0;
96 }
97 }
98 }
99
100 return errorCode;
101 }
102
103 /* ------------------------------------------------------------------------- */
104
105 void usbhidCloseDevice(USBDEVHANDLE usbh)
106 {
107 if (usbh != NULL) {
108 usb_close(usbDevHandle(usbh));
109 usbDevStruct(usbh)->children = NULL;
110 }
111 }
112
113 /* ------------------------------------------------------------------------- */
114
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)
151 {
152 int bytesSent, reportId = buffer[0];
153
154 if ( !usesReportIDs(usbh) ) {
155 buffer++; /* skip dummy report ID */
156 len--;
157 }
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)
163 fprintf(stderr, "Error sending message: %s\n", usb_strerror());
164 return USBOPEN_ERR_IO;
165 }
166 return 0;
167 }
168
169 /* ------------------------------------------------------------------------- */
170
171 int usbhidGetReport(USBDEVHANDLE usbh, int reportNumber, char *buffer, int *len)
172 {
173 int bytesReceived, maxLen = *len;
174
175 if (!usesReportIDs(usbh)) {
176 buffer++; /* make room for dummy report ID */
177 maxLen--;
178 }
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);
182 if(bytesReceived < 0){
183 fprintf(stderr, "Error sending message: %s\n", usb_strerror());
184 return USBOPEN_ERR_IO;
185 }
186 *len = bytesReceived;
187 if (!usesReportIDs(usbh)) {
188 buffer[-1] = reportNumber; /* add dummy report ID */
189 (*len)++;
190 }
191 return 0;
192 }
193
194
195 void usbhidSetUsesReportId(USBDEVHANDLE usbh)
196 {
197 //TODO Implement if some devices prepend report IDs
198 //This differs among several versions of Linux HID libraries...
199 }
200
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 }