~ubuntu-branches/ubuntu/trusty/alsa-utils/trusty

« back to all changes in this revision

Viewing changes to .pc/unset_pulse_internal.patch/amixer/amixer.c

  • Committer: Package Import Robot
  • Author(s): Luke Yelavich
  • Date: 2013-07-26 10:56:44 UTC
  • mfrom: (1.2.17) (93.1.1 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130726105644-kim9enke2jnozg73
Tags: 1.0.27.1-1ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Move init script volume settings to new alsactl database:
    + Set sane level for 'Speaker' and 'Headphone', needed for Dell Mini 9
      and Dell E series
    + ute PC Beep on hda cards that support it during initial volume setup
    + Mute *Analog/Digital Control for Creative cards by default
    + Default Digital Input Source to be Digital Mic 1 so that users
      with digital mic will be able to use it out of the box
    + Mute "IEC958 Optical Raw" by default
    + Set sane level for headphone 1 for Dell Studio XPS with 2.6.30
    + Prefer built-in digital mics on newer Dells
    + Unmute 'Line HP Swap' for Dove boards
    + Set reasonable volume levels for VMWare guests using snd.ens1371
  - debian/README.init.cs4236: Include in /usr/share/doc/alsa-utils so that
    users of snd-cs4236 (e.g., ThinkPad 600) can have audible sound
  - debian/patches/unset_pulse_internal.patch: We don't want alsamixer to
    show the pulse mixer by default, since it can be controlled from
    pulseaudio itself
  - Use upstart jobs for storing/restoring card settings
  - Add udev rule to apply UCM profiles for panda and equivalent hardware
  - Add Vcs-Bzr field
* Create a new upstart job for the alsa state daemon, and adjust the
  other upstart jobs accordingly
* Put the daemon file in /var/lib/alsa

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <assert.h>
30
30
#include <alsa/asoundlib.h>
31
31
#include <sys/poll.h>
 
32
#include <stdint.h>
32
33
#include "amixer.h"
 
34
#include "../alsamixer/volume_mapping.h"
33
35
 
34
36
#define LEVEL_BASIC             (1<<0)
35
37
#define LEVEL_INACTIVE          (1<<1)
68
70
        printf("  -i,--inactive   show also inactive controls\n");
69
71
        printf("  -a,--abstract L select abstraction level (none or basic)\n");
70
72
        printf("  -s,--stdin      Read and execute commands from stdin sequentially\n");
 
73
        printf("  -R,--raw-volume Use the raw value (default)\n");
 
74
        printf("  -M,--mapped-volume Use the mapped volume\n");
71
75
        printf("\nAvailable commands:\n");
72
76
        printf("  scontrols       show all mixer simple controls\n");
73
77
        printf("  scontents       show contents of all mixer simple controls (default command)\n");
134
138
        return 0;
135
139
}
136
140
 
137
 
static const char *control_iface(snd_ctl_elem_id_t *id)
138
 
{
139
 
        return snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id));
140
 
}
141
 
 
142
141
static const char *control_type(snd_ctl_elem_info_t *info)
143
142
{
144
143
        return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info));
187
186
 
188
187
/* Fuction to convert from volume to percentage. val = volume */
189
188
 
190
 
static int convert_prange(int val, int min, int max)
 
