diff options
Diffstat (limited to 'rbutil/jztool/src/usb.c')
-rw-r--r-- | rbutil/jztool/src/usb.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/rbutil/jztool/src/usb.c b/rbutil/jztool/src/usb.c index 7e4a5f3388..c101f2be77 100644 --- a/rbutil/jztool/src/usb.c +++ b/rbutil/jztool/src/usb.c | |||
@@ -30,6 +30,16 @@ | |||
30 | #define VR_PROGRAM_START1 4 | 30 | #define VR_PROGRAM_START1 4 |
31 | #define VR_PROGRAM_START2 5 | 31 | #define VR_PROGRAM_START2 5 |
32 | 32 | ||
33 | /** \brief Open a USB device | ||
34 | * \param jz Context | ||
35 | * \param devptr Returns pointer to the USB device upon success | ||
36 | * \param vend_id USB vendor ID | ||
37 | * \param prod_id USB product ID | ||
38 | * \return either JZ_SUCCESS if device was opened, or an error below | ||
39 | * \retval JZ_ERR_OUT_OF_MEMORY malloc failed | ||
40 | * \retval JZ_ERR_USB libusb error (details are logged) | ||
41 | * \retval JZ_ERR_NO_DEVICE can't unambiguously find the device | ||
42 | */ | ||
33 | int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t prod_id) | 43 | int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t prod_id) |
34 | { | 44 | { |
35 | int rc; | 45 | int rc; |
@@ -80,7 +90,7 @@ int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t p | |||
80 | } | 90 | } |
81 | 91 | ||
82 | if(dev_index < 0) { | 92 | if(dev_index < 0) { |
83 | jz_log(jz, JZ_LOG_ERROR, "No device with ID %04x:%05x found", | 93 | jz_log(jz, JZ_LOG_ERROR, "No device with ID %04x:%04x found", |
84 | (unsigned int)vend_id, (unsigned int)prod_id); | 94 | (unsigned int)vend_id, (unsigned int)prod_id); |
85 | rc = JZ_ERR_NO_DEVICE; | 95 | rc = JZ_ERR_NO_DEVICE; |
86 | goto error; | 96 | goto error; |
@@ -100,6 +110,8 @@ int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t p | |||
100 | goto error; | 110 | goto error; |
101 | } | 111 | } |
102 | 112 | ||
113 | jz_log(jz, JZ_LOG_DEBUG, "Opened device (%p, ID %04x:%04x)", | ||
114 | dev, (unsigned int)vend_id, (unsigned int)prod_id); | ||
103 | dev->jz = jz; | 115 | dev->jz = jz; |
104 | dev->handle = usb_handle; | 116 | dev->handle = usb_handle; |
105 | *devptr = dev; | 117 | *devptr = dev; |
@@ -119,14 +131,20 @@ int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t p | |||
119 | goto exit; | 131 | goto exit; |
120 | } | 132 | } |
121 | 133 | ||
134 | /** \brief Close a USB device | ||
135 | * \param dev Device to close; memory will be freed automatically | ||
136 | */ | ||
122 | void jz_usb_close(jz_usbdev* dev) | 137 | void jz_usb_close(jz_usbdev* dev) |
123 | { | 138 | { |
139 | jz_log(dev->jz, JZ_LOG_DEBUG, "Closing device (%p)", dev); | ||
124 | libusb_release_interface(dev->handle, 0); | 140 | libusb_release_interface(dev->handle, 0); |
125 | libusb_close(dev->handle); | 141 | libusb_close(dev->handle); |
126 | jz_context_unref_libusb(dev->jz); | 142 | jz_context_unref_libusb(dev->jz); |
127 | free(dev); | 143 | free(dev); |
128 | } | 144 | } |
129 | 145 | ||
146 | // Does an Ingenic-specific vendor request | ||
147 | // Written with X1000 in mind but other Ingenic CPUs have the same commands | ||
130 | static int jz_usb_vendor_req(jz_usbdev* dev, int req, uint32_t arg) | 148 | static int jz_usb_vendor_req(jz_usbdev* dev, int req, uint32_t arg) |
131 | { | 149 | { |
132 | int rc = libusb_control_transfer(dev->handle, | 150 | int rc = libusb_control_transfer(dev->handle, |
@@ -137,12 +155,24 @@ static int jz_usb_vendor_req(jz_usbdev* dev, int req, uint32_t arg) | |||
137 | jz_log(dev->jz, JZ_LOG_ERROR, "libusb_control_transfer: %s", libusb_strerror(rc)); | 155 | jz_log(dev->jz, JZ_LOG_ERROR, "libusb_control_transfer: %s", libusb_strerror(rc)); |
138 | rc = JZ_ERR_USB; | 156 | rc = JZ_ERR_USB; |
139 | } else { | 157 | } else { |
158 | static const char* req_names[] = { | ||
159 | "GET_CPU_INFO", | ||
160 | "SET_DATA_ADDRESS", | ||
161 | "SET_DATA_LENGTH", | ||
162 | "FLUSH_CACHES", | ||
163 | "PROGRAM_START1", | ||
164 | "PROGRAM_START2", | ||
165 | }; | ||
166 | |||
167 | jz_log(dev->jz, JZ_LOG_DEBUG, "Issued %s %08lu", | ||
168 | req_names[req], (unsigned long)arg); | ||
140 | rc = JZ_SUCCESS; | 169 | rc = JZ_SUCCESS; |
141 | } | 170 | } |
142 | 171 | ||
143 | return rc; | 172 | return rc; |
144 | } | 173 | } |
145 | 174 | ||
175 | // Bulk transfer wrapper | ||
146 | static int jz_usb_transfer(jz_usbdev* dev, bool write, size_t len, void* buf) | 176 | static int jz_usb_transfer(jz_usbdev* dev, bool write, size_t len, void* buf) |
147 | { | 177 | { |
148 | int xfered = 0; | 178 | int xfered = 0; |
@@ -156,12 +186,16 @@ static int jz_usb_transfer(jz_usbdev* dev, bool write, size_t len, void* buf) | |||
156 | jz_log(dev->jz, JZ_LOG_ERROR, "libusb_bulk_transfer: incorrect amount of data transfered"); | 186 | jz_log(dev->jz, JZ_LOG_ERROR, "libusb_bulk_transfer: incorrect amount of data transfered"); |
157 | rc = JZ_ERR_USB; | 187 | rc = JZ_ERR_USB; |
158 | } else { | 188 | } else { |
189 | jz_log(dev->jz, JZ_LOG_DEBUG, "Transferred %zu bytes %s", | ||
190 | len, write ? "to device" : "from device"); | ||
159 | rc = JZ_SUCCESS; | 191 | rc = JZ_SUCCESS; |
160 | } | 192 | } |
161 | 193 | ||
162 | return rc; | 194 | return rc; |
163 | } | 195 | } |
164 | 196 | ||
197 | // Memory send/receive primitive, performs the necessary vendor requests | ||
198 | // and then tranfers data using the bulk endpoint | ||
165 | static int jz_usb_sendrecv(jz_usbdev* dev, bool write, uint32_t addr, | 199 | static int jz_usb_sendrecv(jz_usbdev* dev, bool write, uint32_t addr, |
166 | size_t len, void* data) | 200 | size_t len, void* data) |
167 | { | 201 | { |
@@ -177,26 +211,54 @@ static int jz_usb_sendrecv(jz_usbdev* dev, bool write, uint32_t addr, | |||
177 | return jz_usb_transfer(dev, write, len, data); | 211 | return jz_usb_transfer(dev, write, len, data); |
178 | } | 212 | } |
179 | 213 | ||
214 | /** \brief Write data to device memory | ||
215 | * \param dev USB device | ||
216 | * \param addr Address where data should be written | ||
217 | * \param len Length of the data, in bytes, should be positive | ||
218 | * \param data Data buffer | ||
219 | * \return either JZ_SUCCESS on success or a failure code | ||
220 | */ | ||
180 | int jz_usb_send(jz_usbdev* dev, uint32_t addr, size_t len, const void* data) | 221 | int jz_usb_send(jz_usbdev* dev, uint32_t addr, size_t len, const void* data) |
181 | { | 222 | { |
182 | return jz_usb_sendrecv(dev, true, addr, len, (void*)data); | 223 | return jz_usb_sendrecv(dev, true, addr, len, (void*)data); |
183 | } | 224 | } |
184 | 225 | ||
226 | /** \brief Read data to device memory | ||
227 | * \param dev USB device | ||
228 | * \param addr Address to read from | ||
229 | * \param len Length of the data, in bytes, should be positive | ||
230 | * \param data Data buffer | ||
231 | * \return either JZ_SUCCESS on success or a failure code | ||
232 | */ | ||
185 | int jz_usb_recv(jz_usbdev* dev, uint32_t addr, size_t len, void* data) | 233 | int jz_usb_recv(jz_usbdev* dev, uint32_t addr, size_t len, void* data) |
186 | { | 234 | { |
187 | return jz_usb_sendrecv(dev, false, addr, len, data); | 235 | return jz_usb_sendrecv(dev, false, addr, len, data); |
188 | } | 236 | } |
189 | 237 | ||
238 | /** \brief Execute stage1 program jumping to the specified address | ||
239 | * \param dev USB device | ||
240 | * \param addr Address to begin execution at | ||
241 | * \return either JZ_SUCCESS on success or a failure code | ||
242 | */ | ||
190 | int jz_usb_start1(jz_usbdev* dev, uint32_t addr) | 243 | int jz_usb_start1(jz_usbdev* dev, uint32_t addr) |
191 | { | 244 | { |
192 | return jz_usb_vendor_req(dev, VR_PROGRAM_START1, addr); | 245 | return jz_usb_vendor_req(dev, VR_PROGRAM_START1, addr); |
193 | } | 246 | } |
194 | 247 | ||
248 | /** \brief Execute stage2 program jumping to the specified address | ||
249 | * \param dev USB device | ||
250 | * \param addr Address to begin execution at | ||
251 | * \return either JZ_SUCCESS on success or a failure code | ||
252 | */ | ||
195 | int jz_usb_start2(jz_usbdev* dev, uint32_t addr) | 253 | int jz_usb_start2(jz_usbdev* dev, uint32_t addr) |
196 | { | 254 | { |
197 | return jz_usb_vendor_req(dev, VR_PROGRAM_START2, addr); | 255 | return jz_usb_vendor_req(dev, VR_PROGRAM_START2, addr); |
198 | } | 256 | } |
199 | 257 | ||
258 | /** \brief Ask device to flush CPU caches | ||
259 | * \param dev USB device | ||
260 | * \return either JZ_SUCCESS on success or a failure code | ||
261 | */ | ||
200 | int jz_usb_flush_caches(jz_usbdev* dev) | 262 | int jz_usb_flush_caches(jz_usbdev* dev) |
201 | { | 263 | { |
202 | return jz_usb_vendor_req(dev, VR_FLUSH_CACHES, 0); | 264 | return jz_usb_vendor_req(dev, VR_FLUSH_CACHES, 0); |