c5f28894ac084b6030876935376ee6238d893cac
[SCSI2SD-V6.git] / software / bootloaderhost / SCSI2SD_HID.cc
1 //      Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
2 //
3 //      This file is part of SCSI2SD.
4 //
5 //      SCSI2SD is free software: you can redistribute it and/or modify
6 //      it under the terms of the GNU General Public License as published by
7 //      the Free Software Foundation, either version 3 of the License, or
8 //      (at your option) any later version.
9 //
10 //      SCSI2SD 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 SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
17 #include "SCSI2SD_HID.hh"
18
19 #include <cassert>
20 #include <stdexcept>
21 #include <sstream>
22
23 #include <iostream>
24 #include <string.h> // memcpy
25
26 using namespace SCSI2SD;
27
28 HID::HID(hid_device_info* hidInfo) :
29         myHidInfo(hidInfo),
30         myConfigHandle(NULL),
31         myDebugHandle(NULL),
32         myFirmwareVersion(0),
33         mySDCapacity(0)
34 {
35         while (hidInfo)
36         {
37                 if (hidInfo->interface_number == CONFIG_INTERFACE)
38                 {
39                         myConfigHandle = hid_open_path(hidInfo->path);
40                 }
41                 else if (hidInfo->interface_number == DEBUG_INTERFACE)
42                 {
43                         myDebugHandle = hid_open_path(hidInfo->path);
44                         readDebugData();
45                 }
46                 hidInfo = hidInfo->next;
47         }
48 }
49
50 HID::~HID()
51 {
52         if (myConfigHandle)
53         {
54                 hid_close(myConfigHandle);
55         }
56         if (myDebugHandle)
57         {
58                 hid_close(myDebugHandle);
59         }
60
61         hid_free_enumeration(myHidInfo);
62 }
63
64 HID*
65 HID::Open()
66 {
67         hid_device_info* dev = hid_enumerate(VENDOR_ID, PRODUCT_ID);
68         if (dev)
69         {
70                 return new HID(dev);
71         }
72         else
73         {
74                 return NULL;
75         }
76 }
77
78 void
79 HID::enterBootloader()
80 {
81         // Reboot commands added in firmware 3.5
82         if (!myDebugHandle)
83         {
84                 throw std::runtime_error(
85                         "Cannot enter SCSI2SD bootloader: debug interface not found");
86         }
87         else if (myFirmwareVersion == 0)
88         {
89                 throw std::runtime_error(
90                         "Cannot enter SCSI2SD bootloader: old firmware version running.\n"
91                         "The SCSI2SD board cannot reset itself. Please disconnect and \n"
92                         "reconnect the USB cable.\n");
93         }
94         else
95         {
96                 uint8_t hidBuf[HID_PACKET_SIZE + 1] =
97                 {
98                         0x00, // Report ID;
99                         0x01 // Reboot command
100                         // 63 bytes unused.
101                 };
102
103                 int result = hid_write(myDebugHandle, hidBuf, sizeof(hidBuf));
104                 if (result < 0)
105                 {
106                         const wchar_t* err = hid_error(myDebugHandle);
107                         std::stringstream ss;
108                         ss << "USB HID write failure: " << err;
109                         throw std::runtime_error(ss.str());
110                 }
111         }
112 }
113
114 void
115 HID::readConfig(uint8_t* buffer, size_t len)
116 {
117         assert(len >= 0);
118         buffer[0] = 0; // report id
119
120         int result = hid_read(myConfigHandle, buffer, len);
121
122         if (result < 0)
123         {
124                 const wchar_t* err = hid_error(myConfigHandle);
125                 std::stringstream ss;
126                 ss << "USB HID read failure: " << err;
127                 throw std::runtime_error(ss.str());
128         }
129 }
130
131 void
132 HID::saveConfig(uint8_t* buffer, size_t len)
133 {
134         assert(len >= 0 && len <= HID_PACKET_SIZE);
135
136         uint8_t hidBuf[HID_PACKET_SIZE + 1] =
137         {
138                 0x00, // Report ID;
139         };
140         memcpy(&hidBuf[1], buffer, len);
141
142         int result = hid_write(myConfigHandle, hidBuf, len + 1);
143
144         if (result < 0)
145         {
146                 const wchar_t* err = hid_error(myConfigHandle);
147                 std::stringstream ss;
148                 ss << "USB HID write failure: " << err;
149                 throw std::runtime_error(ss.str());
150         }
151
152
153 }
154
155 void
156 HID::readDebugData()
157 {
158         uint8_t buf[HID_PACKET_SIZE];
159         buf[0] = 0; // report id
160         int result = hid_read(myDebugHandle, buf, HID_PACKET_SIZE);
161
162         if (result < 0)
163         {
164                 const wchar_t* err = hid_error(myDebugHandle);
165                 std::stringstream ss;
166                 ss << "USB HID read failure: " << err;
167                 throw std::runtime_error(ss.str());
168         }
169         myFirmwareVersion = (((uint16_t)buf[62]) << 8) | buf[63];
170
171         mySDCapacity =
172                 (((uint32_t)buf[58]) << 24) |
173                 (((uint32_t)buf[59]) << 16) |
174                 (((uint32_t)buf[60]) << 8) |
175                 ((uint32_t)buf[61]);
176 }
177
178 std::string
179 HID::getFirmwareVersionStr() const
180 {
181         if (myFirmwareVersion == 0)
182         {
183                 return "Unknown (3.0 - 3.4)";
184         }
185         else
186         {
187                 std::stringstream ver;
188                 ver << std::hex <<
189                         (myFirmwareVersion >> 8) <<
190                         '.' << (myFirmwareVersion & 0xFF);
191                 return ver.str();
192         }
193 }
194
195