summaryrefslogtreecommitdiff
path: root/utils/hwstub/lib/hwstub_usb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hwstub/lib/hwstub_usb.cpp')
-rw-r--r--utils/hwstub/lib/hwstub_usb.cpp728
1 files changed, 728 insertions, 0 deletions
diff --git a/utils/hwstub/lib/hwstub_usb.cpp b/utils/hwstub/lib/hwstub_usb.cpp
new file mode 100644
index 0000000000..28c64d9df3
--- /dev/null
+++ b/utils/hwstub/lib/hwstub_usb.cpp
@@ -0,0 +1,728 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2015 by Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "hwstub.hpp"
22#include "hwstub_usb.hpp"
23#include <cstring> /* for memcpy */
24
25namespace hwstub {
26namespace usb {
27
28const uint8_t VR_GET_CPU_INFO = 0;
29const uint8_t VR_SET_DATA_ADDRESS = 1;
30const uint8_t VR_SET_DATA_LENGTH = 2;
31const uint8_t VR_FLUSH_CACHES = 3;
32const uint8_t VR_PROGRAM_START1 = 4;
33const uint8_t VR_PROGRAM_START2 = 5;
34
35/**
36 * Context
37 */
38
39context::context(libusb_context *ctx, bool cleanup_ctx)
40 :m_usb_ctx(ctx), m_cleanup_ctx(cleanup_ctx)
41{
42}
43
44context::~context()
45{
46 if(m_cleanup_ctx)
47 libusb_exit(m_usb_ctx);
48}
49
50std::shared_ptr<context> context::create(libusb_context *ctx, bool cleanup_ctx,
51 std::string *error)
52{
53 (void) error;
54 if(ctx == nullptr)
55 libusb_init(nullptr);
56 // NOTE: can't use make_shared() because of the protected ctor */
57 return std::shared_ptr<context>(new context(ctx, cleanup_ctx));
58}
59
60libusb_context *context::native_context()
61{
62 return m_usb_ctx;
63}
64
65libusb_device *context::from_ctx_dev(ctx_dev_t dev)
66{
67 return reinterpret_cast<libusb_device*>(dev);
68}
69
70hwstub::context::ctx_dev_t context::to_ctx_dev(libusb_device *dev)
71{
72 return static_cast<ctx_dev_t>(dev);
73}
74
75error context::fetch_device_list(std::vector<ctx_dev_t>& list, void*& ptr)
76{
77 libusb_device **usb_list;
78 ssize_t ret = libusb_get_device_list(m_usb_ctx, &usb_list);
79 if(ret < 0)
80 return error::ERROR;
81 ptr = (void *)usb_list;
82 list.clear();
83 for(int i = 0; i < ret; i++)
84 if(device::is_hwstub_dev(usb_list[i]))
85 list.push_back(to_ctx_dev(usb_list[i]));
86 return error::SUCCESS;
87}
88
89void context::destroy_device_list(void *ptr)
90{
91 /* remove all references */
92 libusb_free_device_list((libusb_device **)ptr, 1);
93}
94
95error context::create_device(ctx_dev_t dev, std::shared_ptr<hwstub::device>& hwdev)
96{
97 // NOTE: can't use make_shared() because of the protected ctor */
98 hwdev.reset(new device(shared_from_this(), from_ctx_dev(dev)));
99 return error::SUCCESS;
100}
101
102bool context::match_device(ctx_dev_t dev, std::shared_ptr<hwstub::device> hwdev)
103{
104 device *udev = dynamic_cast<device*>(hwdev.get());
105 return udev != nullptr && udev->native_device() == dev;
106}
107
108/**
109 * Device
110 */
111device::device(std::shared_ptr<hwstub::context> ctx, libusb_device *dev)
112 :hwstub::device(ctx), m_dev(dev)
113{
114 libusb_ref_device(dev);
115}
116
117device::~device()
118{
119 libusb_unref_device(m_dev);
120}
121
122libusb_device *device::native_device()
123{
124 return m_dev;
125}
126
127bool device::is_hwstub_dev(libusb_device *dev)
128{
129 struct libusb_device_descriptor dev_desc;
130 struct libusb_config_descriptor *config = nullptr;
131 int intf = 0;
132 if(libusb_get_device_descriptor(dev, &dev_desc) != 0)
133 goto Lend;
134 if(libusb_get_config_descriptor(dev, 0, &config) != 0)
135 goto Lend;
136 /* Try to find Rockbox hwstub interface or a JZ device */
137 if(rb_handle::find_intf(&dev_desc, config, intf) ||
138 jz_handle::is_boot_dev(&dev_desc, config))
139 {
140 libusb_free_config_descriptor(config);
141 return true;
142 }
143Lend:
144 if(config)
145 libusb_free_config_descriptor(config);
146 return false;
147}
148
149error device::open_dev(std::shared_ptr<hwstub::handle>& handle)
150{
151 int intf = -1;
152 /* open the device */
153 libusb_device_handle *h;
154 int err = libusb_open(m_dev, &h);
155 if(err != LIBUSB_SUCCESS)
156 return error::ERROR;
157 /* fetch some descriptors */
158 struct libusb_device_descriptor dev_desc;
159 struct libusb_config_descriptor *config = nullptr;
160 if(libusb_get_device_descriptor(m_dev, &dev_desc) != 0)
161 goto Lend;
162 if(libusb_get_config_descriptor(m_dev, 0, &config) != 0)
163 goto Lend;
164 /* Try to find Rockbox hwstub interface */
165 if(rb_handle::find_intf(&dev_desc, config, intf))
166 {
167 libusb_free_config_descriptor(config);
168 /* create the handle */
169 // NOTE: can't use make_shared() because of the protected ctor */
170 handle.reset(new rb_handle(shared_from_this(), h, intf));
171 }
172 /* Maybe this is a JZ device ? */
173 else if(jz_handle::is_boot_dev(&dev_desc, config))
174 {
175 libusb_free_config_descriptor(config);
176 /* create the handle */
177 // NOTE: can't use make_shared() because of the protected ctor */
178 handle.reset(new jz_handle(shared_from_this(), h));
179 }
180 else
181 {
182 libusb_free_config_descriptor(config);
183 return error::ERROR;
184 }
185 /* the class will perform some probing on creation: check that it actually worked */
186 if(handle->valid())
187 return error::SUCCESS;
188 /* abort */
189 handle.reset(); // will close the libusb handle
190 return error::ERROR;
191
192Lend:
193 if(config)
194 libusb_free_config_descriptor(config);
195 libusb_close(h);
196 return error::ERROR;
197}
198
199bool device::has_multiple_open() const
200{
201 /* libusb only allows one handle per device */
202 return false;
203}
204
205uint8_t device::get_bus_number()
206{
207 return libusb_get_bus_number(native_device());
208}
209
210uint8_t device::get_address()
211{
212 return libusb_get_device_address(native_device());
213}
214
215uint16_t device::get_vid()
216{
217 /* NOTE: doc says it's cached so it should always succeed */
218 struct libusb_device_descriptor dev_desc;
219 libusb_get_device_descriptor(native_device(), &dev_desc);
220 return dev_desc.idVendor;
221}
222
223uint16_t device::get_pid()
224{
225 /* NOTE: doc says it's cached so it should always succeed */
226 struct libusb_device_descriptor dev_desc;
227 libusb_get_device_descriptor(native_device(), &dev_desc);
228 return dev_desc.idProduct;
229}
230
231/**
232 * USB handle
233 */
234handle::handle(std::shared_ptr<hwstub::device> dev, libusb_device_handle *handle)
235 :hwstub::handle(dev), m_handle(handle)
236{
237 set_timeout(std::chrono::milliseconds(100));
238}
239
240handle::~handle()
241{
242 libusb_close(m_handle);
243}
244
245error handle::interpret_libusb_error(int err)
246{
247 if(err >= 0)
248 return error::SUCCESS;
249 if(err == LIBUSB_ERROR_NO_DEVICE)
250 return error::DISCONNECTED;
251 else
252 return error::USB_ERROR;
253}
254
255error handle::interpret_libusb_error(int err, size_t expected_val)
256{
257 if(err < 0)
258 return interpret_libusb_error(err);
259 if((size_t)err != expected_val)
260 return error::ERROR;
261 return error::SUCCESS;
262}
263
264error handle::interpret_libusb_size(int err, size_t& out_siz)
265{
266 if(err < 0)
267 return interpret_libusb_error(err);
268 out_siz = (size_t)err;
269 return error::SUCCESS;
270}
271
272void handle::set_timeout(std::chrono::milliseconds ms)
273{
274 m_timeout = ms.count();
275}
276
277/**
278 * Rockbox Handle
279 */
280
281rb_handle::rb_handle(std::shared_ptr<hwstub::device> dev,
282 libusb_device_handle *handle, int intf)
283 :hwstub::usb::handle(dev, handle), m_intf(intf), m_transac_id(0), m_buf_size(1)
284{
285 m_probe_status = error::SUCCESS;
286 /* claim interface */
287 if(libusb_claim_interface(m_handle, m_intf) != 0)
288 m_probe_status = error::PROBE_FAILURE;
289 /* check version */
290 if(m_probe_status == error::SUCCESS)
291 {
292 struct hwstub_version_desc_t ver_desc;
293 m_probe_status = get_version_desc(ver_desc);
294 if(m_probe_status == error::SUCCESS)
295 {
296 if(ver_desc.bMajor != HWSTUB_VERSION_MAJOR ||
297 ver_desc.bMinor < HWSTUB_VERSION_MINOR)
298 m_probe_status = error::PROBE_FAILURE;
299 }
300 }
301 /* get buffer size */
302 if(m_probe_status == error::SUCCESS)
303 {
304 struct hwstub_layout_desc_t layout_desc;
305 m_probe_status = get_layout_desc(layout_desc);
306 if(m_probe_status == error::SUCCESS)
307 m_buf_size = layout_desc.dBufferSize;
308 }
309}
310
311rb_handle::~rb_handle()
312{
313}
314
315size_t rb_handle::get_buffer_size()
316{
317 return m_buf_size;
318}
319
320error rb_handle::status() const
321{
322 error err = handle::status();
323 if(err == error::SUCCESS)
324 err = m_probe_status;
325 return err;
326}
327
328error rb_handle::get_dev_desc(uint16_t desc, void *buf, size_t& buf_sz)
329{
330 return interpret_libusb_size(libusb_control_transfer(m_handle,
331 LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
332 LIBUSB_REQUEST_GET_DESCRIPTOR, desc << 8, m_intf, (unsigned char *)buf, buf_sz, m_timeout),
333 buf_sz);
334}
335
336error rb_handle::get_dev_log(void *buf, size_t& buf_sz)
337{
338 return interpret_libusb_size(libusb_control_transfer(m_handle,
339 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
340 HWSTUB_GET_LOG, 0, m_intf, (unsigned char *)buf, buf_sz, m_timeout), buf_sz);
341}
342
343error rb_handle::exec_dev(uint32_t addr, uint16_t flags)
344{
345 struct hwstub_exec_req_t exec;
346 exec.dAddress = addr;
347 exec.bmFlags = flags;
348 return interpret_libusb_error(libusb_control_transfer(m_handle,
349 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
350 HWSTUB_EXEC, 0, m_intf, (unsigned char *)&exec, sizeof(exec), m_timeout), sizeof(exec));
351}
352
353error rb_handle::read_dev(uint32_t addr, void *buf, size_t& sz, bool atomic)
354{
355 struct hwstub_read_req_t read;
356 read.dAddress = addr;
357 error err = interpret_libusb_error(libusb_control_transfer(m_handle,
358 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
359 HWSTUB_READ, m_transac_id, m_intf, (unsigned char *)&read, sizeof(read), m_timeout),
360 sizeof(read));
361 if(err != error::SUCCESS)
362 return err;
363 return interpret_libusb_size(libusb_control_transfer(m_handle,
364 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN,
365 atomic ? HWSTUB_READ2_ATOMIC : HWSTUB_READ2, m_transac_id++, m_intf,
366 (unsigned char *)buf, sz, m_timeout), sz);
367}
368
369error rb_handle::write_dev(uint32_t addr, const void *buf, size_t& sz, bool atomic)
370{
371 size_t hdr_sz = sizeof(struct hwstub_write_req_t);
372 uint8_t *tmp_buf = new uint8_t[sz + hdr_sz];
373 struct hwstub_write_req_t *req = reinterpret_cast<struct hwstub_write_req_t *>(tmp_buf);
374 req->dAddress = addr;
375 memcpy(tmp_buf + hdr_sz, buf, sz);
376 error ret = interpret_libusb_error(libusb_control_transfer(m_handle,
377 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
378 atomic ? HWSTUB_WRITE_ATOMIC : HWSTUB_WRITE, m_transac_id++, m_intf,
379 (unsigned char *)req, sz + hdr_sz, m_timeout), sz + hdr_sz);
380 delete[] tmp_buf;
381 return ret;
382}
383
384bool rb_handle::find_intf(struct libusb_device_descriptor *dev,
385 struct libusb_config_descriptor *config, int& intf_idx)
386{
387 (void) dev;
388 /* search hwstub interface */
389 for(unsigned i = 0; i < config->bNumInterfaces; i++)
390 {
391 /* hwstub interface has only one setting */
392 if(config->interface[i].num_altsetting != 1)
393 continue;
394 const struct libusb_interface_descriptor *intf = &config->interface[i].altsetting[0];
395 /* check class/subclass/protocol */
396 if(intf->bInterfaceClass == HWSTUB_CLASS &&
397 intf->bInterfaceSubClass == HWSTUB_SUBCLASS &&
398 intf->bInterfaceProtocol == HWSTUB_PROTOCOL)
399 {
400 /* found it ! */
401 intf_idx = i;
402 return true;
403 }
404 }
405 return false;
406}
407
408/**
409 * JZ Handle
410 */
411
412namespace
413{
414 uint16_t jz_bcd(char *bcd)
415 {
416 uint16_t v = 0;
417 for(int i = 0; i < 4; i++)
418 v = (bcd[i] - '0') | v << 4;
419 return v;
420 }
421}
422
423jz_handle::jz_handle(std::shared_ptr<hwstub::device> dev,
424 libusb_device_handle *handle)
425 :hwstub::usb::handle(dev, handle)
426{
427 m_probe_status = probe();
428}
429
430jz_handle::~jz_handle()
431{
432}
433
434error jz_handle::probe()
435{
436 char cpuinfo[8];
437 /* Get CPU info and devise descriptor */
438 error err = jz_cpuinfo(cpuinfo);
439 if(err != error::SUCCESS)
440 return err;
441 struct libusb_device_descriptor dev_desc;
442 err = interpret_libusb_error(libusb_get_device_descriptor(
443 libusb_get_device(m_handle), &dev_desc), 0);
444 if(err != error::SUCCESS)
445 return err;
446 /** parse CPU info */
447 /* if cpuinfo if of the form JZxxxxVy then extract xxxx */
448 if(cpuinfo[0] == 'J' && cpuinfo[1] == 'Z' && cpuinfo[6] == 'V')
449 m_desc_jz.wChipID = jz_bcd(cpuinfo + 2);
450 /* if cpuinfo if of the form Bootxxxx then extract xxxx */
451 else if(strncmp(cpuinfo, "Boot", 4) == 4)
452 m_desc_jz.wChipID = jz_bcd(cpuinfo + 4);
453 /* else use usb id */
454 else
455 m_desc_jz.wChipID = dev_desc.idProduct;
456 m_desc_jz.bRevision = 0;
457
458 /** Retrieve product string */
459 memset(m_desc_target.bName, 0, sizeof(m_desc_target.bName));
460 err = interpret_libusb_error(libusb_get_string_descriptor_ascii(m_handle,
461 dev_desc.iProduct, (unsigned char *)m_desc_target.bName, sizeof(m_desc_target.bName)));
462 if(err != error::SUCCESS)
463 return err;
464 /** The JZ4760 and JZ4760B cannot be distinguished by the above information,
465 * for this the best way I have found is to check the SRAM size: 48KiB vs 16KiB.
466 * This requires to enable AHB1 and SRAM clock and read/write to SRAM, but
467 * this code will leaves registers and ram is the same state as before.
468 * In case of failure, simply assume JZ4760. */
469 if(m_desc_jz.wChipID == 0x4760)
470 probe_jz4760b();
471
472 /** Fill descriptors */
473 m_desc_version.bLength = sizeof(m_desc_version);
474 m_desc_version.bDescriptorType = HWSTUB_DT_VERSION;
475 m_desc_version.bMajor = HWSTUB_VERSION_MAJOR;
476 m_desc_version.bMinor = HWSTUB_VERSION_MINOR;
477 m_desc_version.bRevision = 0;
478
479 m_desc_layout.bLength = sizeof(m_desc_layout);
480 m_desc_layout.bDescriptorType = HWSTUB_DT_LAYOUT;
481 m_desc_layout.dCodeStart = 0xbfc00000; /* ROM */
482 m_desc_layout.dCodeSize = 0x2000; /* 8kB per datasheet */
483 m_desc_layout.dStackStart = 0; /* As far as I can tell, the ROM uses no stack */
484 m_desc_layout.dStackSize = 0;
485 m_desc_layout.dBufferStart = 0x080000000;
486 m_desc_layout.dBufferSize = 0x4000;
487
488 m_desc_target.bLength = sizeof(m_desc_target);
489 m_desc_target.bDescriptorType = HWSTUB_DT_TARGET;
490 m_desc_target.dID = HWSTUB_TARGET_JZ;
491
492 m_desc_jz.bLength = sizeof(m_desc_jz);
493 m_desc_jz.bDescriptorType = HWSTUB_DT_JZ;
494
495 /* claim interface */
496 if(libusb_claim_interface(m_handle, 0) != 0)
497 m_probe_status = error::PROBE_FAILURE;
498
499 return m_probe_status;
500}
501
502error jz_handle::read_reg32(uint32_t addr, uint32_t& value)
503{
504 size_t sz = sizeof(value);
505 error err = read_dev(addr, &value, sz, true);
506 if(err == error::SUCCESS && sz != sizeof(value))
507 err = error::ERROR;
508 return err;
509}
510
511error jz_handle::write_reg32(uint32_t addr, uint32_t value)
512{
513 size_t sz = sizeof(value);
514 error err = write_dev(addr, &value, sz, true);
515 if(err == error::SUCCESS && sz != sizeof(value))
516 err = error::ERROR;
517 return err;
518}
519
520error jz_handle::probe_jz4760b()
521{
522 /* first read CPM_CLKGR1 */
523 const uint32_t cpm_clkgr1_addr = 0xb0000028;
524 uint32_t cpm_clkgr1;
525 error err = read_reg32(cpm_clkgr1_addr, cpm_clkgr1);
526 if(err != error::SUCCESS)
527 return err;
528 /* Bit 7 controls AHB1 clock and bit 5 the SRAM. Note that SRAM is on AHB1.
529 * Only ungate if gated */
530 uint32_t cpm_clkgr1_mask = 1 << 7 | 1 << 5;
531 if(cpm_clkgr1 & cpm_clkgr1_mask)
532 {
533 /* ungate both clocks */
534 err = write_reg32(cpm_clkgr1_addr, cpm_clkgr1 & ~cpm_clkgr1_mask);
535 if(err != error::SUCCESS)
536 return err;
537 }
538 /* read first word of SRAM and then at end (supposedly) */
539 uint32_t sram_addr = 0xb32d0000;
540 uint32_t sram_end_addr = sram_addr + 16 * 1024; /* SRAM is 16KiB on JZ4760B */
541 uint32_t sram_start, sram_end;
542 err = read_reg32(sram_addr, sram_start);
543 if(err != error::SUCCESS)
544 goto Lrestore;
545 err = read_reg32(sram_end_addr, sram_end);
546 if(err != error::SUCCESS)
547 goto Lrestore;
548 /* if start and end are different, clearly the size is not 16KiB and this is
549 * JZ4760 and we have nothing to do */
550 if(sram_start != sram_end)
551 goto Lrestore;
552 /* now reverse all bits of the first word */
553 sram_start ^= 0xffffffff;
554 err = write_reg32(sram_addr, sram_start);
555 if(err != error::SUCCESS)
556 goto Lrestore;
557 /* and read again at end */
558 err = read_reg32(sram_end_addr, sram_end);
559 if(err != error::SUCCESS)
560 goto Lrestore;
561 /* if they are still equal, we identified JZ4760B */
562 if(sram_start == sram_end)
563 m_desc_jz.bRevision = 'B';
564 /* restore SRAM value */
565 sram_start ^= 0xffffffff;
566 err = write_reg32(sram_addr, sram_start);
567 if(err != error::SUCCESS)
568 goto Lrestore;
569
570Lrestore:
571 /* restore gates if needed */
572 if(cpm_clkgr1 & cpm_clkgr1_mask)
573 return write_reg32(cpm_clkgr1_addr, cpm_clkgr1);
574 else
575 return error::SUCCESS;
576}
577
578size_t jz_handle::get_buffer_size()
579{
580 return m_desc_layout.dBufferSize;
581}
582
583error jz_handle::status() const
584{
585 error err = handle::status();
586 if(err == error::SUCCESS)
587 err = m_probe_status;
588 return err;
589}
590
591error jz_handle::get_dev_desc(uint16_t desc, void *buf, size_t& buf_sz)
592{
593 void *p = nullptr;
594 switch(desc)
595 {
596 case HWSTUB_DT_VERSION: p = &m_desc_version; break;
597 case HWSTUB_DT_LAYOUT: p = &m_desc_layout; break;
598 case HWSTUB_DT_TARGET: p = &m_desc_target; break;
599 case HWSTUB_DT_JZ: p = &m_desc_jz; break;
600 default: break;
601 }
602 if(p == nullptr)
603 return error::ERROR;
604 /* size is in the bLength field of the descriptor */
605 size_t desc_sz = *(uint8_t *)p;
606 buf_sz = std::min(buf_sz, desc_sz);
607 memcpy(buf, p, buf_sz);
608 return error::SUCCESS;
609}
610
611error jz_handle::get_dev_log(void *buf, size_t& buf_sz)
612{
613 (void) buf;
614 buf_sz = 0;
615 return error::SUCCESS;
616}
617
618error jz_handle::exec_dev(uint32_t addr, uint16_t flags)
619{
620 (void) flags;
621 /* FIXME the ROM always do call so the stub can always return, this behaviour
622 * cannot be changed */
623 /* NOTE assume that exec at 0x80000000 is a first stage load with START1,
624 * otherwise flush cache and use START2 */
625 if(addr == 0x80000000)
626 return jz_start1(addr);
627 error ret = jz_flush_caches();
628 if(ret == error::SUCCESS)
629 return jz_start2(addr);
630 else
631 return ret;
632}
633
634error jz_handle::read_dev(uint32_t addr, void *buf, size_t& sz, bool atomic)
635{
636 (void) atomic;
637 /* NOTE disassembly shows that the ROM will do atomic read on aligned words */
638 error ret = jz_set_addr(addr);
639 if(ret == error::SUCCESS)
640 ret = jz_set_length(sz);
641 if(ret == error::SUCCESS)
642 ret = jz_upload(buf, sz);
643 return ret;
644}
645
646error jz_handle::write_dev(uint32_t addr, const void *buf, size_t& sz, bool atomic)
647{
648 (void) atomic;
649 /* NOTE disassembly shows that the ROM will do atomic read on aligned words */
650 /* IMPORTANT BUG Despite what the manual suggest, one must absolutely NOT send
651 * a VR_SET_DATA_LENGTH request for a write, otherwise it will have completely
652 * random effects */
653 error ret = jz_set_addr(addr);
654 if(ret == error::SUCCESS)
655 ret = jz_download(buf, sz);
656 return ret;
657}
658
659bool jz_handle::is_boot_dev(struct libusb_device_descriptor *dev,
660 struct libusb_config_descriptor *config)
661{
662 (void) config;
663 /* don't bother checking the config descriptor and use the device ID only */
664 return dev->idVendor == 0x601a && dev->idProduct >= 0x4740 && dev->idProduct <= 0x4780;
665}
666
667error jz_handle::jz_cpuinfo(char cpuinfo[8])
668{
669 return interpret_libusb_error(libusb_control_transfer(m_handle,
670 LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
671 VR_GET_CPU_INFO, 0, 0, (unsigned char *)cpuinfo, 8, m_timeout), 8);
672}
673
674error jz_handle::jz_set_addr(uint32_t addr)
675{
676 return interpret_libusb_error(libusb_control_transfer(m_handle,
677 LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
678 VR_SET_DATA_ADDRESS, addr >> 16, addr & 0xffff, NULL, 0, m_timeout), 0);
679}
680
681error jz_handle::jz_set_length(uint32_t size)
682{
683 return interpret_libusb_error(libusb_control_transfer(m_handle,
684 LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
685 VR_SET_DATA_LENGTH, size >> 16, size & 0xffff, NULL, 0, m_timeout), 0);
686}
687
688error jz_handle::jz_upload(void *data, size_t& length)
689{
690 int xfer = 0;
691 error err = interpret_libusb_error(libusb_bulk_transfer(m_handle,
692 LIBUSB_ENDPOINT_IN | 1, (unsigned char *)data, length, &xfer, m_timeout));
693 length = xfer;
694 return err;
695}
696
697error jz_handle::jz_download(const void *data, size_t& length)
698{
699 int xfer = 0;
700 error err = interpret_libusb_error(libusb_bulk_transfer(m_handle,
701 LIBUSB_ENDPOINT_OUT | 1, (unsigned char *)data, length, &xfer, m_timeout));
702 length = xfer;
703 return err;
704}
705
706error jz_handle::jz_start1(uint32_t addr)
707{
708 return interpret_libusb_error(libusb_control_transfer(m_handle,
709 LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
710 VR_PROGRAM_START1, addr >> 16, addr & 0xffff, NULL, 0, m_timeout), 0);
711}
712
713error jz_handle::jz_flush_caches()
714{
715 return interpret_libusb_error(libusb_control_transfer(m_handle,
716 LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
717 VR_FLUSH_CACHES, 0, 0, NULL, 0, m_timeout), 0);
718}
719
720error jz_handle::jz_start2(uint32_t addr)
721{
722 return interpret_libusb_error(libusb_control_transfer(m_handle,
723 LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
724 VR_PROGRAM_START2, addr >> 16, addr & 0xffff, NULL, 0, m_timeout), 0);
725}
726
727} // namespace usb
728} // namespace hwstub