diff options
author | Marcin Bukat <marcin.bukat@gmail.com> | 2014-11-18 23:27:26 +0100 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2014-11-18 23:30:44 +0100 |
commit | cd04a5f1aadc8e2ec4e787f5ba4cc8c38a579314 (patch) | |
tree | 63e9f095451aeba0139152c8742d0af67413690a /utils/hwstub/lib | |
parent | 794169a18f644eea32de20b26646381137545e2d (diff) | |
download | rockbox-cd04a5f1aadc8e2ec4e787f5ba4cc8c38a579314.tar.gz rockbox-cd04a5f1aadc8e2ec4e787f5ba4cc8c38a579314.zip |
hwstub/qeditor: add support for atomic read/writes
The current code assumed that READ/WRITE would produce atomic read/writes for
8/16/32-bit words, which in turned put assumption on the memcpy function.
Since some memcpy implementation do not always guarantee such strong assumption,
introduce two new operation READ/WRITE_ATOMIC which provide the necessary
tools to do correct read and write to register in a single memory access.
Change-Id: I37451bd5057bb0dcaf5a800d8aef8791c792a090
Diffstat (limited to 'utils/hwstub/lib')
-rw-r--r-- | utils/hwstub/lib/hwstub.c | 40 | ||||
-rw-r--r-- | utils/hwstub/lib/hwstub.h | 5 |
2 files changed, 36 insertions, 9 deletions
diff --git a/utils/hwstub/lib/hwstub.c b/utils/hwstub/lib/hwstub.c index 6ae0400a66..d3908585da 100644 --- a/utils/hwstub/lib/hwstub.c +++ b/utils/hwstub/lib/hwstub.c | |||
@@ -140,7 +140,8 @@ int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz) | |||
140 | HWSTUB_GET_LOG, 0, dev->intf, buf, sz, 1000); | 140 | HWSTUB_GET_LOG, 0, dev->intf, buf, sz, 1000); |
141 | } | 141 | } |
142 | 142 | ||
143 | static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 143 | static int _hwstub_read(struct hwstub_device_t *dev, uint8_t breq, uint32_t addr, |
144 | void *buf, size_t sz) | ||
144 | { | 145 | { |
145 | struct hwstub_read_req_t read; | 146 | struct hwstub_read_req_t read; |
146 | read.dAddress = addr; | 147 | read.dAddress = addr; |
@@ -151,10 +152,11 @@ static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, s | |||
151 | return -1; | 152 | return -1; |
152 | return libusb_control_transfer(dev->handle, | 153 | return libusb_control_transfer(dev->handle, |
153 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, | 154 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, |
154 | HWSTUB_READ2, dev->id++, dev->intf, buf, sz, 1000); | 155 | breq, dev->id++, dev->intf, buf, sz, 1000); |
155 | } | 156 | } |
156 | 157 | ||
157 | static int _hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 158 | static int _hwstub_write(struct hwstub_device_t *dev, uint8_t breq, uint32_t addr, |
159 | const void *buf, size_t sz) | ||
158 | { | 160 | { |
159 | size_t hdr_sz = sizeof(struct hwstub_write_req_t); | 161 | size_t hdr_sz = sizeof(struct hwstub_write_req_t); |
160 | struct hwstub_write_req_t *req = malloc(sz + hdr_sz); | 162 | struct hwstub_write_req_t *req = malloc(sz + hdr_sz); |
@@ -162,18 +164,34 @@ static int _hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, | |||
162 | memcpy(req + 1, buf, sz); | 164 | memcpy(req + 1, buf, sz); |
163 | int size = libusb_control_transfer(dev->handle, | 165 | int size = libusb_control_transfer(dev->handle, |
164 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, | 166 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, |
165 | HWSTUB_WRITE, dev->id++, dev->intf, (void *)req, sz + hdr_sz, 1000); | 167 | breq, dev->id++, dev->intf, (void *)req, sz + hdr_sz, 1000); |
166 | free(req); | 168 | free(req); |
167 | return size - hdr_sz; | 169 | return size - hdr_sz; |
168 | } | 170 | } |
169 | 171 | ||
172 | int hwstub_read_atomic(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | ||
173 | { | ||
174 | /* reject any read greater than the buffer, it makes no sense anyway */ | ||
175 | if(sz > dev->buf_sz) | ||
176 | return -1; | ||
177 | return _hwstub_read(dev, HWSTUB_READ2_ATOMIC, addr, buf, sz); | ||
178 | } | ||
179 | |||
180 | int hwstub_write_atomic(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz) | ||
181 | { | ||
182 | /* reject any write greater than the buffer, it makes no sense anyway */ | ||
183 | if(sz + sizeof(struct hwstub_write_req_t) > dev->buf_sz) | ||
184 | return -1; | ||
185 | return _hwstub_write(dev, HWSTUB_WRITE_ATOMIC, addr, buf, sz); | ||
186 | } | ||
187 | |||
170 | /* Intermediate function which make sure we don't overflow the device buffer */ | 188 | /* Intermediate function which make sure we don't overflow the device buffer */ |
171 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 189 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) |
172 | { | 190 | { |
173 | int cnt = 0; | 191 | int cnt = 0; |
174 | while(sz > 0) | 192 | while(sz > 0) |
175 | { | 193 | { |
176 | int xfer = _hwstub_read(dev, addr, buf, MIN(sz, dev->buf_sz)); | 194 | int xfer = _hwstub_read(dev, HWSTUB_READ2, addr, buf, MIN(sz, dev->buf_sz)); |
177 | if(xfer < 0) | 195 | if(xfer < 0) |
178 | return xfer; | 196 | return xfer; |
179 | sz -= xfer; | 197 | sz -= xfer; |
@@ -185,13 +203,13 @@ int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz | |||
185 | } | 203 | } |
186 | 204 | ||
187 | /* Intermediate function which make sure we don't overflow the device buffer */ | 205 | /* Intermediate function which make sure we don't overflow the device buffer */ |
188 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 206 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz) |
189 | { | 207 | { |
190 | int cnt = 0; | 208 | int cnt = 0; |
191 | while(sz > 0) | 209 | while(sz > 0) |
192 | { | 210 | { |
193 | int xfer = _hwstub_write(dev, addr, buf, MIN(sz, dev->buf_sz - | 211 | int xfer = _hwstub_write(dev, HWSTUB_WRITE, addr, buf, |
194 | sizeof(struct hwstub_write_req_t))); | 212 | MIN(sz, dev->buf_sz - sizeof(struct hwstub_write_req_t))); |
195 | if(xfer < 0) | 213 | if(xfer < 0) |
196 | return xfer; | 214 | return xfer; |
197 | sz -= xfer; | 215 | sz -= xfer; |
@@ -207,6 +225,12 @@ int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *bu | |||
207 | return read ? hwstub_read(dev, addr, buf, sz) : hwstub_write(dev, addr, buf, sz); | 225 | return read ? hwstub_read(dev, addr, buf, sz) : hwstub_write(dev, addr, buf, sz); |
208 | } | 226 | } |
209 | 227 | ||
228 | int hwstub_rw_mem_atomic(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) | ||
229 | { | ||
230 | return read ? hwstub_read_atomic(dev, addr, buf, sz) : | ||
231 | hwstub_write_atomic(dev, addr, buf, sz); | ||
232 | } | ||
233 | |||
210 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags) | 234 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags) |
211 | { | 235 | { |
212 | struct hwstub_exec_req_t exec; | 236 | struct hwstub_exec_req_t exec; |
diff --git a/utils/hwstub/lib/hwstub.h b/utils/hwstub/lib/hwstub.h index d7d6ceb8ef..4d12de8eda 100644 --- a/utils/hwstub/lib/hwstub.h +++ b/utils/hwstub/lib/hwstub.h | |||
@@ -53,8 +53,11 @@ int hwstub_get_desc(struct hwstub_device_t *dev, uint16_t desc, void *info, size | |||
53 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); | 53 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); |
54 | /* Returns number of bytes written/read or <0 on error */ | 54 | /* Returns number of bytes written/read or <0 on error */ |
55 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); | 55 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); |
56 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); | 56 | int hwstub_read_atomic(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); |
57 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz); | ||
58 | int hwstub_write_atomic(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz); | ||
57 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); | 59 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); |
60 | int hwstub_rw_mem_atomic(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); | ||
58 | /* Returns <0 on error */ | 61 | /* Returns <0 on error */ |
59 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags); | 62 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags); |
60 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); | 63 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); |