189
static int convert_prange(long val, long min, long max)
191
190
{
192
 
        int range = max - min;
 
191
        long range = max - min;
193
192
        int tmp;
194
193
 
195
194
        if (range == 0)
204
203
#define convert_prange1(val, min, max) \
205
204
        ceil((val) * ((max) - (min)) * 0.01 + (min))
206
205
 
207
 
static const char *get_percent(int val, int min, int max)
208
 
{
209
 
        static char str[32];
210
 
        int p;
211
 
        
212
 
        p = convert_prange(val, min, max);
213
 
        sprintf(str, "%i [%i%%]", val, p);
214
 
        return str;
215
 
}
216
 
 
217
 
#if 0
218
 
static const char *get_percent1(int val, int min, int max, int min_dB, int max_dB)
219
 
{
220
 
        static char str[32];
221
 
        int p, db;
222
 
 
223
 
        p = convert_prange(val, min, max);
224
 
        db = convert_db_range(val, min, max, min_dB, max_dB);
225
 
        sprintf(str, "%i [%i%%] [%i.%02idB]", val, p, db / 100, abs(db % 100));
226
 
        return str;
227
 
}
228
 
#endif
229
 
 
230
 
static long get_integer(char **ptr, long min, long max)
231
 
{
232
 
        long val = min;
233
 
        char *p = *ptr, *s;
234
 
 
235
 
        if (*p == ':')
236
 
                p++;
237
 
        if (*p == '\0' || (!isdigit(*p) && *p != '-'))
238
 
                goto out;
239
 
 
240
 
        s = p;
241
 
        val = strtol(s, &p, 10);
242
 
        if (*p == '.') {
243
 
                p++;
244
 
                strtol(p, &p, 10);
245
 
        }
246
 
        if (*p == '%') {
247
 
                val = (long)convert_prange1(strtod(s, NULL), min, max);
248
 
                p++;
249
 
        }
250
 
        val = check_range(val, min, max);
251
 
        if (*p == ',')
252
 
                p++;
253
 
 out:
254
 
        *ptr = p;
255
 
        return val;
256
 
}
257
 
 
258
 
static long get_integer64(char **ptr, long long min, long long max)
259
 
{
260
 
        long long val = min;
261
 
        char *p = *ptr, *s;
262
 
 
263
 
        if (*p == ':')
264
 
                p++;
265
 
        if (*p == '\0' || (!isdigit(*p) && *p != '-'))
266
 
                goto out;
267
 
 
268
 
        s = p;
269
 
        val = strtol(s, &p, 10);
270
 
        if (*p == '.') {
271
 
                p++;
272
 
                strtol(p, &p, 10);
273
 
        }
274
 
        if (*p == '%') {
275
 
                val = (long long)convert_prange1(strtod(s, NULL), min, max);
276
 
                p++;
277
 
        }
278
 
        val = check_range(val, min, max);
279
 
        if (*p == ',')
280
 
                p++;
281
 
 out:
282
 
        *ptr = p;
283
 
        return val;
284
 
}
285
 
 
286
206
struct volume_ops {
287
207
        int (*get_range)(snd_mixer_elem_t *elem, long *min, long *max);
288
208
        int (*get)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
289
209
                   long *value);
290
210
        int (*set)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
291
 
                   long value);
 
211
                   long value, int dir);
292
212
};
293
213
        
294
 
enum { VOL_RAW, VOL_DB };
 
214
enum { VOL_RAW, VOL_DB, VOL_MAP };
295
215
 
296
216
struct volume_ops_set {
297
217
        int (*has_volume)(snd_mixer_elem_t *elem);
298
 
        struct volume_ops v[2];
 
218
        struct volume_ops v[3];
299
219
};
300
220
 
301
221
static int set_playback_dB(snd_mixer_elem_t *elem,
302
 
                           snd_mixer_selem_channel_id_t c, long value)
 
222
                           snd_mixer_selem_channel_id_t c, long value, int dir)
303
223
{
304
 
        return snd_mixer_selem_set_playback_dB(elem, c, value, 0);
 
224
        return snd_mixer_selem_set_playback_dB(elem, c, value, dir);
305
225
}
306
226
 
307
227
static int set_capture_dB(snd_mixer_elem_t *elem,
308
 
                          snd_mixer_selem_channel_id_t c, long value)
309
 
{
310
 
        return snd_mixer_selem_set_capture_dB(elem, c, value, 0);
 
228
                          snd_mixer_selem_channel_id_t c, long value, int dir)
 
229
{
 
230
        return snd_mixer_selem_set_capture_dB(elem, c, value, dir);
 
231
}
 
232
 
 
233
static int set_playback_raw_volume(snd_mixer_elem_t *elem,
 
234
                                   snd_mixer_selem_channel_id_t c,
 
235
                                   long value, int dir)
 
236
{
 
237
        return snd_mixer_selem_set_playback_volume(elem, c, value);
 
238
}
 
239
 
 
240
static int set_capture_raw_volume(snd_mixer_elem_t *elem,
 
241
                                  snd_mixer_selem_channel_id_t c,
 
242
                                  long value, int dir)
 
243
{
 
244
        return snd_mixer_selem_set_capture_volume(elem, c, value);
 
245
}
 
246
 
 
247
/* FIXME: normalize to int32 space to be compatible with other types */
 
248
#define MAP_VOL_RES     (INT32_MAX / 100)
 
249
 
 
250
static int get_mapped_volume_range(snd_mixer_elem_t *elem,
 
251
                                   long *pmin, long *pmax)
 
252
{
 
253
        *pmin = 0;
 
254
        *pmax = MAP_VOL_RES;
 
255
        return 0;
 
256
}
 
257
 
 
258
static int get_playback_mapped_volume(snd_mixer_elem_t *elem,
 
259
                                      snd_mixer_selem_channel_id_t c,
 
260
                                      long *value)
 
