]> sigrok.org Git - libsigrok.git/blob - src/hardware/ftdi-la/api.c
scpi-pps: Add a missing "break" in config_get().
[libsigrok.git] / src / hardware / ftdi-la / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2015 Sergey Alirzaev <zl29ah@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 <ftdi.h>
22 #include <libusb.h>
23 #include <libsigrok/libsigrok.h>
24 #include "libsigrok-internal.h"
25 #include "protocol.h"
26
27 static const uint32_t scanopts[] = {
28         SR_CONF_CONN,
29 };
30
31 static const uint32_t drvopts[] = {
32         SR_CONF_LOGIC_ANALYZER,
33 };
34
35 static const uint32_t devopts[] = {
36         SR_CONF_CONTINUOUS,
37         SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
38         SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
39         SR_CONF_CONN | SR_CONF_GET,
40 };
41
42 static const uint64_t samplerates[] = {
43         SR_HZ(3600),
44         SR_MHZ(10),
45         SR_HZ(1),
46 };
47
48 static const struct ftdi_chip_desc ft2232h_desc = {
49         .vendor = 0x0403,
50         .product = 0x6010,
51         .samplerate_div = 20,
52         .channel_names = {
53                 "ADBUS0", "ADBUS1", "ADBUS2", "ADBUS3",
54                 "ADBUS4", "ADBUS5", "ADBUS6", "ADBUS7",
55                 /* TODO: BDBUS[0..7] channels. */
56                 NULL
57         }
58 };
59
60 static const struct ftdi_chip_desc ft232r_desc = {
61         .vendor = 0x0403,
62         .product = 0x6001,
63         .samplerate_div = 30,
64         .channel_names = {
65                 "TXD", "RXD", "RTS#", "CTS#", "DTR#", "DSR#", "DCD#", "RI#",
66                 NULL
67         }
68 };
69
70 static const struct ftdi_chip_desc *chip_descs[] = {
71         &ft2232h_desc,
72         &ft232r_desc,
73 };
74
75 static void scan_device(struct ftdi_context *ftdic,
76         struct libusb_device *dev, GSList **devices)
77 {
78         struct libusb_device_descriptor usb_desc;
79         const struct ftdi_chip_desc *desc;
80         struct dev_context *devc;
81         char *vendor, *model, *serial_num;
82         struct sr_dev_inst *sdi;
83         int rv;
84
85         libusb_get_device_descriptor(dev, &usb_desc);
86
87         desc = NULL;
88         for (unsigned long i = 0; i < ARRAY_SIZE(chip_descs); i++) {
89                 desc = chip_descs[i];
90                 if (desc->vendor == usb_desc.idVendor &&
91                         desc->product == usb_desc.idProduct)
92                         break;
93         }
94
95         if (!desc) {
96                 sr_spew("Unsupported FTDI device 0x%4x:0x%4x.",
97                         usb_desc.idVendor, usb_desc.idProduct);
98                 return;
99         }
100
101         devc = g_malloc0(sizeof(struct dev_context));
102
103         /* Allocate memory for the incoming data. */
104         devc->data_buf = g_malloc0(DATA_BUF_SIZE);
105
106         devc->desc = desc;
107
108         vendor = g_malloc(32);
109         model = g_malloc(32);
110         serial_num = g_malloc(32);
111         rv = ftdi_usb_get_strings(ftdic, dev, vendor, 32,
112                         model, 32, serial_num, 32);
113         switch (rv) {
114         case 0:
115                 break;
116         case -9:
117                 sr_dbg("The device lacks a serial number.");
118                 g_free(serial_num);
119                 serial_num = NULL;
120                 break;
121         default:
122                 sr_err("Failed to get the FTDI strings: %d", rv);
123                 goto err_free_strings;
124         }
125         sr_dbg("Found an FTDI device: %s.", model);
126
127         sdi = g_malloc0(sizeof(struct sr_dev_inst));
128         sdi->status = SR_ST_INACTIVE;
129         sdi->vendor = vendor;
130         sdi->model = model;
131         sdi->serial_num = serial_num;
132         sdi->priv = devc;
133         sdi->connection_id = g_strdup_printf("d:%u/%u",
134                 libusb_get_bus_number(dev), libusb_get_device_address(dev));
135
136         for (char *const *chan = &(desc->channel_names[0]); *chan; chan++)
137                 sr_channel_new(sdi, chan - &(desc->channel_names[0]),
138                                 SR_CHANNEL_LOGIC, TRUE, *chan);
139
140         *devices = g_slist_append(*devices, sdi);
141         return;
142
143 err_free_strings:
144         g_free(vendor);
145         g_free(model);
146         g_free(serial_num);
147         g_free(devc->data_buf);
148         g_free(devc);
149 }
150
151 static GSList *scan_all(struct ftdi_context *ftdic, GSList *options)
152 {
153         GSList *devices;
154         struct ftdi_device_list *devlist = 0;
155         struct ftdi_device_list *curdev;
156         int ret;
157
158         (void)options;
159
160         devices = NULL;
161
162         ret = ftdi_usb_find_all(ftdic, &devlist, 0, 0);
163         if (ret < 0) {
164                 sr_err("Failed to list devices (%d): %s", ret,
165                        ftdi_get_error_string(ftdic));
166                 return NULL;
167         }
168
169         curdev = devlist;
170         while (curdev) {
171                 scan_device(ftdic, curdev->dev, &devices);
172                 curdev = curdev->next;
173         }
174
175         ftdi_list_free(&devlist);
176
177         return devices;
178 }
179
180 static GSList *scan(struct sr_dev_driver *di, GSList *options)
181 {
182         struct ftdi_context *ftdic;
183         struct sr_config *src;
184         struct sr_usb_dev_inst *usb;
185         const char *conn;
186         GSList *l, *conn_devices;
187         GSList *devices;
188         struct drv_context *drvc;
189         libusb_device **devlist;
190         int i;
191
192         drvc = di->context;
193         conn = NULL;
194         for (l = options; l; l = l->next) {
195                 src = l->data;
196                 if (src->key == SR_CONF_CONN) {
197                         conn = g_variant_get_string(src->data, NULL);
198                         break;
199                 }
200         }
201
202         ftdic = ftdi_new();
203         if (!ftdic) {
204                 sr_err("Failed to initialize libftdi.");
205                 return NULL;
206         }
207
208         if (conn) {
209                 devices = NULL;
210                 libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
211                 for (i = 0; devlist[i]; i++) {
212                         conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
213                         for (l = conn_devices; l; l = l->next) {
214                                 usb = l->data;
215                                 if (usb->bus == libusb_get_bus_number(devlist[i])
216                                         && usb->address == libusb_get_device_address(devlist[i])) {
217                                         scan_device(ftdic, devlist[i], &devices);
218                                 }
219                         }
220                 }
221                 libusb_free_device_list(devlist, 1);
222         } else
223                 devices = scan_all(ftdic, options);
224
225         ftdi_free(ftdic);
226
227         return std_scan_complete(di, devices);
228 }
229
230 static void clear_helper(struct dev_context *devc)
231 {
232         g_free(devc->data_buf);
233 }
234
235 static int dev_clear(const struct sr_dev_driver *di)
236 {
237         return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
238 }
239
240 static int dev_open(struct sr_dev_inst *sdi)
241 {
242         struct dev_context *devc;
243         int ret = SR_OK;
244
245         devc = sdi->priv;
246
247         devc->ftdic = ftdi_new();
248         if (!devc->ftdic)
249                 return SR_ERR;
250
251         ret = ftdi_usb_open_string(devc->ftdic, sdi->connection_id);
252         if (ret < 0) {
253                 /* Log errors, except for -3 ("device not found"). */
254                 if (ret != -3)
255                         sr_err("Failed to open device (%d): %s", ret,
256                                ftdi_get_error_string(devc->ftdic));
257                 goto err_ftdi_free;
258         }
259
260         ret = ftdi_usb_purge_buffers(devc->ftdic);
261         if (ret < 0) {
262                 sr_err("Failed to purge FTDI RX/TX buffers (%d): %s.",
263                        ret, ftdi_get_error_string(devc->ftdic));
264                 goto err_dev_open_close_ftdic;
265         }
266
267         ret = ftdi_set_bitmode(devc->ftdic, 0x00, BITMODE_RESET);
268         if (ret < 0) {
269                 sr_err("Failed to reset the FTDI chip bitmode (%d): %s.",
270                        ret, ftdi_get_error_string(devc->ftdic));
271                 goto err_dev_open_close_ftdic;
272         }
273
274         ret = ftdi_set_bitmode(devc->ftdic, 0x00, BITMODE_BITBANG);
275         if (ret < 0) {
276                 sr_err("Failed to put FTDI chip into bitbang mode (%d): %s.",
277                        ret, ftdi_get_error_string(devc->ftdic));
278                 goto err_dev_open_close_ftdic;
279         }
280
281         return SR_OK;
282
283 err_dev_open_close_ftdic:
284         ftdi_usb_close(devc->ftdic);
285
286 err_ftdi_free:
287         ftdi_free(devc->ftdic);
288
289         return SR_ERR;
290 }
291
292 static int dev_close(struct sr_dev_inst *sdi)
293 {
294         struct dev_context *devc;
295
296         devc = sdi->priv;
297
298         if (!devc->ftdic)
299                 return SR_ERR_BUG;
300
301         ftdi_usb_close(devc->ftdic);
302         ftdi_free(devc->ftdic);
303         devc->ftdic = NULL;
304
305         return SR_OK;
306 }
307
308 static int config_get(uint32_t key, GVariant **data,
309         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
310 {
311         struct dev_context *devc;
312         struct sr_usb_dev_inst *usb;
313
314         (void)cg;
315
316         devc = sdi->priv;
317
318         switch (key) {
319         case SR_CONF_SAMPLERATE:
320                 *data = g_variant_new_uint64(devc->cur_samplerate);
321                 break;
322         case SR_CONF_CONN:
323                 if (!sdi || !sdi->conn)
324                         return SR_ERR_ARG;
325                 usb = sdi->conn;
326                 *data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
327                 break;
328         default:
329                 return SR_ERR_NA;
330         }
331
332         return SR_OK;
333 }
334
335 static int config_set(uint32_t key, GVariant *data,
336         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
337 {
338         struct dev_context *devc;
339         uint64_t value;
340
341         (void)cg;
342
343         devc = sdi->priv;
344
345         switch (key) {
346         case SR_CONF_LIMIT_MSEC:
347                 value = g_variant_get_uint64(data);
348                 /* TODO: Implement. */
349                 (void)value;
350                 return SR_ERR_NA;
351         case SR_CONF_LIMIT_SAMPLES:
352                 devc->limit_samples = g_variant_get_uint64(data);
353                 break;
354         case SR_CONF_SAMPLERATE:
355                 value = g_variant_get_uint64(data);
356                 if (value < 3600)
357                         return SR_ERR_SAMPLERATE;
358                 devc->cur_samplerate = value;
359                 return ftdi_la_set_samplerate(devc);
360         default:
361                 return SR_ERR_NA;
362         }
363
364         return SR_OK;
365 }
366
367 static int config_list(uint32_t key, GVariant **data,
368         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
369 {
370         switch (key) {
371         case SR_CONF_SCAN_OPTIONS:
372         case SR_CONF_DEVICE_OPTIONS:
373                 return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
374         case SR_CONF_SAMPLERATE:
375                 *data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
376                 break;
377         default:
378                 return SR_ERR_NA;
379         }
380
381         return SR_OK;
382 }
383
384 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
385 {
386         struct dev_context *devc;
387
388         devc = sdi->priv;
389
390         if (!devc->ftdic)
391                 return SR_ERR_BUG;
392
393         ftdi_set_bitmode(devc->ftdic, 0, BITMODE_BITBANG);
394
395         /* Properly reset internal variables before every new acquisition. */
396         devc->samples_sent = 0;
397         devc->bytes_received = 0;
398
399         std_session_send_df_header(sdi);
400
401         /* Hook up a dummy handler to receive data from the device. */
402         sr_session_source_add(sdi->session, -1, G_IO_IN, 0,
403                               ftdi_la_receive_data, (void *)sdi);
404
405         return SR_OK;
406 }
407
408 static int dev_acquisition_stop(struct sr_dev_inst *sdi)
409 {
410         sr_session_source_remove(sdi->session, -1);
411
412         std_session_send_df_end(sdi);
413
414         return SR_OK;
415 }
416
417 static struct sr_dev_driver ftdi_la_driver_info = {
418         .name = "ftdi-la",
419         .longname = "FTDI LA",
420         .api_version = 1,
421         .init = std_init,
422         .cleanup = std_cleanup,
423         .scan = scan,
424         .dev_list = std_dev_list,
425         .dev_clear = dev_clear,
426         .config_get = config_get,
427         .config_set = config_set,
428         .config_list = config_list,
429         .dev_open = dev_open,
430         .dev_close = dev_close,
431         .dev_acquisition_start = dev_acquisition_start,
432         .dev_acquisition_stop = dev_acquisition_stop,
433         .context = NULL,
434 };
435 SR_REGISTER_DEV_DRIVER(ftdi_la_driver_info);