1 /*
2 * vim:tw=80:ai:tabstop=4:softtabstop=4:shiftwidth=4:expandtab
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * (C) Copyright Kevin Timmerman 2007
19 * (C) Copyright Phil Dibowitz 2007
20 */
21
22 #include "lc_internal.h"
23 #include "libconcord.h"
24
25 #ifdef WANT_HIDAPI
26 #ifndef LC_LIBHIDAPI
27 #define LC_LIBHIDAPI
28
29 #include "hid.h"
30 #include <hidapi/hidapi.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 /*
36 * Harmonies either fall under logitech's VendorID (0x046d), and logitech's
37 * productID range for Harmonies (0xc110 - 0xc14f)...
38 *
39 * OR, they fall under 0x400/0xc359 (older 7-series, all 6-series).
40 */
41 #define LOGITECH_VID 0x046D
42 #define LOGITECH_MIN_PID 0xc110
43 #define LOGITECH_MAX_PID 0xc14f
44 #define NATIONAL_VID 0x0400
45 #define NATIONAL_PID 0xc359
46
47 #define USB_PACKET_LENGTH 64
48
49 hid_device *h_dev;
50
InitUSB()51 int InitUSB()
52 {
53 hid_init();
54 /*
55 * Note we do NOT call hid_exit() in ShutdownUSB, because you can
56 * never reinitialize libhidapi - and on a reset, we need
57 * to come back and do more stuff. So we set it up as an atexit()
58 */
59 atexit((void(*)())hid_exit);
60 return 0;
61 }
62
ShutdownUSB()63 void ShutdownUSB()
64 {
65 if (h_dev) {
66 hid_close(h_dev);
67 }
68 }
69
is_harmony(struct hid_device_info * dev)70 bool is_harmony(struct hid_device_info *dev)
71 {
72 /* IF vendor == logitech AND product is in range of harmony
73 * OR vendor == National Semiconductor and product is harmony
74 */
75 if ((dev->vendor_id == LOGITECH_VID
76 && (dev->product_id >= LOGITECH_MIN_PID
77 && dev->product_id <= LOGITECH_MAX_PID))
78 || (dev->vendor_id == NATIONAL_VID
79 && dev->product_id == NATIONAL_PID)) {
80 return true;
81 }
82 return false;
83 }
84
85 /*
86 * Find a HID device that is a Harmony
87 */
FindRemote(THIDINFO & hid_info)88 int FindRemote(THIDINFO &hid_info)
89 {
90 struct hid_device_info *devs, *cur_dev;
91 bool found = false;
92 devs = hid_enumerate(0x0, 0x0);
93 cur_dev = devs;
94 while (cur_dev) {
95 debug("Testing: %04X, %04X", cur_dev->vendor_id, cur_dev->product_id);
96 if (is_harmony(cur_dev)) {
97 debug("Found a Harmony!");
98 hid_info.vid = cur_dev->vendor_id;
99 hid_info.pid = cur_dev->product_id;
100 hid_info.ver = cur_dev->release_number;
101 h_dev = hid_open(cur_dev->vendor_id, cur_dev->product_id, NULL);
102 found = true;
103 break;
104 }
105 cur_dev = cur_dev->next;
106 }
107 hid_free_enumeration(devs);
108 if (!found || !h_dev) {
109 debug("Failed to establish communication with remote");
110 return LC_ERROR_CONNECT;
111 }
112
113 // Fill in hid_info
114 const size_t buf_len = 128;
115 wchar_t wide_s[buf_len];
116 char s[buf_len];
117 hid_get_manufacturer_string(h_dev, wide_s, buf_len);
118 wcstombs(s, wide_s, buf_len);
119 hid_info.mfg = s;
120 hid_get_product_string(h_dev, wide_s, buf_len);
121 wcstombs(s, wide_s, buf_len);
122 hid_info.prod = s;
123
124 return 0;
125 }
126
HID_WriteReport(const uint8_t * data)127 int HID_WriteReport(const uint8_t *data)
128 {
129 uint8_t newdata[USB_PACKET_LENGTH+1];
130 newdata[0] = 0x00;
131 memcpy(&newdata[1], data, USB_PACKET_LENGTH);
132 int err = hid_write(h_dev, newdata, USB_PACKET_LENGTH + 1);
133 if (err < 0) {
134 debug("Failed to write to device: %d (%ls)", err, hid_error(h_dev));
135 return err;
136 }
137
138 return 0;
139 }
140
HID_ReadReport(uint8_t * data,unsigned int timeout)141 int HID_ReadReport(uint8_t *data, unsigned int timeout)
142 {
143 int err = hid_read_timeout(h_dev, data, USB_PACKET_LENGTH, timeout);
144 if (err < 0) {
145 debug("Failed to read from device: %d (%ls)", err, hid_error(h_dev));
146 return err;
147 } else if (err == 0) {
148 debug("USB read timed out");
149 return 1;
150 }
151
152 return 0;
153 }
154
155 #endif
156 #endif
157