261
{
 
262
        *value = (rint)(get_normalized_playback_volume(elem, c) * MAP_VOL_RES);
 
263
        return 0;
 
264
}
 
265
 
 
266
static int set_playback_mapped_volume(snd_mixer_elem_t *elem,
 
267
                                      snd_mixer_selem_channel_id_t c,
 
268
                                      long value, int dir)
 
269
{
 
270
        return set_normalized_playback_volume(elem, c,
 
271
                                              (double)value / MAP_VOL_RES, dir);
 
272
}
 
273
 
 
274
static int get_capture_mapped_volume(snd_mixer_elem_t *elem,
 
275
                                     snd_mixer_selem_channel_id_t c,
 
276
                                     long *value)
 
277
{
 
278
        *value = (rint)(get_normalized_capture_volume(elem, c) * MAP_VOL_RES);
 
279
        return 0;
 
280
}
 
281
 
 
282
static int set_capture_mapped_volume(snd_mixer_elem_t *elem,
 
283
                                     snd_mixer_selem_channel_id_t c,
 
284
                                     long value, int dir)
 
285
{
 
286
        return set_normalized_capture_volume(elem, c,
 
287
                                             (double)value / MAP_VOL_RES, dir);
311
288
}
312
289
 
313
290
static const struct volume_ops_set vol_ops[2] = {
315
292
                .has_volume = snd_mixer_selem_has_playback_volume,
316
293
                .v = {{ snd_mixer_selem_get_playback_volume_range,
317
294
                        snd_mixer_selem_get_playback_volume,
318
 
                        snd_mixer_selem_set_playback_volume },
 
295
                        set_playback_raw_volume },
319
296
                      { snd_mixer_selem_get_playback_dB_range,
320
297
                        snd_mixer_selem_get_playback_dB,
321
 
                        set_playback_dB }},
 
298
                        set_playback_dB },
 
299
                      { get_mapped_volume_range,
 
300
                        get_playback_mapped_volume,
 
301
                        set_playback_mapped_volume },
 
302
                },
322
303
        },
323
304
        {
324
305
                .has_volume = snd_mixer_selem_has_capture_volume,
325
306
                .v = {{ snd_mixer_selem_get_capture_volume_range,
326
307
                        snd_mixer_selem_get_capture_volume,
327
 
                        snd_mixer_selem_set_capture_volume },
 
308
                        set_capture_raw_volume },
328
309
                      { snd_mixer_selem_get_capture_dB_range,
329
310
                        snd_mixer_selem_get_capture_dB,
330
 
                        set_capture_dB }},
 
311
                        set_capture_dB },
 
312
                      { get_mapped_volume_range,
 
313
                        get_capture_mapped_volume,
 
314
                        set_capture_mapped_volume },
 
315
                },
331
316
        },
332
317
};
333
318
 
 
319
static int std_vol_type = VOL_RAW;
 
320
 
334
321
static int set_volume_simple(snd_mixer_elem_t *elem,
335
322
                             snd_mixer_selem_channel_id_t chn,
336
323
                             char **ptr, int dir)
337
324
{
338
325
        long val, orig, pmin, pmax;
339
326
        char *p = *ptr, *s;
340
 
        int invalid = 0, err = 0, vol_type = VOL_RAW;
 
327
        int invalid = 0, percent = 0, err = 0;
 
328
        int vol_type = std_vol_type;
 
329
        double scale = 1.0;
 
330
        int correct = 0;
341
331
 
342
332
        if (! vol_ops[dir].has_volume(elem))
343
333
                invalid = 1;
347
337
        if (*p == '\0' || (!isdigit(*p) && *p != '-'))
348
338
                goto skip;
349
339
 
350
 
        if (! invalid &&
351
 
            vol_ops[dir].v[VOL_RAW].get_range(elem, &pmin, &pmax) < 0)
352
 
                invalid = 1;
353
 
 
354
340
        s = p;
355
341
        val = strtol(s, &p, 10);
356
342
        if (*p == '.') {
358
344
                strtol(p, &p, 10);
359
345
        }
360
346
        if (*p == '%') {
361
 
                if (! invalid)
362
 
                        val = (long)convert_prange1(strtod(s, NULL), pmin, pmax);
 
347
                percent = 1;
363
348
                p++;
364
349
        } else if (p[0] == 'd' && p[1] == 'B') {
365
 
                if (! invalid) {
366
 
                        val = (long)(strtod(s, NULL) * 100.0);
367
 
                        vol_type = VOL_DB;
368
 
                        if (vol_ops[dir].v[vol_type].get_range(elem, &pmin, &pmax) < 0)
369
 
                                invalid = 1;
370
 
                }
 
350
                vol_type = VOL_DB;
371
351
                p += 2;
372
 
        }
 
352
                scale = 100;
 
353
        } else
 
