diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-02-04 00:18:51 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2014-02-10 23:14:25 +0100 |
commit | 0e0c610df0d3d4044d0b21ddc1752a5dacd7f86e (patch) | |
tree | aca4cf3c5dd86384ee8018d9049e2c3469d597ea /utils/regtools/qeditor/backend.cpp | |
parent | 81dfed27cf7ca1008b9cf21c084310eaeae082ac (diff) | |
download | rockbox-0e0c610df0d3d4044d0b21ddc1752a5dacd7f86e.tar.gz rockbox-0e0c610df0d3d4044d0b21ddc1752a5dacd7f86e.zip |
utils/regtools: make qeditor able to poke directly at a hwstub device
This commit add the very handy feature of being able to read registers
directly from a device using hwstub. This is mostly trivial using the hwstub
library and the biggest change here is actually:
- being able to read registers by name and/or addresses
- being able to enumerate devives
The UI code currently doesn't handle hotplug but the backend does so it should
be trivial to add in the future. It also opens up the possibility the write
registers from hwstub or save the register values to a file.
Since it relies on both hwstub and libusb, a switch has been introduced in
qmake to disable it (use -config nohwstub).
Change-Id: I5d7d7a2a7c97ecd7407227357c8553c2773ea6cc
Diffstat (limited to 'utils/regtools/qeditor/backend.cpp')
-rw-r--r-- | utils/regtools/qeditor/backend.cpp | 317 |
1 files changed, 290 insertions, 27 deletions
diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp index e011965bd2..d2b75be701 100644 --- a/utils/regtools/qeditor/backend.cpp +++ b/utils/regtools/qeditor/backend.cpp | |||
@@ -3,6 +3,10 @@ | |||
3 | #include <QDebug> | 3 | #include <QDebug> |
4 | #include "backend.h" | 4 | #include "backend.h" |
5 | 5 | ||
6 | /** | ||
7 | * Backend | ||
8 | */ | ||
9 | |||
6 | Backend::Backend() | 10 | Backend::Backend() |
7 | { | 11 | { |
8 | } | 12 | } |
@@ -43,9 +47,16 @@ IoBackend *Backend::CreateDummyIoBackend() | |||
43 | return new DummyIoBackend(); | 47 | return new DummyIoBackend(); |
44 | } | 48 | } |
45 | 49 | ||
46 | IoBackend::IoBackend() | 50 | #ifdef HAVE_HWSTUB |
51 | IoBackend *Backend::CreateHWStubIoBackend(HWStubDevice *dev) | ||
47 | { | 52 | { |
53 | return new HWStubIoBackend(dev); | ||
48 | } | 54 | } |
55 | #endif | ||
56 | |||
57 | /** | ||
58 | * FileIoBackend | ||
59 | */ | ||
49 | 60 | ||
50 | FileIoBackend::FileIoBackend(const QString& filename) | 61 | FileIoBackend::FileIoBackend(const QString& filename) |
51 | { | 62 | { |
@@ -91,27 +102,230 @@ bool FileIoBackend::Reload() | |||
91 | return true; | 102 | return true; |
92 | } | 103 | } |
93 | 104 | ||
94 | DummyIoBackend::DummyIoBackend() | 105 | #ifdef HAVE_HWSTUB |
106 | /** | ||
107 | * HWStubDevice | ||
108 | */ | ||
109 | HWStubDevice::HWStubDevice(struct libusb_device *dev) | ||
95 | { | 110 | { |
111 | libusb_ref_device(dev); | ||
112 | m_dev = dev; | ||
113 | m_handle = 0; | ||
114 | m_hwdev = 0; | ||
115 | m_valid = Probe(); | ||
96 | } | 116 | } |
97 | 117 | ||
98 | QString DummyIoBackend::GetSocName() | 118 | HWStubDevice::~HWStubDevice() |
99 | { | 119 | { |
100 | return ""; | 120 | Close(); |
121 | libusb_unref_device(m_dev); | ||
101 | } | 122 | } |
102 | 123 | ||
103 | bool DummyIoBackend::ReadRegister(const QString& name, soc_word_t& value) | 124 | int HWStubDevice::GetBusNumber() |
104 | { | 125 | { |
105 | (void) name; | 126 | return libusb_get_bus_number(m_dev); |
106 | (void) value; | 127 | } |
128 | |||
129 | int HWStubDevice::GetDevAddress() | ||
130 | { | ||
131 | return libusb_get_device_address(m_dev); | ||
132 | } | ||
133 | |||
134 | bool HWStubDevice::Probe() | ||
135 | { | ||
136 | struct libusb_device_descriptor desc; | ||
137 | if(libusb_get_device_descriptor(m_dev, &desc)) | ||
138 | return false; | ||
139 | if(desc.idVendor != HWSTUB_USB_VID || desc.idProduct != HWSTUB_USB_PID) | ||
140 | return false; | ||
141 | if(!Open()) | ||
142 | return false; | ||
143 | int ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_VERSION, &m_hwdev_ver, sizeof(m_hwdev_ver)); | ||
144 | if(ret != sizeof(m_hwdev_ver)) | ||
145 | goto Lerr; | ||
146 | if(m_hwdev_ver.bMajor != HWSTUB_VERSION_MAJOR || m_hwdev_ver.bMinor < HWSTUB_VERSION_MINOR) | ||
147 | goto Lerr; | ||
148 | // get target | ||
149 | ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_TARGET, &m_hwdev_target, sizeof(m_hwdev_target)); | ||
150 | if(ret != sizeof(m_hwdev_target)) | ||
151 | goto Lerr; | ||
152 | // get STMP information | ||
153 | if(m_hwdev_target.dID == HWSTUB_TARGET_STMP) | ||
154 | { | ||
155 | ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_STMP, &m_hwdev_stmp, sizeof(m_hwdev_stmp)); | ||
156 | if(ret != sizeof(m_hwdev_stmp)) | ||
157 | goto Lerr; | ||
158 | } | ||
159 | Close(); | ||
160 | return true; | ||
161 | |||
162 | Lerr: | ||
163 | Close(); | ||
107 | return false; | 164 | return false; |
108 | } | 165 | } |
109 | 166 | ||
110 | bool DummyIoBackend::Reload() | 167 | bool HWStubDevice::Open() |
168 | { | ||
169 | if(libusb_open(m_dev, &m_handle)) | ||
170 | return false; | ||
171 | m_hwdev = hwstub_open(m_handle); | ||
172 | if(m_hwdev == 0) | ||
173 | { | ||
174 | libusb_close(m_handle); | ||
175 | return false; | ||
176 | } | ||
177 | return true; | ||
178 | } | ||
179 | |||
180 | void HWStubDevice::Close() | ||
181 | { | ||
182 | if(m_hwdev) | ||
183 | hwstub_release(m_hwdev); | ||
184 | m_hwdev = 0; | ||
185 | if(m_handle) | ||
186 | libusb_close(m_handle); | ||
187 | m_handle = 0; | ||
188 | } | ||
189 | |||
190 | bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer) | ||
191 | { | ||
192 | if(!m_hwdev) | ||
193 | return false; | ||
194 | int ret = hwstub_rw_mem(m_hwdev, 1, addr, buffer, length); | ||
195 | return ret >= 0 && (size_t)ret == length; | ||
196 | } | ||
197 | |||
198 | bool HWStubDevice::IsValid() | ||
199 | { | ||
200 | return m_valid; | ||
201 | } | ||
202 | |||
203 | |||
204 | /** | ||
205 | * HWStubIoBackend | ||
206 | */ | ||
207 | |||
208 | HWStubIoBackend::HWStubIoBackend(HWStubDevice *dev) | ||
209 | { | ||
210 | m_dev = dev; | ||
211 | m_dev->Open(); | ||
212 | struct hwstub_target_desc_t target = m_dev->GetTargetInfo(); | ||
213 | if(target.dID == HWSTUB_TARGET_STMP) | ||
214 | { | ||
215 | struct hwstub_stmp_desc_t stmp = m_dev->GetSTMPInfo(); | ||
216 | if(stmp.wChipID == 0x3780) | ||
217 | m_soc = "imx233"; | ||
218 | else if(stmp.wChipID >= 0x3700 && stmp.wChipID < 0x3780) | ||
219 | m_soc = "stmp3700"; | ||
220 | else if(stmp.wChipID >= 0x3600 && stmp.wChipID < 0x3700) | ||
221 | m_soc = "stmp3600"; | ||
222 | else | ||
223 | m_soc = QString("stmp%1").arg(stmp.wChipID, 4, 16, QChar('0')); | ||
224 | } | ||
225 | else if(target.dID == HWSTUB_TARGET_RK27) | ||
226 | m_soc = "rk27x"; | ||
227 | else | ||
228 | m_soc = target.bName; | ||
229 | } | ||
230 | |||
231 | QString HWStubIoBackend::GetSocName() | ||
232 | { | ||
233 | return m_soc; | ||
234 | } | ||
235 | |||
236 | HWStubIoBackend::~HWStubIoBackend() | ||
237 | { | ||
238 | m_dev->Close(); | ||
239 | } | ||
240 | |||
241 | bool HWStubIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value) | ||
242 | { | ||
243 | return m_dev->ReadMem(addr, sizeof(value), &value); | ||
244 | } | ||
245 | |||
246 | bool HWStubIoBackend::Reload() | ||
111 | { | 247 | { |
112 | return true; | 248 | return true; |
113 | } | 249 | } |
114 | 250 | ||
251 | /** | ||
252 | * HWStubBackendHelper | ||
253 | */ | ||
254 | HWStubBackendHelper::HWStubBackendHelper() | ||
255 | { | ||
256 | libusb_init(NULL); | ||
257 | #ifdef LIBUSB_NO_HOTPLUG | ||
258 | m_hotplug = false; | ||
259 | #else | ||
260 | m_hotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG); | ||
261 | if(m_hotplug) | ||
262 | { | ||
263 | m_hotplug = LIBUSB_SUCCESS == libusb_hotplug_register_callback( | ||
264 | NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, | ||
265 | LIBUSB_HOTPLUG_ENUMERATE, HWSTUB_USB_VID, HWSTUB_USB_PID, HWSTUB_CLASS, | ||
266 | &HWStubBackendHelper::HotPlugCallback, reinterpret_cast< void* >(this), &m_hotplug_handle); | ||
267 | } | ||
268 | #endif | ||
269 | } | ||
270 | |||
271 | HWStubBackendHelper::~HWStubBackendHelper() | ||
272 | { | ||
273 | #ifndef LIBUSB_NO_HOTPLUG | ||
274 | if(m_hotplug) | ||
275 | libusb_hotplug_deregister_callback(NULL, m_hotplug_handle); | ||
276 | #endif | ||
277 | } | ||
278 | |||
279 | QList< HWStubDevice* > HWStubBackendHelper::GetDevList() | ||
280 | { | ||
281 | QList< HWStubDevice* > list; | ||
282 | libusb_device **dev_list; | ||
283 | ssize_t cnt = libusb_get_device_list(NULL, &dev_list); | ||
284 | for(int i = 0; i < cnt; i++) | ||
285 | { | ||
286 | HWStubDevice *dev = new HWStubDevice(dev_list[i]); | ||
287 | /* filter out non-hwstub devices */ | ||
288 | if(dev->IsValid()) | ||
289 | list.push_back(dev); | ||
290 | else | ||
291 | delete dev; | ||
292 | } | ||
293 | libusb_free_device_list(dev_list, 1); | ||
294 | return list; | ||
295 | } | ||
296 | |||
297 | #ifndef LIBUSB_NO_HOTPLUG | ||
298 | void HWStubBackendHelper::OnHotPlug(bool arrived, struct libusb_device *dev) | ||
299 | { | ||
300 | /* signal it */ | ||
301 | emit OnDevListChanged(arrived, dev); | ||
302 | } | ||
303 | |||
304 | int HWStubBackendHelper::HotPlugCallback(struct libusb_context *ctx, struct libusb_device *dev, | ||
305 | libusb_hotplug_event event, void *user_data) | ||
306 | { | ||
307 | HWStubBackendHelper *helper = reinterpret_cast< HWStubBackendHelper* >(user_data); | ||
308 | switch(event) | ||
309 | { | ||
310 | case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: helper->OnHotPlug(true, dev); break; | ||
311 | case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: helper->OnHotPlug(false, dev); break; | ||
312 | default: break; | ||
313 | } | ||
314 | return 0; | ||
315 | } | ||
316 | #endif | ||
317 | |||
318 | bool HWStubBackendHelper::HasHotPlugSupport() | ||
319 | { | ||
320 | return m_hotplug; | ||
321 | } | ||
322 | |||
323 | #endif | ||
324 | |||
325 | /** | ||
326 | * BackendHelper | ||
327 | */ | ||
328 | |||
115 | BackendHelper::BackendHelper(IoBackend *io_backend, const soc_t& soc) | 329 | BackendHelper::BackendHelper(IoBackend *io_backend, const soc_t& soc) |
116 | :m_io_backend(io_backend), m_soc(soc) | 330 | :m_io_backend(io_backend), m_soc(soc) |
117 | { | 331 | { |
@@ -119,38 +333,87 @@ BackendHelper::BackendHelper(IoBackend *io_backend, const soc_t& soc) | |||
119 | 333 | ||
120 | bool BackendHelper::ReadRegister(const QString& dev, const QString& reg, soc_word_t& v) | 334 | bool BackendHelper::ReadRegister(const QString& dev, const QString& reg, soc_word_t& v) |
121 | { | 335 | { |
122 | return m_io_backend->ReadRegister("HW." + dev + "." + reg, v); | 336 | if(m_io_backend->SupportAccess(IoBackend::ByName)) |
337 | return m_io_backend->ReadRegister("HW." + dev + "." + reg, v); | ||
338 | if(m_io_backend->SupportAccess(IoBackend::ByAddress)) | ||
339 | { | ||
340 | soc_addr_t addr; | ||
341 | if(GetRegisterAddress(dev, reg, addr)) | ||
342 | return m_io_backend->ReadRegister(addr, v); | ||
343 | } | ||
344 | return false; | ||
123 | } | 345 | } |
124 | 346 | ||
125 | bool BackendHelper::ReadRegisterField(const QString& dev, const QString& reg, | 347 | |
126 | const QString& field, soc_word_t& v) | 348 | bool BackendHelper::GetDeviceDesc(const QString& dev, soc_dev_t& dev_desc, size_t& index) |
127 | { | 349 | { |
128 | soc_dev_t *sdev = 0; | ||
129 | for(size_t i = 0; i < m_soc.dev.size(); i++) | 350 | for(size_t i = 0; i < m_soc.dev.size(); i++) |
130 | { | 351 | { |
131 | for(size_t j = 0; j < m_soc.dev[i].addr.size(); j++) | 352 | for(size_t j = 0; j < m_soc.dev[i].addr.size(); j++) |
132 | if(m_soc.dev[i].addr[j].name.c_str() == dev) | 353 | if(m_soc.dev[i].addr[j].name.c_str() == dev) |
133 | sdev = &m_soc.dev[i]; | 354 | { |
355 | dev_desc = m_soc.dev[i]; | ||
356 | index = j; | ||
357 | return true; | ||
358 | } | ||
134 | } | 359 | } |
135 | if(sdev == 0) | 360 | return false; |
136 | return false; | 361 | } |
137 | soc_reg_t *sreg = 0; | 362 | |
138 | for(size_t i = 0; i < sdev->reg.size(); i++) | 363 | bool BackendHelper::GetRegisterDesc(const soc_dev_t& dev, const QString& reg, |
364 | soc_reg_t& reg_desc, size_t& index) | ||
365 | { | ||
366 | for(size_t i = 0; i < dev.reg.size(); i++) | ||
139 | { | 367 | { |
140 | for(size_t j = 0; j < sdev->reg[i].addr.size(); j++) | 368 | for(size_t j = 0; j < dev.reg[i].addr.size(); j++) |
141 | if(sdev->reg[i].addr[j].name.c_str() == reg) | 369 | if(dev.reg[i].addr[j].name.c_str() == reg) |
142 | sreg = &sdev->reg[i]; | 370 | { |
371 | index = j; | ||
372 | reg_desc = dev.reg[i]; | ||
373 | return true; | ||
374 | } | ||
143 | } | 375 | } |
144 | if(sreg == 0) | 376 | return false; |
377 | } | ||
378 | |||
379 | bool BackendHelper::GetFieldDesc(const soc_reg_t& reg_desc, const QString& field, | ||
380 | soc_reg_field_t& field_desc) | ||
381 | { | ||
382 | for(size_t i = 0; i < reg_desc.field.size(); i++) | ||
383 | if(reg_desc.field[i].name.c_str() == field) | ||
384 | field_desc = reg_desc.field[i]; | ||
385 | return false; | ||
386 | } | ||
387 | |||
388 | bool BackendHelper::GetRegisterAddress(const QString& dev, const QString& reg, | ||
389 | soc_addr_t& addr) | ||
390 | { | ||
391 | size_t dev_index, reg_index; | ||
392 | soc_dev_t dev_desc; | ||
393 | soc_reg_t reg_desc; | ||
394 | if(!GetDeviceDesc(dev, dev_desc, dev_index)) | ||
395 | return false; | ||
396 | if(!GetRegisterDesc(dev_desc, reg, reg_desc, reg_index)) | ||
397 | return false; | ||
398 | addr = dev_desc.addr[dev_index].addr + reg_desc.addr[reg_index].addr; | ||
399 | return true; | ||
400 | } | ||
401 | |||
402 | bool BackendHelper::ReadRegisterField(const QString& dev, const QString& reg, | ||
403 | const QString& field, soc_word_t& v) | ||
404 | { | ||
405 | size_t dev_index, reg_index; | ||
406 | soc_dev_t dev_desc; | ||
407 | soc_reg_t reg_desc; | ||
408 | soc_reg_field_t field_desc; | ||
409 | if(!GetDeviceDesc(dev, dev_desc, dev_index)) | ||
410 | return false; | ||
411 | if(!GetRegisterDesc(dev_desc, reg, reg_desc, reg_index)) | ||
145 | return false; | 412 | return false; |
146 | soc_reg_field_t *sfield = 0; | 413 | if(!GetFieldDesc(reg_desc, field, field_desc)) |
147 | for(size_t i = 0; i < sreg->field.size(); i++) | ||
148 | if(sreg->field[i].name.c_str() == field) | ||
149 | sfield = &sreg->field[i]; | ||
150 | if(sfield == 0) | ||
151 | return false; | 414 | return false; |
152 | if(!ReadRegister(dev, reg, v)) | 415 | if(!ReadRegister(dev, reg, v)) |
153 | return false; | 416 | return false; |
154 | v = (v & sfield->bitmask()) >> sfield->first_bit; | 417 | v = (v & field_desc.bitmask()) >> field_desc.first_bit; |
155 | return true; | 418 | return true; |
156 | } \ No newline at end of file | 419 | } \ No newline at end of file |