]> sigrok.org Git - libsigrok.git/blob - src/hardware/sysclk-lwla/lwla.c
sysclk-lwla: Implement support for LWLA1016
[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 <glib/gstdio.h>
22 #include <libsigrok/libsigrok.h>
23 #include "libsigrok-internal.h"
24 #include "protocol.h"
25 #include "lwla.h"
26
27 #define BITSTREAM_MAX_SIZE    (256 * 1024) /* bitstream size limit for safety */
28 #define BITSTREAM_HEADER_SIZE 4            /* transfer header size in bytes */
29
30 /* Load a bitstream file into memory. Returns a newly allocated array
31  * consisting of a 32-bit length field followed by the bitstream data.
32  */
33 static unsigned char *load_bitstream(struct sr_context *ctx,
34                                      const char *name, int *length_p)
35 {
36         struct sr_resource rbf;
37         unsigned char *stream;
38         ssize_t length, count;
39
40         if (sr_resource_open(ctx, &rbf, SR_RESOURCE_FIRMWARE, name) != SR_OK)
41                 return NULL;
42
43         if (rbf.size == 0 || rbf.size > BITSTREAM_MAX_SIZE) {
44                 sr_err("Refusing to load bitstream of unreasonable size "
45                        "(%" PRIu64 " bytes).", rbf.size);
46                 sr_resource_close(ctx, &rbf);
47                 return NULL;
48         }
49
50         /* The message length includes the 4-byte header. */
51         length = BITSTREAM_HEADER_SIZE + rbf.size;
52         stream = g_try_malloc(length);
53         if (!stream) {
54                 sr_err("Failed to allocate bitstream buffer.");
55                 sr_resource_close(ctx, &rbf);
56                 return NULL;
57         }
58
59         /* Write the message length header. */
60         *(uint32_t *)stream = GUINT32_TO_BE(length);
61
62         count = sr_resource_read(ctx, &rbf, stream + BITSTREAM_HEADER_SIZE,
63                                  length - BITSTREAM_HEADER_SIZE);
64         sr_resource_close(ctx, &rbf);
65
66         if (count != length - BITSTREAM_HEADER_SIZE) {
67                 sr_err("Failed to read bitstream '%s'.", name);
68                 g_free(stream);
69                 return NULL;
70         }
71
72         *length_p = length;
73         return stream;
74 }
75
76 /* Load a Raw Binary File (.rbf) from the firmware directory and transfer
77  * it to the device.
78  */
79 SR_PRIV int lwla_send_bitstream(struct sr_context *ctx,
80                                 const struct sr_usb_dev_inst *usb,
81                                 const char *name)
82 {
83         unsigned char *stream;
84         int ret;
85         int length;
86         int xfer_len;
87
88         if (!ctx || !usb || !name)
89                 return SR_ERR_BUG;
90
91         stream = load_bitstream(ctx, name, &length);
92         if (!stream)
93                 return SR_ERR;
94
95         sr_info("Downloading FPGA bitstream '%s'.", name);
96
97         /* Transfer the entire bitstream in one URB. */
98         ret = libusb_bulk_transfer(usb->devhdl, EP_CONFIG,
99                                    stream, length, &xfer_len, USB_TIMEOUT_MS);
100         g_free(stream);
101
102         if (ret != 0) {
103                 sr_err("Failed to transfer bitstream: %s.",
104                        libusb_error_name(ret));
105                 return SR_ERR;
106         }
107         if (xfer_len != length) {
108                 sr_err("Failed to transfer bitstream: incorrect length "
109                        "%d != %d.", xfer_len, length);
110                 return SR_ERR;
111         }
112         sr_info("FPGA bitstream download of %d bytes done.", xfer_len);
113
114         /* This delay appears to be necessary for reliable operation. */
115         g_usleep(30 * 1000);
116
117         return SR_OK;
118 }
119
120 SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
121                               const uint16_t *command, int cmd_len)
122 {
123         int ret;
124         int xfer_len;
125
126         if (!usb || !command || cmd_len <= 0)
127                 return SR_ERR_BUG;
128
129         xfer_len = 0;
130         ret = libusb_bulk_transfer(usb->devhdl, EP_COMMAND,
131                                    (unsigned char *)command, cmd_len * 2,
132                                    &xfer_len, USB_TIMEOUT_MS);
133         if (ret != 0) {
134                 sr_dbg("Failed to send command %d: %s.",
135                        LWLA_TO_UINT16(command[0]), libusb_error_name(ret));
136                 return SR_ERR;
137         }
138         if (xfer_len != cmd_len * 2) {
139                 sr_dbg("Failed to send command %d: incorrect length %d != %d.",
140                        LWLA_TO_UINT16(command[0]), xfer_len, cmd_len * 2);
141                 return SR_ERR;
142         }
143         return SR_OK;
144 }
145
146 SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
147                                uint32_t *reply, int reply_len, int expect_len)
148 {
149         int ret;
150         int xfer_len;
151
152         if (!usb || !reply || reply_len <= 0)
153                 return SR_ERR_BUG;
154
155         xfer_len = 0;
156         ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY,
157                                    (unsigned char *)reply, reply_len * 4,
158                                    &xfer_len, USB_TIMEOUT_MS);
159         if (ret != 0) {
160                 sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret));
161                 return SR_ERR;
162         }
163         if (xfer_len != expect_len * 4) {
164                 sr_dbg("Failed to receive reply: incorrect length %d != %d.",
165                        xfer_len, expect_len * 4);
166                 return SR_ERR;
167         }
168         return SR_OK;
169 }
170
171 SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
172                           uint16_t reg, uint32_t *value)
173 {
174         int ret;
175         uint16_t command[2];
176         uint32_t reply[128]; /* full EP buffer to avoid overflows */
177
178         command[0] = LWLA_WORD(CMD_READ_REG);
179         command[1] = LWLA_WORD(reg);
180
181         ret = lwla_send_command(usb, command, ARRAY_SIZE(command));
182
183         if (ret != SR_OK)
184                 return ret;
185
186         ret = lwla_receive_reply(usb, reply, ARRAY_SIZE(reply), 1);
187
188         if (ret == SR_OK)
189                 *value = LWLA_TO_UINT32(reply[0]);
190
191         return ret;
192 }
193
194 SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
195                            uint16_t reg, uint32_t value)
196 {
197         uint16_t command[4];
198
199         command[0] = LWLA_WORD(CMD_WRITE_REG);
200         command[1] = LWLA_WORD(reg);
201         command[2] = LWLA_WORD_0(value);
202         command[3] = LWLA_WORD_1(value);
203
204         return lwla_send_command(usb, command, ARRAY_SIZE(command));
205 }
206
207 SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
208                             const struct regval *regvals, int count)
209 {
210         int i;
211         int ret;
212
213         ret = SR_OK;
214
215         for (i = 0; i < count; ++i) {
216                 ret = lwla_write_reg(usb, regvals[i].reg, regvals[i].val);
217
218                 if (ret != SR_OK)
219                         break;
220         }
221
222         return ret;
223 }