354
                vol_type = VOL_RAW;
 
355
 
 
356
        val = (long)(strtod(s, NULL) * scale);
 
357
        if (vol_ops[dir].v[vol_type].get_range(elem, &pmin, &pmax) < 0)
 
358
                invalid = 1;
 
359
        if (percent)
 
360
                val = (long)convert_prange1(val, pmin, pmax);
373
361
        if (*p == '+' || *p == '-') {
374
362
                if (! invalid) {
375
363
                        if (vol_ops[dir].v[vol_type].get(elem, chn, &orig) < 0)
376
364
                                invalid = 1;
377
 
                        if (*p == '+')
 
365
                        if (*p == '+') {
378
366
                                val = orig + val;
379
 
                        else
 
367
                                correct = 1;
 
368
                        } else {
380
369
                                val = orig - val;
 
370
                                correct = -1;
 
371
                        }
381
372
                }
382
373
                p++;
383
374
        }
384
375
        if (! invalid) {
385
376
                val = check_range(val, pmin, pmax);
386
 
                err = vol_ops[dir].v[vol_type].set(elem, chn, val);
 
377
                err = vol_ops[dir].v[vol_type].set(elem, chn, val, correct);
387
378
        }
388
379
 skip:
389
380
        if (*p == ',')
424
415
                
425
416
static void show_control_id(snd_ctl_elem_id_t *id)
426
417
{
427
 
        unsigned int index, device, subdevice;
428
 
        printf("numid=%u,iface=%s,name='%s'",
429
 
               snd_ctl_elem_id_get_numid(id),
430
 
               control_iface(id),
431
 
               snd_ctl_elem_id_get_name(id));
432
 
        index = snd_ctl_elem_id_get_index(id);
433
 
        device = snd_ctl_elem_id_get_device(id);
434
 
        subdevice = snd_ctl_elem_id_get_subdevice(id);
435
 
        if (index)
436
 
                printf(",index=%i", index);
437
 
        if (device)
438
 
                printf(",device=%i", device);
439
 
        if (subdevice)
440
 
                printf(",subdevice=%i", subdevice);
 
418
        char *str;
 
419
 
 
420
        str = snd_ctl_ascii_elem_id_get(id);
 
421
        if (str)
 
422
                printf("%s", str);
 
423
        free(str);
441
424
}
442
425
 
443
426
static void print_spaces(unsigned int spaces)
479
462
                                printf("TLV size error in compound!\n");
480
463
                                return;
481
464
                        }
482
 
                        decode_tlv(spaces + 2, tlv + idx, tlv[idx+1]);
 
465
                        decode_tlv(spaces + 2, tlv + idx, tlv[idx+1] + 8);
483
466
                        idx += 2 + (tlv[1] + sizeof(unsigned int) - 1) / sizeof(unsigned int);
484
467
                }
485
468
                break;
508
491
                        }
509
492
                } else {
510
493
                        printf("min=");
511
 
                        print_dB(tlv[2]);
 
494
                        print_dB((int)tlv[2]);
512
495
                        printf(",max=");
513
 
                        print_dB(tlv[3]);
 
496
                        print_dB((int)tlv[3]);
514
497
                }
515
498
                break;
516
499
#endif
548
531
                        }
549
532
                } else {
550
533
                        printf("min=");
551
 
                        print_dB(tlv[2]);
 
534
                        print_dB((int)tlv[2]);
552
535
                        printf(",max=");
553
 
                        print_dB(tlv[3]);
 
536
                        print_dB((int)tlv[3]);
554
537
                }
555
538
                break;
556
539
#endif
711
694
        return 0;
712
695
}
713
696
 
 
697
static void show_selem_volume(snd_mixer_elem_t *elem, 
 
698
                              snd_mixer_selem_channel_id_t chn, int dir,
 
699
                              long min, long max)
 
700
{
 
701
        long raw, val;
 
702
        vol_ops[dir].v[VOL_RAW].get(elem, chn, &raw);
 
703
        if (std_vol_type == VOL_RAW)
 
704
                val = convert_prange(raw, min, max);
 
705
        else {
 
706
                vol_ops[dir].v[std_vol_type].get(elem, chn, &val);
 
707
                val = convert_prange(val, 0, MAP_VOL_RES);
 
708
        }
 
709
        printf(" %li [%li%%]", raw, val);
 
710
        if (!vol_ops[dir].v[VOL_DB].get(elem, chn, &val)) {
 
711
                printf(" [");
 
712
                print_dB(val);
 
713
                printf("]");
 
714
        }
 
715
}
 
