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