]> sigrok.org Git - libsigrok.git/blob - src/hardware/sysclk-lwla/lwla.c
Build: Include <config.h> first in all source files
[libsigrok.git] / src / hardware / sysclk-lwla / lwla.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Daniel Elstner <daniel.kitta@gmail.com>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <errno.h>
22 #include <glib/gstdio.h>
23 #include <libsigrok/libsigrok.h>
24 #include "libsigrok-internal.h"
25 #include "protocol.h"
26 #include "lwla.h"
27
28 #define BITSTREAM_MAX_SIZE    (256 * 1024) /* bitstream size limit for safety */
29 #define BITSTREAM_HEADER_SIZE 4            /* transfer header size in bytes */
30
31 /* Load a bitstream file into memory.  Returns a newly allocated array
32  * consisting of a 32-bit length field followed by the bitstream data.
33  */
34 static unsigned char *load_bitstream_file(const char *filename, int *length_p)
35 {
36         GStatBuf statbuf;
37         FILE *file;
38         unsigned char *stream;
39         size_t length, count;
40
41         /* Retrieve and validate the file size. */
42         if (g_stat(filename, &statbuf) < 0) {
43                 sr_err("Failed to access bitstream file: %s.",
44                        g_strerror(errno));
45                 return NULL;
46         }
47         if (!S_ISREG(statbuf.st_mode)) {
48                 sr_err("Bitstream is not a regular file.");
49                 return NULL;
50         }
51         if (statbuf.st_size <= 0 || statbuf.st_size > BITSTREAM_MAX_SIZE) {
52                 sr_err("Refusing to load bitstream of unreasonable size "
53                        "(%" PRIu64 " bytes).", (uint64_t)statbuf.st_size);
54                 return NULL;
55         }
56
57         /* The message length includes the 4-byte header. */
58         length = BITSTREAM_HEADER_SIZE + statbuf.st_size;
59         stream = g_try_malloc(length);
60         if (!stream) {
61                 sr_err("Failed to allocate bitstream buffer.");
62                 return NULL;
63         }
64
65         file = g_fopen(filename, "rb");
66         if (!file) {
67                 sr_err("Failed to open bitstream file: %s.", g_strerror(errno));
68                 g_free(stream);
69                 return NULL;
70         }
71
72         /* Write the message length header. */
73         *(uint32_t *)stream = GUINT32_TO_BE(length);
74
75         count = fread(stream + BITSTREAM_HEADER_SIZE,
76                       length - BITSTREAM_HEADER_SIZE, 1, file);
77         if (count != 1) {
78                 sr_err("Failed to read bitstream file: %s.", g_strerror(errno));
79                 fclose(file);
80                 g_free(stream);
81                 return NULL;
82         }
83         fclose(file);
84
85         *length_p = length;
86         return stream;
87 }
88
89 /* Load a Raw Binary File (.rbf) from the firmware directory and transfer
90  * it to the device.
91  */
92 SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
93                                 const char *basename)
94 {
95         char *filename;
96         unsigned char *stream;
97         int ret;
98         int length;
99         int xfer_len;
100
101         if (!usb || !basename)
102                 return SR_ERR_BUG;
103
104         filename = g_build_filename(FIRMWARE_DIR, basename, NULL);
105         sr_info("Downloading FPGA bitstream at '%s'.", filename);
106
107         stream = load_bitstream_file(filename, &length);
108         g_free(filename);
109
110         if (!stream)
111                 return SR_ERR;
112
113         /* Transfer the entire bitstream in one URB. */
114         ret = libusb_bulk_transfer(usb->devhdl, EP_BITSTREAM,
115                                    stream, length, &xfer_len, USB_TIMEOUT_MS);
116         g_free(stream);
117
118         if (ret != 0) {
119                 sr_err("Failed to transfer bitstream: %s.",
120                        libusb_error_name(ret));
121                 return SR_ERR;
122         }
123         if (xfer_len != length) {
124                 sr_err("Failed to transfer bitstream: incorrect length "
125                        "%d != %d.", xfer_len, length);
126                 return SR_ERR;
127         }
128         sr_info("FPGA bitstream download of %d bytes done.", xfer_len);
129
130         /* This delay appears to be necessary for reliable operation. */
131         g_usleep(30 * 1000);
132
133         return SR_OK;
134 }
135
136 SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
137                               const uint16_t *command, int cmd_len)
138 {
139         int ret;
140         int xfer_len;
141
142         if (!usb || !command || cmd_len <= 0)
143                 return SR_ERR_BUG;
144
145         xfer_len = 0;
146         ret = libusb_bulk_transfer(usb->devhdl, EP_COMMAND,
147                                    (unsigned char *)command, cmd_len * 2,
148                                    &xfer_len, USB_TIMEOUT_MS);
149         if (ret != 0) {
150                 sr_dbg("Failed to send command %d: %s.",
151                        LWLA_TO_UINT16(command[0]), libusb_error_name(ret));
152                 return SR_ERR;
153         }
154         if (xfer_len != cmd_len * 2) {
155                 sr_dbg("Failed to send command %d: incorrect length %d != %d.",
156                        LWLA_TO_UINT16(command[0]), xfer_len, cmd_len * 2);
157                 return SR_ERR;
158         }
159         return SR_OK;
160 }
161
162 SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
163                                uint32_t *reply, int reply_len, int expect_len)
164 {
165         int ret;
166         int xfer_len;
167
168         if (!usb || !reply || reply_len <= 0)
169                 return SR_ERR_BUG;
170
171         xfer_len = 0;
172         ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY,
173                                    (unsigned char *)reply, reply_len * 4,
174                                    &xfer_len, USB_TIMEOUT_MS);
175         if (ret != 0) {
176                 sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret));
177                 return SR_ERR;
178         }
179         if (xfer_len != expect_len * 4) {
180                 sr_dbg("Failed to receive reply: incorrect length %d != %d.",
181                        xfer_len, expect_len * 4);
182                 return SR_ERR;
183         }
184         return SR_OK;
185 }
186
187 SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
188                           uint16_t reg, uint32_t *value)
189 {
190         int ret;
191         uint16_t command[2];
192         uint32_t reply[128]; /* full EP buffer to avoid overflows */
193
194         command[0] = LWLA_WORD(CMD_READ_REG);
195         command[1] = LWLA_WORD(reg);
196
197         ret = lwla_send_command(usb, command, ARRAY_SIZE(command));
198
199         if (ret != SR_OK)
200                 return ret;
201
202         ret = lwla_receive_reply(usb, reply, ARRAY_SIZE(reply), 1);
203
204         if (ret == SR_OK)
205                 *value = LWLA_TO_UINT32(reply[0]);
206
207         return ret;
208 }
209
210 SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
211                            uint16_t reg, uint32_t value)
212 {
213         uint16_t command[4];
214
215         command[0] = LWLA_WORD(CMD_WRITE_REG);
216         command[1] = LWLA_WORD(reg);
217         command[2] = LWLA_WORD_0(value);
218         command[3] = LWLA_WORD_1(value);
219
220         return lwla_send_command(usb, command, ARRAY_SIZE(command));
221 }
222
223 SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
224                             const struct regval_pair *regvals, int count)
225 {
226         int i;
227         int ret;
228
229         ret = SR_OK;
230
231         for (i = 0; i < count; ++i) {
232                 ret = lwla_write_reg(usb, regvals[i].reg, regvals[i].val);
233
234                 if (ret != SR_OK)
235                         break;
236         }
237
238         return ret;
239 }