716
 
714
717
static int show_selem(snd_mixer_t *handle, snd_mixer_selem_id_t *id, const char *space, int level)
715
718
{
716
719
        snd_mixer_selem_channel_id_t chn;
717
720
        long pmin = 0, pmax = 0;
718
721
        long cmin = 0, cmax = 0;
719
 
        long pvol, cvol;
720
722
        int psw, csw;
721
723
        int pmono, cmono, mono_ok = 0;
722
 
        long db;
723
724
        snd_mixer_elem_t *elem;
724
725
        
725
726
        elem = snd_mixer_find_selem(handle, id);
868
869
                                mono_ok = 1;
869
870
                        }
870
871
                        if (snd_mixer_selem_has_common_volume(elem)) {
871
 
                                snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &pvol);
872
 
                                printf(" %s", get_percent(pvol, pmin, pmax));
873
 
                                if (!snd_mixer_selem_get_playback_dB(elem, SND_MIXER_SCHN_MONO, &db)) {
874
 
                                        printf(" [");
875
 
                                        print_dB(db);
876
 
                                        printf("]");
877
 
                                }
 
872
                                show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax);
878
873
                        }
879
874
                        if (snd_mixer_selem_has_common_switch(elem)) {
880
875
                                snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw);
891
886
                                if (snd_mixer_selem_has_playback_volume(elem)) {
892
887
                                        printf(" Playback");
893
888
                                        title = 1;
894
 
                                        snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &pvol);
895
 
                                        printf(" %s", get_percent(pvol, pmin, pmax));
896
 
                                        if (!snd_mixer_selem_get_playback_dB(elem, SND_MIXER_SCHN_MONO, &db)) {
897
 
                                                printf(" [");
898
 
                                                print_dB(db);
899
 
                                                printf("]");
900
 
                                        }
 
889
                                        show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax);
901
890
                                }
902
891
                        }
903
892
                        if (!snd_mixer_selem_has_common_switch(elem)) {
919
908
                                if (snd_mixer_selem_has_capture_volume(elem)) {
920
909
                                        printf(" Capture");
921
910
                                        title = 1;
922
 
                                        snd_mixer_selem_get_capture_volume(elem, SND_MIXER_SCHN_MONO, &cvol);
923
 
                                        printf(" %s", get_percent(cvol, cmin, cmax));
924
 
                                        if (!snd_mixer_selem_get_capture_dB(elem, SND_MIXER_SCHN_MONO, &db)) {
925
 
                                                printf(" [");
926
 
                                                print_dB(db);
927
 
                                                printf("]");
928
 
                                        }
 
911
                                        show_selem_volume(elem, SND_MIXER_SCHN_MONO, 1, cmin, cmax);
929
912
                                }
930
913
                        }
