]> sigrok.org Git - libsigrok.git/blob - hardware/alsa/alsa.c
alsa: Use message logging helpers.
[libsigrok.git] / hardware / alsa / alsa.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2011 Daniel Ribeiro <drwyrm@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 2 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 /* Note: This driver doesn't compile, analog support in sigrok is WIP. */
22
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <alsa/asoundlib.h>
27 #include "libsigrok.h"
28 #include "libsigrok-internal.h"
29
30 /* Message logging helpers with driver-specific prefix string. */
31 #define DRIVER_LOG_DOMAIN "alsa: "
32 #define sr_log(l, s, args...) sr_log(l, DRIVER_LOG_DOMAIN s, ## args)
33 #define sr_spew(s, args...) sr_spew(DRIVER_LOG_DOMAIN s, ## args)
34 #define sr_dbg(s, args...) sr_dbg(DRIVER_LOG_DOMAIN s, ## args)
35 #define sr_info(s, args...) sr_info(DRIVER_LOG_DOMAIN s, ## args)
36 #define sr_warn(s, args...) sr_warn(DRIVER_LOG_DOMAIN s, ## args)
37 #define sr_err(s, args...) sr_err(DRIVER_LOG_DOMAIN s, ## args)
38
39 #define NUM_PROBES 2
40 #define SAMPLE_WIDTH 16
41 #define AUDIO_DEV "plughw:0,0"
42
43 struct sr_analog_probe {
44         uint8_t att;
45         uint8_t res;    /* Needs to be a power of 2, FIXME */
46         uint16_t val;   /* Max hardware ADC width is 16bits */
47 };
48
49 struct sr_analog_sample {
50         uint8_t num_probes; /* Max hardware probes is 256 */
51         struct sr_analog_probe probes[];
52 };
53
54 static const int hwcaps[] = {
55         SR_HWCAP_SAMPLERATE,
56         SR_HWCAP_LIMIT_SAMPLES,
57         SR_HWCAP_CONTINUOUS,
58 };
59
60 /* TODO: Which probe names/numbers to use? */
61 static const char *probe_names[NUM_PROBES + 1] = {
62         "0",
63         "1",
64         NULL,
65 };
66
67 static GSList *dev_insts = NULL;
68
69 /* Private, per-device-instance driver context. */
70 struct context {
71         uint64_t cur_rate;
72         uint64_t limit_samples;
73         snd_pcm_t *capture_handle;
74         snd_pcm_hw_params_t *hw_params;
75         void *session_dev_id;
76 };
77
78 static int hw_init(const char *devinfo)
79 {
80         struct sr_dev_inst *sdi;
81         struct context *ctx;
82
83         (void)devinfo;
84
85         if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
86                 sr_err("%s: ctx malloc failed", __func__);
87                 return SR_ERR_MALLOC;
88         }
89
90         if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "alsa", NULL, NULL))) {
91                 sr_err("%s: sdi was NULL", __func__);
92                 goto free_ctx;
93         }
94
95         sdi->priv = ctx;
96
97         dev_insts = g_slist_append(dev_insts, sdi);
98
99         return 1;
100
101 free_ctx:
102         g_free(ctx);
103         return 0;
104 }
105
106 static int hw_dev_open(int dev_index)
107 {
108         struct sr_dev_inst *sdi;
109         struct context *ctx;
110         int ret;
111
112         if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
113                 return SR_ERR;
114         ctx = sdi->priv;
115
116         ret = snd_pcm_open(&ctx->capture_handle, AUDIO_DEV,
117                            SND_PCM_STREAM_CAPTURE, 0);
118         if (ret < 0) {
119                 sr_err("Can't open audio device %s (%s).", AUDIO_DEV,
120                        snd_strerror(ret));
121                 return SR_ERR;
122         }
123
124         ret = snd_pcm_hw_params_malloc(&ctx->hw_params);
125         if (ret < 0) {
126                 sr_err("Can't allocate hardware parameter structure (%s).",
127                        snd_strerror(ret));
128                 return SR_ERR_MALLOC;
129         }
130
131         ret = snd_pcm_hw_params_any(ctx->capture_handle, ctx->hw_params);
132         if (ret < 0) {
133                 sr_err("Can't initialize hardware parameter structure (%s)",
134                        snd_strerror(ret));
135                 return SR_ERR;
136         }
137
138         return SR_OK;
139 }
140
141 static int hw_dev_close(int dev_index)
142 {
143         struct sr_dev_inst *sdi;
144         struct context *ctx;
145
146         if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
147                 sr_err("%s: sdi was NULL", __func__);
148                 return SR_ERR_BUG;
149         }
150
151         if (!(ctx = sdi->priv)) {
152                 sr_err("%s: sdi->priv was NULL", __func__);
153                 return SR_ERR_BUG;
154         }
155
156         // TODO: Return values of snd_*?
157         if (ctx->hw_params)
158                 snd_pcm_hw_params_free(ctx->hw_params);
159         if (ctx->capture_handle)
160                 snd_pcm_close(ctx->capture_handle);
161
162         return SR_OK;
163 }
164
165 static int hw_cleanup(void)
166 {
167         struct sr_dev_inst *sdi;
168
169         if (!(sdi = sr_dev_inst_get(dev_insts, 0))) {
170                 sr_err("%s: sdi was NULL", __func__);
171                 return SR_ERR_BUG;
172         }
173
174         sr_dev_inst_free(sdi);
175
176         return SR_OK;
177 }
178
179 static const void *hw_dev_info_get(int dev_index, int dev_info_id)
180 {
181         struct sr_dev_inst *sdi;
182         struct context *ctx;
183         void *info = NULL;
184
185         if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
186                 return NULL;
187         ctx = sdi->priv;
188
189         switch (dev_info_id) {
190         case SR_DI_INST:
191                 info = sdi;
192                 break;
193         case SR_DI_NUM_PROBES:
194                 info = GINT_TO_POINTER(NUM_PROBES);
195                 break;
196         case SR_DI_PROBE_NAMES:
197                 info = probe_names;
198                 break;
199         case SR_DI_CUR_SAMPLERATE:
200                 info = &ctx->cur_rate;
201                 break;
202         // case SR_DI_PROBE_TYPE:
203         //      info = GINT_TO_POINTER(SR_PROBE_TYPE_ANALOG);
204         //      break;
205         }
206
207         return info;
208 }
209
210 static int hw_dev_status_get(int dev_index)
211 {
212         (void)dev_index;
213
214         return SR_ST_ACTIVE;
215 }
216
217 static const int *hw_hwcap_get_all(void)
218 {
219         return hwcaps;
220 }
221
222 static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
223 {
224         struct sr_dev_inst *sdi;
225         struct context *ctx;
226
227         if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
228                 return SR_ERR;
229         ctx = sdi->priv;
230
231         switch (hwcap) {
232         case SR_HWCAP_PROBECONFIG:
233                 return SR_OK;
234         case SR_HWCAP_SAMPLERATE:
235                 ctx->cur_rate = *(const uint64_t *)value;
236                 return SR_OK;
237         case SR_HWCAP_LIMIT_SAMPLES:
238                 ctx->limit_samples = *(const uint64_t *)value;
239                 return SR_OK;
240         default:
241                 return SR_ERR;
242         }
243 }
244
245 static int receive_data(int fd, int revents, void *cb_data)
246 {
247         struct sr_dev_inst *sdi = cb_data;
248         struct context *ctx = sdi->priv;
249         struct sr_datafeed_packet packet;
250         struct sr_analog_sample *sample;
251         unsigned int sample_size = sizeof(struct sr_analog_sample) +
252                 (NUM_PROBES * sizeof(struct sr_analog_probe));
253         char *outb;
254         char inb[4096];
255         int i, x, count;
256
257         fd = fd;
258         revents = revents;
259
260         do {
261                 memset(inb, 0, sizeof(inb));
262                 count = snd_pcm_readi(ctx->capture_handle, inb,
263                         MIN(4096 / 4, ctx->limit_samples));
264                 if (count < 1) {
265                         sr_err("Failed to read samples");
266                         return FALSE;
267                 }
268
269                 if (!(outb = g_try_malloc(sample_size * count))) {
270                         sr_err("%s: outb malloc failed", __func__);
271                         return FALSE;
272                 }
273
274                 for (i = 0; i < count; i++) {
275                         sample = (struct sr_analog_sample *)
276                                                 (outb + (i * sample_size));
277                         sample->num_probes = NUM_PROBES;
278
279                         for (x = 0; x < NUM_PROBES; x++) {
280                                 sample->probes[x].val =
281                                         *(uint16_t *)(inb + (i * 4) + (x * 2));
282                                 sample->probes[x].val &= ((1 << 16) - 1);
283                                 sample->probes[x].res = 16;
284                         }
285                 }
286
287                 packet.type = SR_DF_ANALOG;
288                 packet.length = count * sample_size;
289                 packet.unitsize = sample_size;
290                 packet.payload = outb;
291                 sr_session_send(sdi, &packet);
292                 g_free(outb);
293                 ctx->limit_samples -= count;
294
295         } while (ctx->limit_samples > 0);
296
297         packet.type = SR_DF_END;
298         sr_session_send(sdi, &packet);
299
300         return TRUE;
301 }
302
303 static int hw_dev_acquisition_start(int dev_index, void *cb_data)
304 {
305         struct sr_dev_inst *sdi;
306         struct context *ctx;
307         struct sr_datafeed_packet packet;
308         struct sr_datafeed_header header;
309         struct pollfd *ufds;
310         int count;
311         int ret;
312
313         if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
314                 return SR_ERR;
315         ctx = sdi->priv;
316
317         ret = snd_pcm_hw_params_set_access(ctx->capture_handle,
318                         ctx->hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
319         if (ret < 0) {
320                 sr_err("Can't set access type (%s).", snd_strerror(ret));
321                 return SR_ERR;
322         }
323
324         /* FIXME: Hardcoded for 16bits */
325         ret = snd_pcm_hw_params_set_format(ctx->capture_handle,
326                         ctx->hw_params, SND_PCM_FORMAT_S16_LE);
327         if (ret < 0) {
328                 sr_err("Can't set sample format (%s).", snd_strerror(ret));
329                 return SR_ERR;
330         }
331
332         ret = snd_pcm_hw_params_set_rate_near(ctx->capture_handle,
333                         ctx->hw_params, (unsigned int *)&ctx->cur_rate, 0);
334         if (ret < 0) {
335                 sr_err("Can't set sample rate (%s).", snd_strerror(ret));
336                 return SR_ERR;
337         }
338
339         ret = snd_pcm_hw_params_set_channels(ctx->capture_handle,
340                         ctx->hw_params, NUM_PROBES);
341         if (ret < 0) {
342                 sr_err("Can't set channel count (%s).", snd_strerror(ret));
343                 return SR_ERR;
344         }
345
346         ret = snd_pcm_hw_params(ctx->capture_handle, ctx->hw_params);
347         if (ret < 0) {
348                 sr_err("Can't set parameters (%s).", snd_strerror(ret));
349                 return SR_ERR;
350         }
351
352         ret = snd_pcm_prepare(ctx->capture_handle);
353         if (ret < 0) {
354                 sr_err("Can't prepare audio interface for use (%s).",
355                        snd_strerror(ret));
356                 return SR_ERR;
357         }
358
359         count = snd_pcm_poll_descriptors_count(ctx->capture_handle);
360         if (count < 1) {
361                 sr_err("Unable to obtain poll descriptors count.");
362                 return SR_ERR;
363         }
364
365         if (!(ufds = g_try_malloc(count * sizeof(struct pollfd)))) {
366                 sr_err("%s: ufds malloc failed", __func__);
367                 return SR_ERR_MALLOC;
368         }
369
370         ret = snd_pcm_poll_descriptors(ctx->capture_handle, ufds, count);
371         if (ret < 0) {
372                 sr_err("Unable to obtain poll descriptors (%s)",
373                        snd_strerror(ret));
374                 g_free(ufds);
375                 return SR_ERR;
376         }
377
378         ctx->session_dev_id = cb_data;
379         sr_source_add(ufds[0].fd, ufds[0].events, 10, receive_data, sdi);
380
381         packet.type = SR_DF_HEADER;
382         packet.length = sizeof(struct sr_datafeed_header);
383         packet.payload = (unsigned char *)&header;
384         header.feed_version = 1;
385         gettimeofday(&header.starttime, NULL);
386         header.samplerate = ctx->cur_rate;
387         header.num_analog_probes = NUM_PROBES;
388         header.num_logic_probes = 0;
389         header.protocol_id = SR_PROTO_RAW;
390         sr_session_send(cb_data, &packet);
391         g_free(ufds);
392
393         return SR_OK;
394 }
395
396 /* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
397 static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
398 {
399         (void)dev_index;
400         (void)cb_data;
401
402         return SR_OK;
403 }
404
405 SR_PRIV struct sr_dev_driver alsa_driver_info = {
406         .name = "alsa",
407         .longname = "ALSA driver",
408         .api_version = 1,
409         .init = hw_init,
410         .cleanup = hw_cleanup,
411         .dev_open = hw_dev_open,
412         .dev_close = hw_dev_close,
413         .dev_info_get = hw_dev_info_get,
414         .dev_status_get = hw_dev_status_get,
415         .hwcap_get_all = hw_hwcap_get_all,
416         .dev_config_set = hw_dev_config_set,
417         .dev_acquisition_start = hw_dev_acquisition_start,
418         .dev_acquisition_stop = hw_dev_acquisition_stop,
419 };