00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <string.h>
00026 #include <alsa/asoundlib.h>
00027 #include "sigrok.h"
00028 #include "sigrok-internal.h"
00029
00030 #define NUM_PROBES 2
00031 #define SAMPLE_WIDTH 16
00032 #define AUDIO_DEV "plughw:0,0"
00033
00034 struct sr_analog_probe {
00035 uint8_t att;
00036 uint8_t res;
00037 uint16_t val;
00038 };
00039
00040 struct sr_analog_sample {
00041 uint8_t num_probes;
00042 struct sr_analog_probe probes[];
00043 };
00044
00045 static int hwcaps[] = {
00046 SR_HWCAP_SAMPLERATE,
00047 SR_HWCAP_LIMIT_SAMPLES,
00048 SR_HWCAP_CONTINUOUS,
00049 };
00050
00051
00052 static const char *probe_names[NUM_PROBES + 1] = {
00053 "0",
00054 "1",
00055 NULL,
00056 };
00057
00058 static GSList *dev_insts = NULL;
00059
00060
00061 struct context {
00062 uint64_t cur_rate;
00063 uint64_t limit_samples;
00064 snd_pcm_t *capture_handle;
00065 snd_pcm_hw_params_t *hw_params;
00066 void *session_dev_id;
00067 };
00068
00069 static int hw_init(const char *devinfo)
00070 {
00071 struct sr_dev_inst *sdi;
00072 struct context *ctx;
00073
00074
00075 (void)devinfo;
00076
00077 if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
00078 sr_err("alsa: %s: ctx malloc failed", __func__);
00079 return 0;
00080 }
00081
00082 if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "alsa", NULL, NULL))) {
00083 sr_err("alsa: %s: sdi was NULL", __func__);
00084 goto free_ctx;
00085 }
00086
00087 sdi->priv = ctx;
00088
00089 dev_insts = g_slist_append(dev_insts, sdi);
00090
00091 return 1;
00092
00093 free_ctx:
00094 g_free(ctx);
00095 return 0;
00096 }
00097
00098 static int hw_dev_open(int dev_index)
00099 {
00100 struct sr_dev_inst *sdi;
00101 struct context *ctx;
00102 int ret;
00103
00104 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
00105 return SR_ERR;
00106 ctx = sdi->priv;
00107
00108 ret = snd_pcm_open(&ctx->capture_handle, AUDIO_DEV,
00109 SND_PCM_STREAM_CAPTURE, 0);
00110 if (ret < 0) {
00111 sr_err("alsa: can't open audio device %s (%s)", AUDIO_DEV,
00112 snd_strerror(ret));
00113 return SR_ERR;
00114 }
00115
00116 ret = snd_pcm_hw_params_malloc(&ctx->hw_params);
00117 if (ret < 0) {
00118 sr_err("alsa: can't allocate hardware parameter structure (%s)",
00119 snd_strerror(ret));
00120 return SR_ERR;
00121 }
00122
00123 ret = snd_pcm_hw_params_any(ctx->capture_handle, ctx->hw_params);
00124 if (ret < 0) {
00125 sr_err("alsa: can't initialize hardware parameter structure "
00126 "(%s)", snd_strerror(ret));
00127 return SR_ERR;
00128 }
00129
00130 return SR_OK;
00131 }
00132
00133 static int hw_dev_close(int dev_index)
00134 {
00135 struct sr_dev_inst *sdi;
00136 struct context *ctx;
00137
00138 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) {
00139 sr_err("alsa: %s: sdi was NULL", __func__);
00140 return SR_ERR_BUG;
00141 }
00142
00143 if (!(ctx = sdi->priv)) {
00144 sr_err("alsa: %s: sdi->priv was NULL", __func__);
00145 return SR_ERR_BUG;
00146 }
00147
00148
00149 if (ctx->hw_params)
00150 snd_pcm_hw_params_free(ctx->hw_params);
00151 if (ctx->capture_handle)
00152 snd_pcm_close(ctx->capture_handle);
00153
00154 return SR_OK;
00155 }
00156
00157 static int hw_cleanup(void)
00158 {
00159 struct sr_dev_inst *sdi;
00160
00161 if (!(sdi = sr_dev_inst_get(dev_insts, 0))) {
00162 sr_err("alsa: %s: sdi was NULL", __func__);
00163 return SR_ERR_BUG;
00164 }
00165
00166 sr_dev_inst_free(sdi);
00167
00168 return SR_OK;
00169 }
00170
00171 static void *hw_dev_info_get(int dev_index, int dev_info_id)
00172 {
00173 struct sr_dev_inst *sdi;
00174 struct context *ctx;
00175 void *info = NULL;
00176
00177 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
00178 return NULL;
00179 ctx = sdi->priv;
00180
00181 switch (dev_info_id) {
00182 case SR_DI_INST:
00183 info = sdi;
00184 break;
00185 case SR_DI_NUM_PROBES:
00186 info = GINT_TO_POINTER(NUM_PROBES);
00187 break;
00188 case SR_DI_PROBE_NAMES:
00189 info = probe_names;
00190 break;
00191 case SR_DI_CUR_SAMPLERATE:
00192 info = &ctx->cur_rate;
00193 break;
00194
00195
00196
00197 }
00198
00199 return info;
00200 }
00201
00202 static int hw_dev_status_get(int dev_index)
00203 {
00204
00205 dev_index = dev_index;
00206
00207 return SR_ST_ACTIVE;
00208 }
00209
00210 static int *hw_hwcap_get_all(void)
00211 {
00212 return hwcaps;
00213 }
00214
00215 static int hw_dev_config_set(int dev_index, int hwcap, void *value)
00216 {
00217 struct sr_dev_inst *sdi;
00218 struct context *ctx;
00219
00220 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
00221 return SR_ERR;
00222 ctx = sdi->priv;
00223
00224 switch (hwcap) {
00225 case SR_HWCAP_PROBECONFIG:
00226 return SR_OK;
00227 case SR_HWCAP_SAMPLERATE:
00228 ctx->cur_rate = *(uint64_t *)value;
00229 return SR_OK;
00230 case SR_HWCAP_LIMIT_SAMPLES:
00231 ctx->limit_samples = *(uint64_t *)value;
00232 return SR_OK;
00233 default:
00234 return SR_ERR;
00235 }
00236 }
00237
00238 static int receive_data(int fd, int revents, void *cb_data)
00239 {
00240 struct sr_dev_inst *sdi = cb_data;
00241 struct context *ctx = sdi->priv;
00242 struct sr_datafeed_packet packet;
00243 struct sr_analog_sample *sample;
00244 unsigned int sample_size = sizeof(struct sr_analog_sample) +
00245 (NUM_PROBES * sizeof(struct sr_analog_probe));
00246 char *outb;
00247 char inb[4096];
00248 int i, x, count;
00249
00250 fd = fd;
00251 revents = revents;
00252
00253 do {
00254 memset(inb, 0, sizeof(inb));
00255 count = snd_pcm_readi(ctx->capture_handle, inb,
00256 MIN(4096 / 4, ctx->limit_samples));
00257 if (count < 1) {
00258 sr_err("alsa: Failed to read samples");
00259 return FALSE;
00260 }
00261
00262 if (!(outb = g_try_malloc(sample_size * count))) {
00263 sr_err("alsa: %s: outb malloc failed", __func__);
00264 return FALSE;
00265 }
00266
00267 for (i = 0; i < count; i++) {
00268 sample = (struct sr_analog_sample *)
00269 (outb + (i * sample_size));
00270 sample->num_probes = NUM_PROBES;
00271
00272 for (x = 0; x < NUM_PROBES; x++) {
00273 sample->probes[x].val =
00274 *(uint16_t *)(inb + (i * 4) + (x * 2));
00275 sample->probes[x].val &= ((1 << 16) - 1);
00276 sample->probes[x].res = 16;
00277 }
00278 }
00279
00280 packet.type = SR_DF_ANALOG;
00281 packet.length = count * sample_size;
00282 packet.unitsize = sample_size;
00283 packet.payload = outb;
00284 sr_session_send(sdi, &packet);
00285 g_free(outb);
00286 ctx->limit_samples -= count;
00287
00288 } while (ctx->limit_samples > 0);
00289
00290 packet.type = SR_DF_END;
00291 sr_session_send(sdi, &packet);
00292
00293 return TRUE;
00294 }
00295
00296 static int hw_dev_acquisition_start(int dev_index, void *cb_data)
00297 {
00298 struct sr_dev_inst *sdi;
00299 struct context *ctx;
00300 struct sr_datafeed_packet packet;
00301 struct sr_datafeed_header header;
00302 struct pollfd *ufds;
00303 int count;
00304 int ret;
00305
00306 if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
00307 return SR_ERR;
00308 ctx = sdi->priv;
00309
00310 ret = snd_pcm_hw_params_set_access(ctx->capture_handle,
00311 ctx->hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
00312 if (ret < 0) {
00313 sr_err("alsa: can't set access type (%s)", snd_strerror(ret));
00314 return SR_ERR;
00315 }
00316
00317
00318 ret = snd_pcm_hw_params_set_format(ctx->capture_handle,
00319 ctx->hw_params, SND_PCM_FORMAT_S16_LE);
00320 if (ret < 0) {
00321 sr_err("alsa: can't set sample format (%s)", snd_strerror(ret));
00322 return SR_ERR;
00323 }
00324
00325 ret = snd_pcm_hw_params_set_rate_near(ctx->capture_handle,
00326 ctx->hw_params, (unsigned int *)&ctx->cur_rate, 0);
00327 if (ret < 0) {
00328 sr_err("alsa: can't set sample rate (%s)", snd_strerror(ret));
00329 return SR_ERR;
00330 }
00331
00332 ret = snd_pcm_hw_params_set_channels(ctx->capture_handle,
00333 ctx->hw_params, NUM_PROBES);
00334 if (ret < 0) {
00335 sr_err("alsa: can't set channel count (%s)", snd_strerror(ret));
00336 return SR_ERR;
00337 }
00338
00339 ret = snd_pcm_hw_params(ctx->capture_handle, ctx->hw_params);
00340 if (ret < 0) {
00341 sr_err("alsa: can't set parameters (%s)", snd_strerror(ret));
00342 return SR_ERR;
00343 }
00344
00345 ret = snd_pcm_prepare(ctx->capture_handle);
00346 if (ret < 0) {
00347 sr_err("alsa: can't prepare audio interface for use (%s)",
00348 snd_strerror(ret));
00349 return SR_ERR;
00350 }
00351
00352 count = snd_pcm_poll_descriptors_count(ctx->capture_handle);
00353 if (count < 1) {
00354 sr_err("alsa: Unable to obtain poll descriptors count");
00355 return SR_ERR;
00356 }
00357
00358 if (!(ufds = g_try_malloc(count * sizeof(struct pollfd)))) {
00359 sr_err("alsa: %s: ufds malloc failed", __func__);
00360 return SR_ERR_MALLOC;
00361 }
00362
00363 ret = snd_pcm_poll_descriptors(ctx->capture_handle, ufds, count);
00364 if (ret < 0) {
00365 sr_err("alsa: Unable to obtain poll descriptors (%s)",
00366 snd_strerror(ret));
00367 g_free(ufds);
00368 return SR_ERR;
00369 }
00370
00371 ctx->session_dev_id = cb_data;
00372 sr_source_add(ufds[0].fd, ufds[0].events, 10, receive_data, sdi);
00373
00374 packet.type = SR_DF_HEADER;
00375 packet.length = sizeof(struct sr_datafeed_header);
00376 packet.payload = (unsigned char *)&header;
00377 header.feed_version = 1;
00378 gettimeofday(&header.starttime, NULL);
00379 header.samplerate = ctx->cur_rate;
00380 header.num_analog_probes = NUM_PROBES;
00381 header.num_logic_probes = 0;
00382 header.protocol_id = SR_PROTO_RAW;
00383 sr_session_send(cb_data, &packet);
00384 g_free(ufds);
00385
00386 return SR_OK;
00387 }
00388
00389
00390 static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
00391 {
00392
00393 (void)dev_index;
00394 (void)cb_data;
00395
00396 return SR_OK;
00397 }
00398
00399 SR_PRIV struct sr_dev_driver alsa_driver_info = {
00400 .name = "alsa",
00401 .longname = "ALSA driver",
00402 .api_version = 1,
00403 .init = hw_init,
00404 .cleanup = hw_cleanup,
00405 .dev_open = hw_dev_open,
00406 .dev_close = hw_dev_close,
00407 .dev_info_get = hw_dev_info_get,
00408 .dev_status_get = hw_dev_status_get,
00409 .hwcap_get_all = hw_hwcap_get_all,
00410 .dev_config_set = hw_dev_config_set,
00411 .dev_acquisition_start = hw_dev_acquisition_start,
00412 .dev_acquisition_stop = hw_dev_acquisition_stop,
00413 };