931
914
                        if (!snd_mixer_selem_has_common_switch(elem)) {
946
929
                                        continue;
947
930
                                printf("%s%s:", space, snd_mixer_selem_channel_name(chn));
948
931
                                if (!pmono && !cmono && snd_mixer_selem_has_common_volume(elem)) {
949
 
                                        snd_mixer_selem_get_playback_volume(elem, chn, &pvol);
950
 
                                        printf(" %s", get_percent(pvol, pmin, pmax));
951
 
                                        if (!snd_mixer_selem_get_playback_dB(elem, chn, &db)) {
952
 
                                                printf(" [");
953
 
                                                print_dB(db);
954
 
                                                printf("]");
955
 
                                        }
 
932
                                        show_selem_volume(elem, chn, 0, pmin, pmax);
956
933
                                }
957
934
                                if (!pmono && !cmono && snd_mixer_selem_has_common_switch(elem)) {
958
935
                                        snd_mixer_selem_get_playback_switch(elem, chn, &psw);
964
941
                                                if (snd_mixer_selem_has_playback_volume(elem)) {
965
942
                                                        printf(" Playback");
966
943
                                                        title = 1;
967
 
                                                        snd_mixer_selem_get_playback_volume(elem, chn, &pvol);
968
 
                                                        printf(" %s", get_percent(pvol, pmin, pmax));
969
 
                                                        if (!snd_mixer_selem_get_playback_dB(elem, chn, &db)) {
970
 
                                                                printf(" [");
971
 
                                                                print_dB(db);
972
 
                                                                printf("]");
973
 
                                                        }
 
944
                                                        show_selem_volume(elem, chn, 0, pmin, pmax);
974
945
                                                }
975
946
                                        }
976
947
                                        if (!snd_mixer_selem_has_common_switch(elem)) {
988
959
                                                if (snd_mixer_selem_has_capture_volume(elem)) {
989
960
                                                        printf(" Capture");
990
961
                                                        title = 1;
991
 
                                                        snd_mixer_selem_get_capture_volume(elem, chn, &cvol);
992
 
                                                        printf(" %s", get_percent(cvol, cmin, cmax));
993
 
                                                        if (!snd_mixer_selem_get_capture_dB(elem, chn, &db)) {
994
 
                                                                printf(" [");
995
 
                                                                print_dB(db);
996
 
                                                                printf("]");
997
 
                                                        }
 
962
                                                        show_selem_volume(elem, chn, 1, cmin, cmax);
998
963
                                                }
999
964
                                        }
1000
965
                                        if (!snd_mixer_selem_has_common_switch(elem)) {
1052
1017
        return 0;
1053
1018
}
1054
1019
 
1055
 
static int parse_control_id(const char *str, snd_ctl_elem_id_t *id)
1056
 
{
1057
 
        int c, size, numid;
1058
 
        char *ptr;
1059
 
 
1060
 
        while (*str == ' ' || *str == '\t')
1061
 
                str++;
1062
 
        if (!(*str))
1063
 
                return -EINVAL;
1064
 
        snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);    /* default */
1065
 
        while (*str) {
1066
 
                if (!strncasecmp(str, "numid=", 6)) {
1067
 
                        str += 6;
1068
 
                        numid = atoi(str);
1069
 
                        if (numid <= 0) {
1070
 
                                fprintf(stderr, "amixer: Invalid numid %d\n", numid);
1071
 
                                return -EINVAL;
1072
 
                        }
1073
 
                        snd_ctl_elem_id_set_numid(id, atoi(str));
1074
 
                        while (isdigit(*str))
1075
 
                                str++;
1076
 
                } else if (!strncasecmp(str, "iface=", 6)) {
1077
 
                        str += 6;
1078
 
                        if (!strncasecmp(str, "card", 4)) {
1079
 
                                snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
1080
 
                                str += 4;
1081
 
                        } else if (!strncasecmp(str, "mixer", 5)) {
1082
 
                                snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
1083
 
                                str += 5;
1084
 
                        } else if (!strncasecmp(str, "pcm", 3)) {
1085
 
                                snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
1086
 
                                str += 3;
1087
 
                        } else if (!strncasecmp(str, "rawmidi", 7)) {
1088
 
                                snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_RAWMIDI);
1089
 
                                str += 7;
1090
 
                        } else if (!strncasecmp(str, "timer", 5)) {
1091
 
                                snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_TIMER);
1092
 
                                str += 5;
1093
 
                        } else if (!strncasecmp(str, "sequencer", 9)) {
1094
 
                                snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_SEQUENCER);
1095
 
                                str += 9;
1096
 
                        } else {
1097
 
                                return -EINVAL;
1098
 
                        }
1099
 
                } else if (!strncasecmp(str, "name=", 5)) {
1100
 
                        char buf[64];
1101
 
                        str += 5;
1102
 
                        ptr = buf;
1103
 
                        size = 0;
1104
 
                        if (*str == '\'' || *str == '\"') {
1105
 
                                c = *str++;
1106
 
                                while (*str && *str != c) {
1107
 
                                        if (size < (int)sizeof(buf)) {
1108
 
                                                *ptr++ = *str;
1109
 
                                                size++;
1110
 
                                        }
1111
 
                                        str++;
1112
 
                                }
1113
 
                                if (*str == c)
1114
 
                                        str++;
1115
 
                        } else {
1116
 
                                while (*str && *str != ',') {
1117
 
                                        if (size < (int)sizeof(buf)) {
1118
 
                                                *ptr++ = *str;
1119
 
                                                size++;
1120
 
                                        }
1121
 
                                        str++;
1122
 
                                }
1123
 
                        }
1124
 
                        *ptr = '\0';
1125
 
                        snd_ctl_elem_id_set_name(id, buf);
1126
 
                } else if (!strncasecmp(str, "index=", 6)) {
1127
 
                        str += 6;
1128
 
                        snd_ctl_elem_id_set_index(id, atoi(str));
1129
 
                        while (isdigit(*str))
1130
 
                                str++;
1131
 
                } else if (!strncasecmp(str, "device=", 7)) {
1132
 
                        str += 7;
1133
 
                        snd_ctl_elem_id_set_device(id, atoi(str));
1134
 
                        while (isdigit(*str))
1135
 
                                str++;
1136
 
                } else if (!strncasecmp(str, "subdevice=", 10)) {
1137
 
                        str += 10;
1138
 
                        snd_ctl_elem_id_set_subdevice(id, atoi(str));
1139
 
                        while (isdigit(*str))
1140
 
                                str++;
1141
 
                }
1142
 
                if (*str == ',') {
1143
 
                        str++;
1144
 
                } else {
1145
 
                        if (*str)
1146
 
                                return -EINVAL;
1147
 
                }
1148
 
        }                       
1149
 
        return 0;
1150
 
}
1151
 
 
1152
1020
static int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid)
1153
1021
{
1154
1022
        int c, size;
1197
1065
        return 0;
1198
1066
}
1199
1067
 
1200
 
static int get_ctl_enum_item_index(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
1201
 
                                   char **ptrp)
1202
 
{
1203
 
        char *ptr = *ptrp;
1204
 
        int items, i, len;
1205
 
        const char *name;
1206
 
        
1207
 
        items = snd_ctl_elem_info_get_items(info);
1208
 
        if (items <= 0)
1209
 
                return -1;
1210
 
 
1211
 
        for (i = 0; i < items; i++) {
1212
 
                snd_ctl_elem_info_set_item(info, i);
1213
 
                if (snd_ctl_elem_info(handle, info) < 0)
1214
 
                        return -1;
1215
 
                name = snd_ctl_elem_info_get_item_name(info);
1216
 
                len = strlen(name);
1217
 
                if (! strncmp(name, ptr, len)) {
1218
 
                        if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') {
1219
 
                                ptr += len;
1220
 
                                *ptrp = ptr;
1221
 
                                return i;
1222
 
                        }
1223
 
                }
1224
 
        }
1225
 
        return -1;
1226
 
}
1227
 
 
1228
1068
static int cset(int argc, char *argv[], int roflag, int keep_handle)
1229
1069
{
1230
1070
        int err;
1232
1072
        snd_ctl_elem_info_t *info;
1233
1073
        snd_ctl_elem_id_t *id;
1234
1074
        snd_ctl_elem_value_t *control;
1235
 
        char *ptr;
1236
 
        unsigned int idx, count;
1237
 
        long tmp;
1238
 
        snd_ctl_elem_type_t type;
1239
1075
        snd_ctl_elem_info_alloca(&info);
1240
1076
        snd_ctl_elem_id_alloca(&id);
1241
1077
        snd_ctl_elem_value_alloca(&control);
1244
1080
                fprintf(stderr, "Specify a full control identifier: [[iface=<iface>,][name='name',][index=<index>,][device=<device>,][subdevice=<subdevice>]]|[numid=<numid>]\n");
1245
1081
                return -EINVAL;
1246
1082
        }
1247
 
        if (parse_control_id(argv[0], id)) {
 
1083
        if (snd_ctl_ascii_elem_id_parse(id, argv[0])) {
1248
1084
                fprintf(stderr, "Wrong control identifier: %s\n", argv[0]);
1249
1085
                return -EINVAL;
1250
1086
        }
1269
1105
                }
1270
1106
                return err;
1271
1107
        }
1272
 
        snd_ctl_elem_info_get_id(info, id);     /* FIXME: Remove it when hctl find works ok !!! */
1273
 
        type = snd_ctl_elem_info_get_type(info);
1274
 
        count = snd_ctl_elem_info_get_count(info);
1275
 
        snd_ctl_elem_value_set_id(control, id);
1276
 
        
 
1108
        snd_ctl_elem_info_get_id(info, id);     /* FIXME: Remove it when hctl find works ok !!! */
1277
1109
        if (!roflag) {
1278
 
                ptr = argv[1];
1279
 
                for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) {
1280
 
                        switch (type) {
1281
 
                        case SND_CTL_ELEM_TYPE_BOOLEAN:
1282
 
                                tmp = 0;
1283
 
                                if (!strncasecmp(ptr, "on", 2) || !strncasecmp(ptr, "up", 2)) {
1284
 
                                        tmp = 1;
1285
 
                                        ptr += 2;
1286
 
                                } else if (!strncasecmp(ptr, "yes", 3)) {
1287
 
                                        tmp = 1;
1288
 
                                        ptr += 3;
1289
 
                                } else if (!strncasecmp(ptr, "toggle", 6)) {
1290
 
                                        tmp = snd_ctl_elem_value_get_boolean(control, idx);
1291
 
                                        tmp = tmp > 0 ? 0 : 1;
1292
 
                                        ptr += 6;
1293
 
                                } else if (isdigit(*ptr)) {
1294
 
                                        tmp = atoi(ptr) > 0 ? 1 : 0;
1295
 
                                        while (isdigit(*ptr))
1296
 
                                                ptr++;
1297
 
                                } else {
1298
 
                                        while (*ptr && *ptr != ',')
1299
 
                                                ptr++;
1300
 
                                }
1301
 
                                snd_ctl_elem_value_set_boolean(control, idx, tmp);
1302
 
                                break;
1303
 
                        case SND_CTL_ELEM_TYPE_INTEGER:
1304
 
                                tmp = get_integer(&ptr,
1305
 
                                                  snd_ctl_elem_info_get_min(info),
1306
 
                                                  snd_ctl_elem_info_get_max(info));
1307
 
                                snd_ctl_elem_value_set_integer(control, idx, tmp);
1308
 
                                break;
1309
 
                        case SND_CTL_ELEM_TYPE_INTEGER64:
1310
 
                                tmp = get_integer64(&ptr,
1311
 
                                                  snd_ctl_elem_info_get_min64(info),
1312
 
                                                  snd_ctl_elem_info_get_max64(info));
1313
 
                                snd_ctl_elem_value_set_integer64(control, idx, tmp);
1314
 
                                break;
1315
 
                        case SND_CTL_ELEM_TYPE_ENUMERATED:
1316
 
                                tmp = get_ctl_enum_item_index(handle, info, &ptr);
1317
 
                                if (tmp < 0)
1318
 
                                        tmp = get_integer(&ptr, 0, snd_ctl_elem_info_get_items(info) - 1);
1319
 
                                snd_ctl_elem_value_set_enumerated(control, idx, tmp);
1320
 
                                break;
1321
 
                        case SND_CTL_ELEM_TYPE_BYTES:
1322
 
                                tmp = get_integer(&ptr, 0, 255);
1323
 
                                snd_ctl_elem_value_set_byte(control, idx, tmp);
1324
 
                                break;
1325
 
                        default:
1326
 
                                break;
1327
 
                        }
1328
 
                        if (!strchr(argv[1], ','))
1329
 
                                ptr = argv[1];
1330
 
                        else if (*ptr == ',')
1331
 
                                ptr++;
 
1110
                snd_ctl_elem_value_set_id(control, id);
 
1111
                if ((err = snd_ctl_elem_read(handle, control)) < 0) {
 
1112
                        if (ignore_error)
 
1113
                                return 0;
 
1114
                        error("Cannot read the given element from control %s\n", card);
 
1115
                        if (! keep_handle) {
 
1116
                                snd_ctl_close(handle);
 
1117
                                handle = NULL;
 
1118
                        }
 
1119
                        return err;
 
1120
                }
 
1121
                err = snd_ctl_ascii_value_parse(handle, control, info, argv[1]);
 
1122
                if (err < 0) {
 
1123
                        if (!ignore_error)
 
1124
                                error("Control %s parse error: %s\n", card, snd_strerror(err));
 
1125
                        if (!keep_handle) {
 
1126
                                snd_ctl_close(handle);
 
1127
                                handle = NULL;
 
1128
                        }
 
1129
                        return ignore_error ? 0 : err;
1332
1130
                }
1333
1131
                if ((err = snd_ctl_elem_write(handle, control)) < 0) {
1334
1132
                        if (!ignore_error)
1927
1725
                {"version", 0, NULL, 'v'},
1928
1726
                {"abstract", 1, NULL, 'a'},
1929
1727
                {"stdin", 0, NULL, 's'},
 
1728
                {"raw-volume", 0, NULL, 'R'},
 
1729
                {"mapped-volume", 0, NULL, 'M'},
1930
1730
                {NULL, 0, NULL, 0},
1931
1731
        };
1932
1732
 
1934
1734
        while (1) {
1935
1735
                int c;
1936
1736
 
1937
 
                if ((c = getopt_long(argc, argv, "hc:D:qidnva:s", long_option, NULL)) < 0)
 
1737
                if ((c = getopt_long(argc, argv, "hc:D:qidnva:sRM", long_option, NULL)) < 0)
1938
1738
                        break;
1939
1739
                switch (c) {
1940
1740
                case 'h':
1987
1787
                case 's':
1988
1788
                        read_stdin = 1;
1989
1789
                        break;
 
1790
                case 'R':
 
1791
                        std_vol_type = VOL_RAW;
 
1792
                        break;
 
1793
                case 'M':
 
1794
                        std_vol_type = VOL_MAP;
 
1795
                        break;
1990
1796
                default:
1991
1797
                        fprintf(stderr, "Invalid switch or option needs an argument.\n");
1992
1798
                        morehelp++;