diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
commit | 1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch) | |
tree | 4495d23e7b54ab5700e3839081e797c1eafe0db9 /utils | |
download | oss4-1058def8e7827e56ce4a70afb4aeacb5dc44148f.tar.gz |
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'utils')
-rw-r--r-- | utils/.nomake | 0 | ||||
-rw-r--r-- | utils/Makefile | 17 | ||||
-rw-r--r-- | utils/README | 60 | ||||
-rw-r--r-- | utils/lin-inject.sh | 141 | ||||
-rw-r--r-- | utils/mixgen.c | 800 | ||||
-rw-r--r-- | utils/mixgen2.c | 1233 | ||||
-rw-r--r-- | utils/ossmkdep.c | 234 | ||||
-rwxr-xr-x | utils/phpmake | 27 | ||||
-rw-r--r-- | utils/readtimings.c | 61 | ||||
-rw-r--r-- | utils/snoopy.c | 901 | ||||
-rwxr-xr-x | utils/vib | 9 | ||||
-rwxr-xr-x | utils/vif | 9 | ||||
-rwxr-xr-x | utils/vil | 9 | ||||
-rwxr-xr-x | utils/vil24 | 3 | ||||
-rwxr-xr-x | utils/vis | 9 | ||||
-rwxr-xr-x | utils/viu | 9 | ||||
-rwxr-xr-x | utils/viv | 9 |
17 files changed, 3531 insertions, 0 deletions
diff --git a/utils/.nomake b/utils/.nomake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/utils/.nomake diff --git a/utils/Makefile b/utils/Makefile new file mode 100644 index 0000000..86fe4fa --- /dev/null +++ b/utils/Makefile @@ -0,0 +1,17 @@ +CFLAGS=-I../include + +PROGRAMS=snoopy mixgen readtimings + +all: $(PROGRAMS) + +snoopy: snoopy.c ../kernel/drv/oss_hdaudio/hdaudio.h + $(CC) -o snoopy snoopy.c -I../kernel/drv/oss_hdaudio $(CFLAGS) + +mixgen: mixgen.c ../kernel/drv/oss_hdaudio/hdaudio.h + $(CC) -o mixgen mixgen.c -I../kernel/drv/oss_hdaudio $(CFLAGS) + +mixgen2: mixgen2.c ../kernel/drv/oss_hdaudio/hdaudio.h + $(CC) -o mixgen2 mixgen2.c -I../kernel/drv/oss_hdaudio $(CFLAGS) + +clean: + rm -f $(PROGRAMS) core core.* *.core *~ x y z *.o diff --git a/utils/README b/utils/README new file mode 100644 index 0000000..4ff708f --- /dev/null +++ b/utils/README @@ -0,0 +1,60 @@ +This directory contains some utilities, diagnostic tools and helper +scripts for developing, building and testing OSS. + +ossmkdep.c + +This is a simple utility that is used by "make dep". It lists the dependencies +of each the source files given in the command line. This utility is used since +GNU cpp is not available in all environments we support. It will be compiled +and used automatically when OSS is built. + +readtimings.c + +This is an internal diagnostic tool that can be used to extract run-time tracing +information produced by OSS. To use this feature you need to use +the --enable-timings option when configuring OSS. +Don't define this flag in production environment since it will cause +significant amount of CPU overhead. + +Compile this program using "make readtimings" and then copy it to (say) +/usr/local/bin. + +Then start readtimings>some_file.txt in one terminal window (or in backround). +Run the program you would like to debug in another window. Kill the readtimings +program as soon as the problem shows up (the listing may be very long). + +Now the produced file (say some_file.txt) will contain a trace of what +happened. Don't ask what all this means? + +snoopy.c + +An utility program for displaying information about a HD audio codec chip. +You need to edit hdaudio.conf and set the hdaudio_snoopy option to 1. The +program tries to open /dev/oss/hdaudio0/pcm0 and to obtain the codec information +from the driver. If the codec has some other codec number than 0 then you will +need to edit the source and to change the "int cad=0;" line to match the +codec number. This utility must be run as root. + +vif +vib +vil +vis +viu + +These are helper scripts for editing OSS files. Copy them to /usr/local. + +vif <file_mask> finds all files that match the given mask in the +current directory and it's source trees. For example vif os_*.h will launch +"vi" command for os.h files. + +vib, vil, vis, viu are similar commands for editing OS dependent files +for Freebsd, Linux, Solaris and SCO UnixWare/OpenServer (respectively). These +commands are usefull if you like to edit the build.sh file only for Linux (vil). +The fif buils.sh script will open them for all operating systems. + +mixgen.c + +This is a tool to generate dedicated mixer modules for HDAudio based laptops +and motherboards. Actually this program will generate just a template that +needs to be edited and fine tuned manually. Full instructions are available +at "http://developer.opensound.com/hdaudio_mixers.html". diff --git a/utils/lin-inject.sh b/utils/lin-inject.sh new file mode 100644 index 0000000..3d2126f --- /dev/null +++ b/utils/lin-inject.sh @@ -0,0 +1,141 @@ +#!/bin/sh + +if test "$1 " = " " +then + echo You need to give the Linux kernel directory as a argument. + exit 1 +fi + +TARGETDIR="$1" + +if ! test -d $TARGETDIR +then + echo $TARGETDIR does not exist. + exit 1 +fi + +echo +echo Kernel build directory is $TARGETDIR + +if test -d $TARGETDIR/sound/oss4 +then + echo error: $TARGETDIR/sound/oss4 already exists. Remove it and try again. + exit 1 +fi + +if ! test -d kernel/drv +then + echo You need to run this script inside the OSS source directory + exit 1 +fi + +echo Copying OSS files +if ! cp -R kernel $TARGETDIR/sound/oss4 +then + echo Failed to copy OSS files to $TARGETDIR/sound/oss4. + exit 1 +fi + +(cd $TARGETDIR/sound/oss4;mv OS/Linux linux_os;rm -rf OS) +cp setup/Linux/oss/build/*.c $TARGETDIR/sound/oss4/linux_os +cp setup/Linux/oss/build/*.h $TARGETDIR/sound/oss4/linux_os +cp setup/Linux/oss/build/*.inc $TARGETDIR/sound/oss4/linux_os +cp setup/Linux/oss/build/osscore.c $TARGETDIR/sound/oss4/framework/osscore/ + +rm -rf $TARGETDIR/sound/oss4/drv/Makefile + +# Remove some non-Linux drivers +rm -rf $TARGETDIR/sound/oss4/drv/oss_sadasupport +rm -rf $TARGETDIR/sound/oss4/drv/osscore +rm -rf $TARGETDIR/sound/oss4/drv/oss_audiocs +rm -rf $TARGETDIR/sound/oss4/nonfree + +# Remove MIDI support that is not functional yet. +rm -rf $TARGETDIR/sound/oss4/framework/midi + +# Remove all previous Makefiles that are bogus +find $TARGETDIR/sound/oss4 -name Makefile -exec rm {} ';' + +# Remove the man files +find $TARGETDIR/sound/oss4 -name '*.man' -exec rm {} ';' + +cat<<END_OF_CONFIG >$TARGETDIR/sound/oss4/Kconfig + +config OSS_VMIX + bool "Virtual audio mixer (vmix) suport" + default y + +config OSS_VMIX_FLOAT + bool "Use floating point arithmetic for vmix computations" + default y + +config OSS_MIDI + bool "MIDI support (partially functional)" + default n + +END_OF_CONFIG + +echo Generating drivers +for n in $TARGETDIR/sound/oss4/drv/* +do + N=`basename $n|tr 'a-z' 'A-Z'` + BN=`basename $n` + + echo config $N >>$TARGETDIR/sound/oss4/Kconfig + echo " tristate" \"`head -1 $n/.name`\">>$TARGETDIR/sound/oss4/Kconfig + echo " depends on" OSS4 >>$TARGETDIR/sound/oss4/Kconfig + echo " default y" >>$TARGETDIR/sound/oss4/Kconfig + echo >>$TARGETDIR/sound/oss4/Kconfig + + mv $TARGETDIR/sound/oss4/drv/$BN/$BN.c $TARGETDIR/sound/oss4/drv/$BN/"$BN"_main.c + cp target/build/$BN.c $TARGETDIR/sound/oss4/drv/$BN/"$BN"_stub.c + + echo obj-\$\(CONFIG_OSS_$N\) += drv\/$BN/ >> $TARGETDIR/sound/oss4/Makefile + echo obj-\$\(CONFIG_OSS_$N\) := $BN.o > $TARGETDIR/sound/oss4/drv/$BN/Makefile + echo >> $TARGETDIR/sound/oss4/drv/$BN/Makefile + + for fn in $TARGETDIR/sound/oss4/drv/$BN/*.c + do + fn=`basename $fn .c`.o + echo $BN-objs += $fn >> $TARGETDIR/sound/oss4/drv/$BN/Makefile + done +done + +echo Done + +if ! grep -q OSS4 $TARGETDIR/sound/Kconfig +then + + echo + echo NOTICE + echo + echo As the final step you need to copy/paste the following lines to + echo $TARGETDIR/sound/Kconfig + echo The right location is just above the last endmenu line. + + cat <<END_OF_CONFIG +----- cut here --- +menu "Open Sound System v4.x" + +config OSS4 + tristate "Open Sound System v4.x support" + depends on SOUND!=n + depends on !SND + depends on !SOUND_PRIME + help + This is version 4.x of Open Sound System. It replaces + the older (DEPRECATED) OSS version that has been included + in the kernel during past 10 years. + + You need to disabele both ALSA and the older OSS version + before being able to compile OSSv4. + +source "sound/oss4/Kconfig" +endmenu +----- cut here --- +END_OF_CONFIG + +echo Finally append the following line to $TARGETDIR/sound/Makefile +echo 'obj-$(CONFIG_OSS4) += oss4/' +fi +exit 0 diff --git a/utils/mixgen.c b/utils/mixgen.c new file mode 100644 index 0000000..1aed9cd --- /dev/null +++ b/utils/mixgen.c @@ -0,0 +1,800 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <string.h> +#include <soundcard.h> + +typedef int sound_os_info, mixer_create_controls_t, oss_device_t; + +#include <hdaudio.h> + +#define ioctl_arg int +#define mixer_ext_init_fn int +#include <hdaudio_codec.h> + +static int num_widgets = 0; + +static int print_widgets = 0; + +typedef struct +{ + int type; + int valid; + int used; + + char name[32]; + + unsigned int wcaps; + unsigned int pincaps; + unsigned int inamp_caps; + unsigned int outamp_caps; + int nconn; + int connections[MAX_CONN]; + widget_t widget_info; +} mixgen_widget_t; + +static mixgen_widget_t widgets[256] = { {0} }; + +static int errors = 0; + +static unsigned int default_outamp_caps = 0; +static unsigned int default_inamp_caps = 0; +static unsigned int subdevice = 0; + +#undef corb_read +#undef corb_write + +int fd; +void *mixer = NULL; +int trace = 0; + +int cad = -1; + +int +corb_write (void *dc, unsigned int cad, unsigned int nid, unsigned int d, + unsigned int verb, unsigned int parm) +{ + unsigned int tmp; + + tmp = (cad << 28) | (d << 27) | (nid << 20) | (verb << 8) | parm; + if (trace) + printf ("WRITE %08x\n", tmp); + + if (ioctl (fd, HDA_IOCTL_WRITE, &tmp) == -1) + { + /* perror("HDA_IOCTL_WRITE"); */ + return 0; + } + + return 1; +} + +static int +corb_read (void *dc, unsigned int cad, unsigned int nid, unsigned int d, + unsigned int verb, unsigned int parm, unsigned int *upper, + unsigned int *lower) +{ + unsigned int tmp; + + tmp = (cad << 28) | (d << 27) | (nid << 20) | (verb << 8) | parm; + + if (ioctl (fd, HDA_IOCTL_READ, &tmp) == -1) + { + /* perror("HDA_IOCTL_READ"); */ + if (errno == EINVAL) + { + fprintf (stderr, "hdaudio_snoopy mode is not available\n"); + exit (-1); + } + return 0; + } + + *upper = tmp; + *lower = 0; + if (trace) + printf ("READ %08x\n", tmp); + + return 1; +} + +static int +set_error (char *msg) +{ + fprintf (stderr, "%s"); + errors++; + + return 0; +} + +static int +gen_amps (mixgen_widget_t * widget, int wid) +{ + int i; + char *name; + + if (widget->wcaps & WCAP_OUTPUT_AMP_PRESENT) + { + if (widget->outamp_caps & ~AMPCAP_MUTE) /* Has gain control */ + { + name = "-"; + if (widget->type == NT_PIN) + name = "invol"; + printf ("\t\tHDA_OUTAMP(0x%02x, group, \"%s\", 90);\n", wid, name); + } + else if (widget->outamp_caps & AMPCAP_MUTE) /* Only mute control */ + { + name = "mute"; + if (widget->type == NT_PIN) + name = "inmute"; + printf ("\t\tHDA_OUTMUTE(0x%02x, group, \"%s\", UNMUTE);\n", wid, + name); + } + } + + if (widget->wcaps & WCAP_INPUT_AMP_PRESENT) + { + int n = widget->nconn; + if (widget->type == NT_PIN) + n = 1; + + if (n > 1 && !(widget->inamp_caps & ~AMPCAP_MUTE)) + { /* Create mute group */ + printf ("\t\t{\n"); + printf ("\t\t\tint amp_group;\n\n"); + printf ("\t\t\tHDA_GROUP(amp_group, group, \"mute\");\n"); + for (i = 0; i < widget->nconn; i++) + { + char *name; + + name = widgets[widget->connections[i]].name; + if (widgets[widget->connections[i]].type == NT_PIN) + name = widgets[widget->connections[i]].widget_info.color; + printf + ("\t\t\tHDA_INMUTE(0x%02x, %d, amp_group, \"%s\", UNMUTE);\t/* From widget 0x%02x */\n", + wid, i, name, widget->connections[i]); + } + printf ("\t\t}\n"); + } + else + { + for (i = 0; i < n; i++) + { + char *name; + + name = widgets[widget->connections[i]].name; + if (widgets[widget->connections[i]].type == NT_PIN) + name = widgets[widget->connections[i]].widget_info.color; + if (widget->type == NT_PIN) + name = "out"; + if (widget->inamp_caps & ~AMPCAP_MUTE) /* Has gain control */ + { + printf + ("\t\tHDA_INAMP(0x%02x, %d, group, \"%s\", 90);\t/* From widget 0x%02x */\n", + wid, i, name, widget->connections[i]); + } + else + { + printf + ("\t\tHDA_INMUTE(0x%02x, %d, group, \"%smute\", UNMUTE);\t/* From widget 0x%02x */\n", + wid, i, name, widget->connections[i]); + } + } + } + } + + return 0; +} + +static int +follow_widget_chain (int wid, int force) +{ + int i; + char choice_list[1024] = "", *s = choice_list; + mixgen_widget_t *widget; + + if (!widgets[wid].valid || widgets[wid].used) + return 0; + + widget = &widgets[wid]; + + if (widget->widget_info.refcount > 1 && !force) + return 0; + + widget->used = 1; + + printf ("\n\t\t/* Widget 0x%02x (%s) */\n", wid, widget->name); + + for (i = 0; i < widget->nconn; i++) + { + char *name = widgets[widget->connections[i]].name; + if (widgets[widget->connections[i]].type == NT_PIN) + name = widgets[widget->connections[i]].widget_info.color; + if (i > 0) + *s++ = ' '; + if (widget->connections[i] < num_widgets) + strcpy (s, widgets[widget->connections[i]].name); + else + strcpy (s, "unknown"); + printf ("\t\t/* Src 0x%x=%s */\n", widget->connections[i], name); + s += strlen (s); + } + + if (widget->type == NT_SELECT && widget->nconn > 1) + { + printf ("\t\tif (HDA_SELECT(0x%02x, \"src\", ctl, group, -1))\n", wid); + printf ("\t\t {\n"); + printf ("\t\t\tHDA_CHOICES(ctl, \"%s\");\n", choice_list); + printf ("\t\t }\n"); + } + + gen_amps (widget, wid); +/* + * Follow the input connection chain. + */ + if (widget->nconn == 1) + follow_widget_chain (widget->connections[0], force); + + return 0; +} + +static int +handle_pin_widget (int wid, mixgen_widget_t * widget) +{ + int outselects = 0, inselects = 0, num_amps = 0; + char choice_list[1024] = "", *s = choice_list; + int i; + + widget->used = 1; + + if (widget->pincaps & PINCAP_INPUT_CAPABLE) + { + if (!(widget->wcaps & WCAP_DIGITAL)) /* Analog pin */ + { + inselects = 1; + } + } + + if (widget->pincaps & PINCAP_OUTPUT_CAPABLE) + { + if (!(widget->wcaps & WCAP_DIGITAL)) /* Analog pin */ + { + outselects = widget->nconn; + } + } + + if (widget->wcaps & WCAP_INPUT_AMP_PRESENT) + { + num_amps += widget->nconn; + } + + if (widget->wcaps & WCAP_OUTPUT_AMP_PRESENT) + { + num_amps++; + } + + if (inselects + outselects + num_amps == 0) + return 0; + + printf + ("\n\tif (HDA_PIN_GROUP(0x%02x, group, pin_group, \"%s\", n, \"jack\", 4))\t/* Pin widget 0x%02x */\n", + wid, widget->widget_info.color, wid); + printf ("\t {\n"); + + for (i = 0; i < widget->nconn; i++) + { + if (i > 0) + *s++ = ' '; + + if (widget->connections[i] < num_widgets) + sprintf (s, "%s-out", widgets[widget->connections[i]].name); + else + strcpy (s, "unknown"); + printf ("\t\t/* Src 0x%x=%s */\n", widget->connections[i], + widgets[widget->connections[i]].name); + s += strlen (s); + } + + if (widget->nconn > 0) + *s++ = ' '; + sprintf (s, "input"); + s += strlen (s); + + printf ("\t\tif (HDA_PINSELECT(0x%02x, ctl, group, \"mode\", -1))\n", wid); + printf ("\t\t\tHDA_CHOICES(ctl, \"%s\");\n", choice_list); + + gen_amps (widget, wid); + + for (i = 0; i < widget->nconn; i++) + follow_widget_chain (widget->connections[i], 0); + + printf ("\t }\n"); + + return 0; +} + +static int +handle_adc_widget (int wid, mixgen_widget_t * widget) +{ + int outselects = 0, inselects = 0, num_amps = 0; + char choice_list[4000] = "", *s = choice_list; + int i; + + widget->used = 1; + + if (widget->wcaps & WCAP_INPUT_AMP_PRESENT) + { + num_amps += widget->nconn; + } + + if (widget->wcaps & WCAP_OUTPUT_AMP_PRESENT) + { + num_amps++; + } + + printf + ("\n\tif (HDA_ADC_GROUP(0x%02x, group, rec_group, \"%s\", n, \"record\", 4))\t/* ADC widget 0x%02x */\n", + wid, widget->name, wid); + printf ("\t {\n"); + + for (i = 0; i < widget->nconn; i++) + { + if (i > 0) + *s++ = ' '; + if (widget->connections[i] < num_widgets) + strcpy (s, widgets[widget->connections[i]].name); + else + strcpy (s, "unknown"); + printf ("\t\t/* Src 0x%x=%s */\n", widget->connections[i], + widgets[widget->connections[i]].name); + s += strlen (s); + } + + if (widget->nconn > 1) + { + printf ("\t\tif (HDA_SELECT(0x%02x, \"src\", ctl, group, -1))\n", wid); + printf ("\t\t {\n"); + printf ("\t\t\tHDA_CHOICES(ctl, \"%s\");\n", choice_list); + printf ("\t\t }\n"); + } + + gen_amps (widget, wid); + + for (i = 0; i < widget->nconn; i++) + follow_widget_chain (widget->connections[i], 0); + + printf ("\t }\n"); + + return 0; +} + +static int +handle_misc_widget (int wid, mixgen_widget_t * widget) +{ + int outselects = 0, inselects = 0, num_amps = 0; + char choice_list[4000] = "", *s = choice_list; + int i; + + widget->used = 1; + + if (widget->wcaps & WCAP_INPUT_AMP_PRESENT) + { + num_amps += widget->nconn; + } + + if (widget->wcaps & WCAP_OUTPUT_AMP_PRESENT) + { + num_amps++; + } + + if (num_amps == 0) + return 0; + + printf + ("\n\tif (HDA_MISC_GROUP(0x%02x, group, misc_group, \"%s\", n, \"misc\", 8))\t/* Misc widget 0x%02x */\n", + wid, widget->name, wid); + printf ("\t {\n"); + + for (i = 0; i < widget->nconn; i++) + { + if (i > 0) + *s++ = ' '; + if (widget->connections[i] < num_widgets) + strcpy (s, widgets[widget->connections[i]].name); + else + strcpy (s, "unknown"); + printf ("\t\t/* Src 0x%x=%s */\n", widget->connections[i], + widgets[widget->connections[i]].name); + s += strlen (s); + } + + if (widget->type == NT_SELECT && widget->nconn > 1) + { + printf ("\t\tif (HDA_SELECT(0x%02x, \"src\", ctl, group, -1))\n", wid); + printf ("\t\t {\n"); + printf ("\t\t\tHDA_CHOICES(ctl, \"%s\");\n", choice_list); + printf ("\t\t }\n"); + } + + gen_amps (widget, wid); + + for (i = 0; i < widget->nconn; i++) + follow_widget_chain (widget->connections[i], 1); + + printf ("\t }\n"); + + return 0; +} + +static int +attach_widget (int wid) +{ + hda_name_t name; + hda_widget_info_t info; + unsigned int wcaps, b; + mixgen_widget_t *widget = &widgets[wid]; + int type; + int i; + unsigned int nconn, connections[256]; + + memset (&name, 0, sizeof (name)); + memset (&info, 0, sizeof (info)); + + name.cad = cad; + name.wid = wid; + if (ioctl (fd, HDA_IOCTL_NAME, &name) == -1) + strcpy (name.name, "Unknown_widget"); + + info.cad = cad; + info.wid = wid; + if (ioctl (fd, HDA_IOCTL_WIDGET, &info) != -1) + memcpy (&widget->widget_info, info.info, sizeof (widget->widget_info)); + + if (!corb_read + (mixer, cad, wid, 0, GET_PARAMETER, HDA_WIDGET_CAPS, &wcaps, &b)) + return set_error ("Can't get widget capabilities\n"); + + type = (wcaps >> 20) & 0xf; + + if (type == NT_PIN) + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_PIN_CAPS, &widget->pincaps, &b)) + return set_error ("Can't get widget pin capabilities\n"); + + widget->valid = 1; + strcpy (widget->name, name.name); + widget->wcaps = wcaps; + widget->inamp_caps = default_inamp_caps; + widget->outamp_caps = default_outamp_caps; + widget->type = type; + + /* + * Handle connection list. + */ + nconn = 0; + if (wcaps & WCAP_CONN_LIST) + { + + if (corb_read + (mixer, cad, wid, 0, GET_PARAMETER, HDA_CONNLIST_LEN, &nconn, &b)) + + if (nconn >= MAX_CONN) + { + fprintf (stderr, + "Too many input connections (%d) for widget %d\n", nconn, + wid); + exit (-1); + } + if (nconn != 0) + { + unsigned int clist; + int j; + int n = 0; + + nconn &= 0x7f; + + for (i = 0; i < nconn; i += 4) + if (corb_read + (mixer, cad, wid, 0, GET_CONNECTION_LIST_ENTRY, i, &clist, + &b)) + for (j = 0; j < 4 && (i + j) < nconn; j++) + { + connections[n++] = (clist >> (j * 8)) & 0xff; + } + } + } + + for (i = 0; i < nconn; i++) + widget->connections[i] = connections[i]; + widget->nconn = nconn; + + if ((wcaps & WCAP_AMP_CAP_OVERRIDE) && (wcaps & WCAP_OUTPUT_AMP_PRESENT)) + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_OUTPUTAMP_CAPS, + &widget->outamp_caps, &b)) + { + fprintf (stderr, "GET_PARAMETER HDA_OUTPUTAMP_CAPS failed\n"); + return set_error ("Can't get outamp capabilities\n"); + } + + if ((wcaps & WCAP_AMP_CAP_OVERRIDE) && (wcaps & WCAP_INPUT_AMP_PRESENT)) + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_INPUTAMP_CAPS, + &widget->inamp_caps, &b)) + { + fprintf (stderr, "GET_PARAMETER HDA_INPUTTAMP_CAPS failed\n"); + return set_error ("Can't get inamp capabilities\n"); + } + + return 0; +} + +static void +dump_node (int wid) +{ + int i; + unsigned int a, b, gtype, gcaps, wcaps, sizes, fmts, pincaps; + unsigned int inamp_caps, outamp_caps, clen, pstates, pcaps, gpio_count; + unsigned int vkcaps; + int first_node = 0, num_nodes = 0; + char *s; + int ntype = -1; + + if (corb_read + (mixer, cad, wid, 0, GET_PARAMETER, HDA_GROUP_TYPE, >ype, &b)) + if ((gtype & 0x1ff) != 0) + { + s = "Unknown"; + + switch (gtype & 0xff) + { + case 0: + s = "Reserved"; + return; + break; + case 1: + s = "Audio function group"; + break; + case 2: + s = "Vendor defined modem function group"; + //return; + break; + } + + } + if (corb_read (mixer, cad, wid, 0, GET_SUBSYSTEM_ID, 0, &a, &b)) + { + printf ("/* Subsystem ID %08x */\n", a); + subdevice = a; + } + + if (!corb_read (mixer, cad, wid, 0, GET_PARAMETER, HDA_NODE_COUNT, &a, &b)) + { + fprintf (stderr, "GET_PARAMETER HDA_NODE_COUNT2 failed\n"); + return; + } + + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_OUTPUTAMP_CAPS, + &default_outamp_caps, &b)) + { + fprintf (stderr, "GET_PARAMETER HDA_OUTPUTAMP_CAPS failed\n"); + return; + } + + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_INPUTAMP_CAPS, &default_inamp_caps, &b)) + { + fprintf (stderr, "GET_PARAMETER HDA_INPUTTAMP_CAPS failed\n"); + return; + } + + printf ("/* Default amplifier caps: in=%08x, out=%08x */\n", + default_inamp_caps, default_outamp_caps); + + first_node = (a >> 16) & 0xff; + num_nodes = a & 0xff; + + for (wid = first_node; wid < first_node + num_nodes; wid++) + { + attach_widget (wid); + if (wid >= num_widgets) + num_widgets = wid + 1; + } +} + +static void +dump_widgets (void) +{ + int i; + + for (i = 0; i < num_widgets; i++) + { + if (widgets[i].valid) + { + if (widgets[i].name[0] == 0) /* Empty string */ + printf("\tES,\n"); + else + printf ("\t\"%s\",\t\t/* 0x%02x */\n", widgets[i].name, i); + } + else + printf ("\tES,\t\t/* 0x%02x */\n", i); + } +} + +int +main (int argc, char *argv[]) +{ + unsigned int a, b; + int first_node, num_nodes; + int i; + char codec_name[32] = ""; + + if (argc > 1) + strcpy (codec_name, argv[1]); + + if ((fd = open ("/dev/oss/oss_hdaudio0/pcm0", O_RDWR | O_EXCL, 0)) == -1) + { + perror ("/dev/oss/oss_hdaudio0/pcm0"); + exit (-1); + } + + if (argc > 2) + cad = atoi (argv[2]); + + for (i = 3; i < argc; i++) + switch (argv[i][0]) + { + case 'w': + print_widgets = 1; + break; + } + + if (cad == -1) /* Not given on command line so find it. */ + for (cad = 0; cad < 16; cad++) + if (corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_VENDOR, &a, &b)) + break; + printf +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + + printf ("/* Codec index is %d */\n", cad); + printf ("/* Codec vendor %04x:%04x */\n", a >> 16, a & 0xffff); + + if (corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_REVISION, &a, &b)) + { + printf ("/* HD codec revision %d.%d (%d.%d) (0x%08x) */\n", + (a >> 20) & 0xf, (a >> 16) & 0xf, (a >> 8) & 0xff, a & 0xff, a); + } + else + printf ("hdaudio: Can't get codec revision\n"); + +/* + * Find out the primary group list + */ + + if (!corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_NODE_COUNT, &a, &b)) + exit(1); + + first_node = (a >> 16) & 0xff; + num_nodes = a & 0xff; + + for (i = first_node; i < first_node + num_nodes; i++) + dump_node (i); + +/* + * Next produce the output + */ + + if (*codec_name == 0) + sprintf (codec_name, "subdevice%08x", subdevice); + + printf ("#include \"oss_hdaudio_cfg.h\"\n"); + printf ("#include \"hdaudio.h\"\n"); + printf ("#include \"hdaudio_codec.h\"\n"); + printf ("#include \"hdaudio_dedicated.h\"\n"); + printf ("\n"); + + printf ("int\n"); + printf + ("hdaudio_%s_mixer_init (int dev, hdaudio_mixer_t * mixer, int cad, int top_group)\n", + codec_name); + printf ("{\n"); + //printf (" int wid;\n"); + printf (" int ctl=0;\n"); + //printf (" codec_t *codec = mixer->codecs[cad];\n"); + + printf ("\n"); + printf + (" DDB(cmn_err(CE_CONT, \"hdaudio_%s_mixer_init got called.\\n\"));\n", + codec_name); + printf ("\n"); + +/* + * Handle PIN widgets first + */ + printf (" /* Handle PIN widgets */\n"); + printf (" {\n"); + printf ("\tint n, group, pin_group;\n"); + printf ("\n\tn=0;\n"); + + printf ("\n\tHDA_GROUP(pin_group, top_group, \"jack\");\n"); + + for (i = 0; i < num_widgets; i++) + { + mixgen_widget_t *widget = &widgets[i]; + + if (!widget->valid) + continue; + + if (widget->type != NT_PIN) + continue; + + handle_pin_widget (i, widget); + } + printf (" }\n"); + +/* + * Handle ADC widgets + */ + printf (" /* Handle ADC widgets */\n"); + printf (" {\n"); + printf ("\tint n, group, rec_group;\n"); + printf ("\n\tn=0;\n"); + + printf ("\n\tHDA_GROUP(rec_group, top_group, \"record\");\n"); + + for (i = 0; i < num_widgets; i++) + { + mixgen_widget_t *widget = &widgets[i]; + + if (!widget->valid || widget->used) + continue; + + if (widget->type != NT_ADC) + continue; + + handle_adc_widget (i, widget); + } + printf (" }\n"); + +/* + * Handle the remaining widgets + */ + printf (" /* Handle misc widgets */\n"); + printf (" {\n"); + printf ("\tint n, group, misc_group;\n"); + printf ("\n\tn=0;\n"); + + printf ("\n\tHDA_GROUP(misc_group, top_group, \"misc\");\n"); + + for (i = 0; i < num_widgets; i++) + { + mixgen_widget_t *widget = &widgets[i]; + + if (!widget->valid || widget->used) + continue; + + handle_misc_widget (i, widget); + } + printf (" }\n"); + + printf (" return 0;\n"); + printf ("}\n"); + + if (print_widgets) + dump_widgets (); + exit (errors); +} diff --git a/utils/mixgen2.c b/utils/mixgen2.c new file mode 100644 index 0000000..41a55a9 --- /dev/null +++ b/utils/mixgen2.c @@ -0,0 +1,1233 @@ +/* + * Temporary utility used to develop the next hdaudio driver + * version. Not usable. + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <string.h> +#include <soundcard.h> +#include <stdarg.h> + +#define DRIVER_NICK "hdaudio" +#define CE_CONT 0 +#define CE_NOTE 1 +#define CE_WARN 2 + +#define DDB(x) + +#define PMALLOC(osdev, s) malloc(s) + +typedef int sound_os_info, mixer_create_controls_t; + +typedef struct +{ + char *hw_info; +} oss_device_t; + +#include <hdaudio.h> + +#define ioctl_arg int +#define mixer_ext_init_fn int +#include <hdaudio_codec.h> +//#include <hdaudio_codecids.h> + +int fd; + +#undef corb_read +#undef corb_write + +typedef struct +{ + int association, sequence; + int nwidgets; + int jack_count; + +#define PATH_MAXWID 8 + widget_t *widgets[PATH_MAXWID]; +} path_t; + +#define MAX_PATHS 32 +path_t *paths[MAX_PATHS]; +int npaths=0; + +int +corb_write (void *dc, unsigned int cad, unsigned int nid, unsigned int d, + unsigned int verb, unsigned int parm) +{ + unsigned int tmp; + + tmp = (cad << 28) | (d << 27) | (nid << 20) | (verb << 8) | parm; + + if (ioctl (fd, HDA_IOCTL_WRITE, &tmp) == -1) + { + perror ("HDA_IOCTL_WRITE"); + return 0; + } + + return 1; +} + +static int +corb_read (void *dc, unsigned int cad, unsigned int nid, unsigned int d, + unsigned int verb, unsigned int parm, unsigned int *upper, + unsigned int *lower) +{ + unsigned int tmp; + + tmp = (cad << 28) | (d << 27) | (nid << 20) | (verb << 8) | parm; + + if (ioctl (fd, HDA_IOCTL_READ, &tmp) == -1) + { + /* perror("HDA_IOCTL_READ"); */ + if (errno == EINVAL) + { + fprintf (stderr, "hdaudio_snoopy mode is not available\n"); + exit (-1); + } + return 0; + } + + *upper = tmp; + *lower = 0; + + return 1; +} + +void +cmn_err (int level, char *s, ...) +{ + char tmp[1024], *a[6]; + va_list ap; + int i, n = 0; + + va_start (ap, s); + + for (i = 0; i < strlen (s); i++) + if (s[i] == '%') + n++; + + for (i = 0; i < n && i < 6; i++) + { + a[i] = va_arg (ap, char *); + } + + for (i = n; i < 6; i++) + a[i] = NULL; + + if (level == CE_CONT) + { + sprintf (tmp, s, a[0], a[1], a[2], a[3], a[4], a[5], NULL, + NULL, NULL, NULL); + printf ("%s", tmp); + } + else + { + strcpy (tmp, DRIVER_NICK ": "); + + sprintf (tmp + strlen (tmp), s, a[0], a[1], a[2], a[3], a[4], a[5], + NULL, NULL, NULL, NULL); + printf ("%s", tmp); + } + + va_end (ap); +} + +/* + ******************************** + */ + +static const char *widget_id[16] = { + "pcm", + "rec", + "mix", + "select", + "jack", + "power", + "vol", + "beep", + "unkn", + "unkn", + "unkn", + "unkn", + "unkn", + "unkn", + "unkn", + "vendor" + }; + +static int +attach_pin_widget (hdaudio_mixer_t * mixer, codec_t * codec, + widget_t * widget, int cad, int wid, int group_type) +{ + unsigned int conf; + int num = codec->jack_number++; + unsigned int pincaps, b; + int association, sequence; + int default_device; + int default_loc; + int conn; + + int color; + int no_color = 0; + char *name = NULL, *loc = "", *color_name = NULL; + + if (!corb_read (mixer, cad, wid, 0, GET_CONFIG_DEFAULT, 0, &conf, &b)) + return 0; + + default_device = (conf >> 20) & 0x0f; + default_loc = (conf >> 24) & 0x3f; + conn = (conf >> 30) & 0x03; + + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_PIN_CAPS, &pincaps, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_PIN_CAPS failed\n"); + return 0; + } + + widget->pincaps = pincaps; + + if (conf == 0) + { + cmn_err (CE_WARN, + "CONFIG_DEFAULT information not provided by BIOS for cad=%d, wid=%02x\n", + cad, wid); + cmn_err (CE_CONT, "Cannot work in this system.\n"); + return 0; + } + + color = (conf >> 12) & 0x0f; + + association = (conf>>4) & 0xf; + sequence = conf & 0xf; + + if (pincaps & (1 << 6)) + cmn_err (CE_WARN, "Balanced I/O not supported\n"); + if (!(pincaps & (1 << 5))) /* No input */ + widget->pin_type = PIN_OUT; + if (!(pincaps & (1 << 4))) + widget->pin_type = PIN_IN; + + DDB (cmn_err (CE_CONT, "\tConfig default %08x\n", conf)); + + if ((default_loc & 0x0f) == 0x1) /* Rear panel - default */ + loc = ""; + if ((default_loc & 0x0f) == 0x2) /* Front panel */ + loc = "fp-"; + if ((default_loc & 0xf0) == 0x10) /* Internal func - eg cd/tad/spk */ + loc = "int-"; + + if (conn == 1) /* Pin not connected to anything */ + { + widget->skip = 1; + widget->skip_output = 1; + } + + widget->association = association; + widget->sequence = sequence; + + switch (default_device) + { + case 0x0: + name = "lineout"; + widget->pin_type = PIN_OUT; + break; + case 0x1: + name = "speaker"; + no_color = 1; + widget->pin_type = PIN_OUT; + break; + case 0x2: + name = "headphone"; + widget->pin_type = PIN_OUT; + break; + case 0x3: + name = "cd"; + no_color = 1; + widget->pin_type = PIN_IN; + break; + case 0x4: + name = "spdifout"; + no_color = 1; + widget->pin_type = PIN_OUT; + break; + case 0x5: + name = "digout"; + no_color = 1; + widget->pin_type = PIN_OUT; + break; + case 0x6: + name = "modem"; + no_color = 1; + break; + case 0x7: + name = "phone"; + no_color = 1; + break; + case 0x8: + name = "linein"; + widget->pin_type = PIN_IN; + break; + case 0x9: + name = "aux"; + break; + case 0xa: + name = "mic"; + widget->pin_type = PIN_MIC; + break; + case 0xb: + name = "telephony"; + no_color = 1; + break; + case 0xc: + name = "spdifin"; + no_color = 1; + break; + case 0xd: + name = "digin"; + no_color = 1; + break; + case 0xe: + name = "reserved"; + no_color = 1; + break; + case 0xf: /* Unused pin widget */ + widget->skip = 1; + widget->skip_output = 1; + break; + } + +/* process only colored jacks and skip fixed function jacks */ + switch (color) + { + case 0x1: + color_name = "black"; + widget->rgbcolor = OSS_RGB_BLACK; + break; + case 0x2: + color_name = "gray"; + widget->rgbcolor = OSS_RGB_GRAY; + break; + case 0x3: + color_name = "blue"; + widget->rgbcolor = OSS_RGB_BLUE; + break; + case 0x4: + color_name = "green"; + widget->rgbcolor = OSS_RGB_GREEN; + break; + case 0x5: + color_name = "red"; + widget->rgbcolor = OSS_RGB_RED; + break; + case 0x6: + color_name = "orange"; + widget->rgbcolor = OSS_RGB_ORANGE; + break; + case 0x7: + color_name = "yellow"; + widget->rgbcolor = OSS_RGB_YELLOW; + break; + case 0x8: + color_name = "purple"; + widget->rgbcolor = OSS_RGB_PURPLE; + break; + case 0x9: + color_name = "pink"; + widget->rgbcolor = OSS_RGB_PINK; + break; + case 0xe: + color_name = "white"; + widget->rgbcolor = OSS_RGB_WHITE; + break; + + default: + if (name != NULL) + color_name = name; + else + color_name = "internal"; + } + + if (no_color) + widget->rgbcolor = 0; + + if (default_device == 0xf) /* Not present */ + { + widget->rgbcolor = 0; + color_name = "internal"; + } + + sprintf (widget->color, "%s%s", loc, color_name); + + if (name == NULL || default_device == 0x00) + name = color_name; + sprintf (widget->name, "%s%s", loc, name); + + DDB(cmn_err(CE_CONT, "\tJack name %s, color %s (%06x)\n", + widget->name, widget->color, widget->rgbcolor)); + DDB(cmn_err(CE_CONT, "\tAssociation %x, sequence %x\n", association, sequence)); + +printf("Widget %02x: default_device=%d, name=%s, color=%s\n", wid, default_device, widget->name, widget->color); + return 1; +} + +static int +attach_widget (hdaudio_mixer_t * mixer, int cad, int wid, int group_type) +{ + static const char *widget_types[16] = { + "Audio output", + "Audio input", + "Audio mixer", + "Audio selector", + "Pin complex", + "Power widget", + "Volume knob", + "Beep generator", + "Reserved8", + "Reserved9", + "ReservedA", + "ReservedB", + "ReservedC", + "ReservedD", + "ReservedE", + "Vendor defined audio" + }; + + static const int bit_sizes[] = { + 8, + 16, + 20, + 24, + 32 + }; + + static const unsigned int bit_fmts[] = { + AFMT_U8, + AFMT_S16_LE, + AFMT_S32_LE, + AFMT_S32_LE, + AFMT_S32_LE + }; + + static const int srates[] = { + 8000, + 11025, + 16000, + 22050, + 32000, + 44100, + 48000, + 88200, + 96000, + 176400, + 192000, + 384000 + }; + + unsigned int widget_caps, b, pstate; + unsigned int inamp_caps, outamp_caps; + int wid_type; + int i; + + codec_t *codec = mixer->codecs[cad]; + widget_t *widget; + + if (codec == NULL) + return 0; + + if (wid >= MAX_WIDGETS) + { + cmn_err (CE_WARN, "Too many widgets for codec %d (%d/%d)\n", cad, wid, + MAX_WIDGETS); + return 0; + } + + mixer->ncontrols++; + + codec->nwidgets = wid + 1; + widget = &codec->widgets[wid]; + + widget->cad = cad; + widget->wid = wid; + + widget->rgbcolor = 0; + + widget->group_type = group_type; + + DDB (cmn_err (CE_CONT, " * Widget %02x, type %d\n", wid, group_type)); + + if (!corb_read + (mixer, cad, wid, 0, GET_PARAMETER, HDA_WIDGET_CAPS, &widget_caps, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_WIDGET_CAPS failed\n"); + return 0; + } + + if (widget_caps & WCAP_AMP_CAP_OVERRIDE) /* Amp param override? */ + { + if (!corb_read (mixer, widget->cad, widget->wid, 0, + GET_PARAMETER, HDA_OUTPUTAMP_CAPS, &outamp_caps, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_OUTPUTAMP_CAPS failed\n"); + return -EIO; + } + widget->outamp_caps = outamp_caps; + + if (!corb_read (mixer, widget->cad, widget->wid, 0, + GET_PARAMETER, HDA_INPUTAMP_CAPS, &inamp_caps, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_INPUTAMP_CAPS failed\n"); + return -EIO; + } + widget->inamp_caps = inamp_caps; + } + else + { + widget->outamp_caps = outamp_caps = codec->default_outamp_caps; + widget->inamp_caps = inamp_caps = codec->default_inamp_caps; + } + + if (!corb_read (mixer, cad, wid, 0, GET_POWER_STATE, 0, &pstate, &b)) + return 0; + + /* power up each of the widgets if there is a Power Capability (1<<10) */ + if (widget_caps & WCAP_POWER_CTL) + corb_write (mixer, cad, wid, 0, SET_POWER_STATE, 0); + + widget->widget_caps = widget_caps; + + wid_type = (widget_caps >> 20) & 0x0f; + DDB (cmn_err + (CE_CONT, "\tWidget type %d (%s)(%s)\n", wid_type, + widget_types[wid_type], widget_id[wid_type])); + DDB (cmn_err (CE_CONT, "\tPower State %d\n", pstate)); + + if (widget_caps & WCAP_CONN_LIST) + { + unsigned int clen; + /* Handle connection list */ + + if (!corb_read + (mixer, cad, wid, 0, GET_PARAMETER, HDA_CONNLIST_LEN, &clen, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_CONNLIST_LEN failed\n"); + return 0; + } + + if (clen & 0x80) + { + cmn_err (CE_WARN, "Long form connection list not supported\n"); + return 0; + } + + if (clen > 0) + { + if (clen > MAX_CONN) + { + cmn_err (CE_WARN, "Too many connections\n"); + return 0; + } + + DDB (cmn_err (CE_CONT, "\tConn list (%d): ", clen)); + + for (i = 0; i < clen; i += 4) + { + int j; + unsigned int a; + + if (!corb_read + (mixer, cad, wid, 0, GET_CONNECTION_LIST_ENTRY, i, &a, &b)) + { + cmn_err (CE_WARN, "GET_CONNECTION_LIST_ENTRY failed\n"); + return 0; + } + + for (j = 0; j < 4 && (i + j) < clen; j++) + { + int v, is_range = 0; + + if (widget->nconn >= MAX_CONN) + { + cmn_err (CE_WARN, + "Too many connections for widget %d (%d)\n", + widget->wid, widget->nconn); + break; + } + + v = (a >> (j * 8)) & 0xff; + DDB (cmn_err (CE_CONT, "%d ", v)); + + if (v & 0x80) + { + is_range = 1; + v &= ~0x80; + } + + if (v < 0 || v >= MAX_WIDGETS) + { + cmn_err (CE_NOTE, + "Connection %d for widget %d is out of range (%d) - Skipped\n", + j, widget->wid, v); + continue; + } + + if (is_range) /* Range: prev...v */ + { + int x; + codec->widgets[v].references[codec->widgets[v]. + refcount++] = wid; + + if (widget->nconn < 1) + { + cmn_err (CE_CONT, + "Bad range connection for widget %d\n", + widget->wid); + continue; + } + + for (x = widget->connections[widget->nconn - 1] + 1; + x <= v; x++) + { + if (widget->nconn >= MAX_CONN) + { + cmn_err (CE_WARN, + "Too many connectionsi(B) for widget %d (%d)\n", + widget->wid, widget->nconn); + break; + } + + widget->connections[widget->nconn++] = x; + codec->widgets[x].references[codec->widgets[x]. + refcount++] = wid; + } + } + else + { + widget->connections[widget->nconn++] = v; + codec->widgets[v].references[codec->widgets[v]. + refcount++] = wid; + } + } + } + + DDB (cmn_err (CE_CONT, "\n")); + } + } + + widget->wid_type = wid_type; + strcpy (widget->name, widget_id[wid_type]); + +/* + * Handle widget based on its type. + */ + + switch (wid_type) + { + case NT_PIN: + if (!attach_pin_widget (mixer, codec, widget, cad, wid, group_type)) + return 0; + break; + } + + return 1; +} + + /*ARGSUSED*/ static int +attach_function_group (hdaudio_mixer_t * mixer, int cad, int wid, + int group_type) +{ + unsigned int a, b, gt; + int i, first_node, num_nodes; + codec_t *codec = mixer->codecs[cad]; + + if (codec == NULL) + return 0; + cmn_err (CE_CONT, "Attach function group, cad=%02x, wid=%02x\n", cad, wid); + + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_OUTPUTAMP_CAPS, + &codec->default_outamp_caps, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_OUTPUTAMP_CAPS failed\n"); + return 0; + } + + if (!corb_read (mixer, cad, wid, 0, + GET_PARAMETER, HDA_INPUTAMP_CAPS, + &codec->default_inamp_caps, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_INPUTTAMP_CAPS failed\n"); + return 0; + } + + if (!corb_read (mixer, cad, wid, 0, GET_PARAMETER, HDA_NODE_COUNT, &a, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_NODE_COUNT2 failed\n"); + return 0; + } + + first_node = (a >> 16) & 0xff; + num_nodes = a & 0xff; + + corb_read (mixer, cad, wid, 0, GET_PARAMETER, HDA_GROUP_TYPE, >, &b); + gt &= 0xff; + + DDB (cmn_err + (CE_CONT, + " * Function group %d First node %d, num nodes %d, group type %x\n", + wid, first_node, num_nodes, gt)); +/* + * Ignore other than audio function groups. Codecs probably allocate + * higher widget number for the modem group than the audio group. So in this + * way we can have smaller MAX_WIDGETS which in turn conserves memory. + */ + if (gt != group_type) + return 0; + + if (corb_read (mixer, cad, wid, 0, GET_PARAMETER, HDA_PCM_SIZES, &a, &b)) + { + codec->sizes = a; + } + + if (first_node > 0) + for (i = first_node; i < first_node + num_nodes; i++) + if (!attach_widget (mixer, cad, i, gt)) + return 0; + + if (num_nodes >= 1) + codec->active = 1; + return 1; +} +static int +attach_codec (hdaudio_mixer_t * mixer, int cad, char *hw_info, + unsigned int pci_subdevice, int group_type) +{ + unsigned int a, b, x; + int i; + int first_node, num_nodes; + int has_audio_group = 0; + codec_t *codec; + + if (cad >= MAX_CODECS) + { + cmn_err (CE_WARN, "attach_codec: Too many codecs %d\n", cad); + return -EIO; + } + + mixer->ncodecs = cad + 1; + + if (mixer->codecs[cad] == NULL) + { + if ((codec = PMALLOC (mixer->osdev, sizeof (*codec))) == NULL) + { + cmn_err (CE_CONT, "Cannot allocate codec descriptor\n"); + return -ENOMEM; + } + + memset (codec, 0, sizeof (*codec)); + + mixer->codecs[cad] = codec; + } + else + { + codec = mixer->codecs[cad]; + } + + corb_write (mixer, cad, 0, 0, SET_POWER_STATE, 0); /* Power up everything */ + + if (!corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_VENDOR, &a, &b)) + { + if (group_type == 1) + { + sprintf (hw_info, " Codec %2d: Not present\n", cad); + cmn_err (CE_NOTE, + "attach_codec: Codec #%d is not physically present\n", + cad); + } + return -EIO; + } + + codec->vendor_id = a; + +/* + * Find out the primary group list + */ + + if (!corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_NODE_COUNT, &x, &b)) + { + cmn_err (CE_WARN, "GET_PARAMETER HDA_NODE_COUNT3 failed\n"); + return -EIO; + } + + codec->first_node = first_node = (x >> 16) & 0xff; + num_nodes = x & 0xff; + +/* + * Check if this one is an audio codec (has an audio function group) + */ + for (i = first_node; i < first_node + num_nodes; i++) + { + unsigned int gt; + + if (corb_read + (mixer, cad, i, 0, GET_PARAMETER, HDA_GROUP_TYPE, >, &b)); + if ((gt & 0xff) != 1) /* Audio function group */ + continue; + + has_audio_group = 1; + } + +#if 0 +/* + * Find codec specific settings + */ + for (ix = 0; codecs[ix].id != 0; ix++) + if (codecs[ix].id == a) + break; + + DDB (cmn_err + (CE_CONT, "HD audio Codec ID: %08x (%s)\n", a, codecs[ix].name)); + + if (codecs[ix].id == 0) /* Unknown codec */ + { + if (group_type == 1) + sprintf (hw_info, " Codec %2d: Unknown (0x%08x", cad, a); + cmn_err (CE_NOTE, "Unknown HDA codec 0x%08x\n", a); + /* + * Create hexadecimal codec ID + */ + if (has_audio_group && mixer->chip_name == NULL) + if ((mixer->chip_name = PMALLOC (mixer->osdev, 32)) != NULL) + { + sprintf (mixer->chip_name, "0x%08x", a); + } + } + else + { + if (group_type == 1) + sprintf (hw_info, " Codec %2d: %s (0x%08x", cad, codecs[ix].name, a); + } + + if (has_audio_group && mixer->chip_name == NULL) + { + mixer->chip_name = codecs[ix].name; + + } + + if (codecs[ix].remap != NULL) + codec->remap = codecs[ix].remap; + + if (codecs[ix].flags != 0) + codec->vendor_flags = codecs[ix].flags; + + if (codecs[ix].mixer_init != NULL) + codec->mixer_init = codecs[ix].mixer_init; + + codec->multich_map = codecs[ix].multich_map; + codec->codec_desc = &codecs[ix]; +#endif + + if (corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_REVISION, &a, &b)) + { + DDB (cmn_err (CE_CONT, "HDA codec revision %d.%d (%d.%d) (0x%08x)\n", + (a >> 20) & 0xf, + (a >> 16) & 0xf, (a >> 8) & 0xff, a & 0xff, a)); + } + else + DDB (cmn_err (CE_CONT, "Can't get codec revision\n")); + + DDB (cmn_err (CE_CONT, "**** Codec %d ****\n", cad)); + DDB (cmn_err + (CE_CONT, "First group node %d, num nodes %d\n", first_node, + num_nodes)); + + for (i = first_node; i < first_node + num_nodes; i++) + { + corb_read (mixer, cad, i, 0, GET_PARAMETER, HDA_GROUP_TYPE, &a, &b); + if ((a & 0xff) == group_type) /* Proper function group type */ + { + codec->afg = i; + + if (corb_read (mixer, cad, i, 0, GET_SUBSYSTEM_ID, 0, &a, &b)) + { + DDB (cmn_err (CE_CONT, "Subsystem ID = 0x%08x\n", a)); + + if (group_type == 1) + { + /* Append subvendor ID to hw_info */ + hw_info += strlen (hw_info); + sprintf (hw_info, "/0x%08x", a); + } + + codec->subvendor_id = a; + +#if 0 + for (subix = 0; subdevices[subix].id != 0; subix++) + if (subdevices[subix].id == a) + { + if (subdevices[subix].main_id != 0) + if (subdevices[subix].main_id != codec->vendor_id) + continue; + + if (subdevices[subix].pci_subdevice != 0) + if (subdevices[subix].pci_subdevice != pci_subdevice) + continue; + + + DDB (cmn_err + (CE_CONT, "Subdevice known as %s\n", + subdevices[subix].name)); + if (group_type == 1) + { + hw_info += strlen (hw_info); + sprintf (hw_info, " %s", subdevices[subix].name); + } + if (subdevices[subix].remap != NULL) + { + codec->remap = subdevices[subix].remap; + } + + if (subdevices[subix].multich_map != 0) + codec->multich_map = subdevices[subix].multich_map; + if (subdevices[subix].flags != 0) + codec->vendor_flags = subdevices[subix].flags; + if (subdevices[subix].mixer_init != NULL) + { + codec->mixer_init = subdevices[subix].mixer_init; + } + } +#endif + } + break; + } + } + + hw_info += strlen (hw_info); + if (group_type == 1) + strcpy (hw_info, ")\n"); + + for (i = first_node; i < first_node + num_nodes; i++) + { + if (!attach_function_group (mixer, cad, i, group_type)) + continue; + + /* power up the AFG! */ + corb_write (mixer, cad, i, 0, SET_POWER_STATE, 0); + } + +#if 0 + if (has_audio_group) + { + polish_widget_list (mixer, cad); + } + + copy_endpoints (mixer, codec, 0); /* Copy analog endpoints from codec to mixer */ +#endif + + return (has_audio_group) ? 0 : -EIO; +} + +static void +follow_path(hdaudio_mixer_t *mixer, codec_t *codec, widget_t *widget, path_t *path, int use_force) +{ + int i; + + if (widget->used) + return; + + widget->used = 1; + path->widgets[path->nwidgets++] = widget; + if (widget->wid_type == NT_PIN) + { + path->jack_count++; + path->association=widget->association; + path->sequence=widget->sequence; + + /* + * Stop at a pin widget that is not the first widget of the path. + * In this way we don't walk back the input chain from the pin. + */ + + if (path->nwidgets > 1) + return; + } + + if (use_force || path->nwidgets == 1 || widget->nconn == 1 || (widget->nconn>0 && widget->wid_type == NT_SELECT)) + { + for (i=0;i<widget->nconn;i++) + if (!codec->widgets[widget->connections[i]].used) + //if (codec->widgets[widget->connections[i]].refcount < 2) + { + follow_path(mixer, codec, &codec->widgets[widget->connections[i]], path, use_force); + return; + } + } +} + +static void +dump_path(hdaudio_mixer_t *mixer, path_t *path) +{ + int i, j; + + if (path->nwidgets == 0) + return; + + printf("Path (a=%x, s=%x, jc=%d):\n ", path->association, path->sequence, path->jack_count); + + for (i=0;i<path->nwidgets;i++) + { + widget_t *widget = path->widgets[i]; + + printf("\t%02x(%s/%s/nc=%d/rc=%d", widget->wid, widget_id[widget->wid_type], widget->name, widget->nconn, widget->refcount); + printf(")\n"); + + if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT) + { + printf("\t\tOutput amp\n"); + } + + if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT) + { + printf("\t\t%d input amp(s)\n", widget->nconn); + + for (j=0;j<widget->nconn;j++) + { + widget_t *in_widget; + + in_widget = &mixer->codecs[widget->cad]-> + widgets[widget->connections[j]]; + printf("\t\t\t%02x(%s/%s/nc=%d/rc=%d)\n", in_widget->wid, widget_id[in_widget->wid_type], in_widget->name, in_widget->nconn, in_widget->refcount); + + in_widget->used=1; + } + } + } + printf("\n"); +} + +static void +store_path(hdaudio_mixer_t *mixer, path_t *path) +{ + if (npaths>=MAX_PATHS) + { + cmn_err(CE_WARN, "Too many paths\n"); + return; + } + + paths[npaths++]=path; +} + +static void +create_path_list(hdaudio_mixer_t *mixer, int cad, int node_type, int use_force) +{ + codec_t *codec; + int wid; + + path_t *path; + +cmn_err(CE_CONT, "Create path list %d (%s)\n", node_type, widget_id[node_type]); + codec=mixer->codecs[cad]; + + for (wid=0;wid<codec->nwidgets;wid++) + if (codec->widgets[wid].wid_type == node_type) + if (!codec->widgets[wid].skip) + if (codec->widgets[wid].wid == wid) + { + path=malloc(sizeof(*path)); + + follow_path(mixer, codec, &codec->widgets[wid], path, use_force); + + if (path->nwidgets>1) + store_path(mixer, path); + else + if (path->nwidgets>0) + path->widgets[0]->used=0; + } + +} + +static void +create_path_list_for_pin(hdaudio_mixer_t *mixer, int cad, int association, int sequence) +{ + codec_t *codec; + int wid; + + path_t *path; + + codec=mixer->codecs[cad]; + + for (wid=0;wid<codec->nwidgets;wid++) + if (codec->widgets[wid].wid_type == NT_PIN && !codec->widgets[wid].skip) + if (codec->widgets[wid].pin_type == PIN_HEADPHONE || codec->widgets[wid].pin_type == PIN_OUT) + if (codec->widgets[wid].wid == wid) + if (codec->widgets[wid].nconn > 0) + if (!codec->widgets[wid].skip) + if (codec->widgets[wid].sequence == sequence) + if (codec->widgets[wid].association == association) + { + path=malloc(sizeof(*path)); + + follow_path(mixer, codec, &codec->widgets[wid], path, 0); + + if (path->nwidgets>1) + store_path(mixer, path); + else + if (path->nwidgets>0) + path->widgets[0]->used=0; + } + +} + +hdaudio_mixer_t * +hdaudio_mixer_create (char *name, void *devc, + oss_device_t * osdev, + hdmixer_write_t writefunc, + hdmixer_read_t readfunc, unsigned int codecmask, + unsigned int vendor_id, unsigned int subvendor_id) +{ + hdaudio_mixer_t *mixer; + int i, func; + int ncodecs = 0; + char tmp[128]; + int mixer_dev; + + char *hw_info = osdev->hw_info; /* For printing hardware information */ + + if ((mixer = PMALLOC (osdev, sizeof (*mixer))) == NULL) + { + cmn_err (CE_WARN, "hdaudio_mixer_create: Out of memory\n"); + return NULL; + } + + memset (mixer, 0, sizeof (*mixer)); + + mixer->devc = devc; + mixer->osdev = osdev; + mixer->mixer_dev = 0; + strncpy (mixer->name, name, sizeof (mixer->name) - 1); + mixer->name[sizeof (mixer->name) - 1] = 0; + + for (i = 0; i < MAX_CODECS; i++) + mixer->codecs[i] = NULL; + +#ifdef _KERNEL + mixer->read = readfunc; + mixer->write = writefunc; +#endif + + mixer->codecmask = codecmask; + + sprintf (hw_info, "HD Audio controller %s\n" + "Vendor ID 0x%08x\n" + "Subvendor ID 0x%08x\n", name, vendor_id, subvendor_id); + hw_info += strlen (hw_info); + +/* + * Search first all audio function groups for all codecs and then + * handle modem function groups. + */ + for (func = 1; func <= 2; func++) + for (i = 0; i < 16; i++) + if (mixer->codecmask & (1 << i)) + { + if (attach_codec (mixer, i, hw_info, subvendor_id, func) >= 0) + ncodecs++; + hw_info += strlen (hw_info); + } + + for (i = 0; i < 16; i++) + if (mixer->codecmask & (1 << i)) + { + int association, sequence; + +printf("*** Codec %d\n", i); + for (association=1;association<16;association++) + for (sequence=0;sequence<16;sequence++) + create_path_list_for_pin(mixer, i, association, sequence); + + create_path_list(mixer, i, NT_ADC, 0); + create_path_list(mixer, i, NT_MIXER, 1); + create_path_list(mixer, i, NT_SELECT, 1); + } + + for (i=0;i<npaths;i++) + dump_path(mixer, paths[i]); + +#if 1 + printf("\n\nOther widgets:\n"); + + for (i = 0; i < 16; i++) + if (mixer->codecmask & (1 << i)) + { + int wid; + + for (wid=0;wid<mixer->codecs[i]->nwidgets;wid++) + { + widget_t *widget = &mixer->codecs[i]->widgets[wid]; + + if (widget->wid != wid) + continue; + + if (widget->used || widget->skip) + continue; + printf("Codec %d, Widget %02x %s/%s/%d\n", widget->cad, widget->wid, widget_id[widget->wid_type], widget->name, widget->nconn); + } + } +#endif + + return mixer; +} + +int +main (int argc, char *argv[]) +{ + unsigned int rev, b; + int first_node, num_nodes; + int i; + int cad = 0; + + int codecmask = 0; + + oss_device_t osdev = { 0 }; + + osdev.hw_info = malloc (256); + + if ((fd = open ("/dev/oss/oss_hdaudio0/pcm0", O_RDWR | O_EXCL, 0)) == -1) + { + perror ("/dev/oss/oss_hdaudio0/pcm0"); + exit (-1); + } + + for (cad = 0; cad < 15; cad++) + if (corb_read (NULL, cad, 0, 0, GET_PARAMETER, HDA_REVISION, &rev, &b)) + { +#if 1 + printf ("Codec %2d: HD codec revision %d.%d (%d.%d) (0x%08x)\n", cad, + (rev >> 20) & 0xf, (rev >> 16) & 0xf, (rev >> 8) & 0xff, + rev & 0xff, rev); +#endif + codecmask |= (1 << cad); + } + + hdaudio_mixer_create ("ACME hdaudio", NULL, + &osdev, NULL, NULL, codecmask, 0x12345678, 0x8754321); + + //printf("HW Info: %s\n", osdev.hw_info); + exit (0); +} diff --git a/utils/ossmkdep.c b/utils/ossmkdep.c new file mode 100644 index 0000000..9d33da9 --- /dev/null +++ b/utils/ossmkdep.c @@ -0,0 +1,234 @@ +/* + * Purpose: Simple replacement for cpp -M (gcc) + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +int ndirs = 0; +char *dirs[1024]; + +int ndupes = 0; +char *dupes[4096]; + +static void +add_includedir (char *d) +{ + dirs[ndirs++] = d; +} + +static int +dupe_file (char *name) +{ + int i; + + for (i = 0; i < ndupes; i++) + if (strcmp (dupes[i], name) == 0) + return 1; + + dupes[ndupes++] = strdup (name); + return 0; +} + +static void parse_f (FILE * f, char *pathname); + +static void +do_global_include (char *hdrname, char *pathname) +{ + FILE *f; + int i; + + char tmp[512]; + sprintf (tmp, "%s/%s", pathname, hdrname); + + if (dupe_file (tmp)) + return; + if ((f = fopen (tmp, "r")) != NULL) + { + printf ("%s ", tmp); + parse_f (f, pathname); + fclose (f); + return; + } + + for (i = 0; i < ndirs; i++) + { + sprintf (tmp, "%s/%s", dirs[i], hdrname); + if (dupe_file (tmp)) + return; + + if ((f = fopen (tmp, "r")) == NULL) + continue; + printf ("\\\n %s ", tmp); + + parse_f (f, dirs[i]); + fclose (f); + return; + } + + fprintf (stderr, "Cannot locate <%s>\n", hdrname); + printf ("\n"); + exit (-1); +} + +static void +do_local_include (char *hdrname, char *pathname) +{ + FILE *f; + char tmp[512]; + + sprintf (tmp, "%s/%s", pathname, hdrname); + + if (dupe_file (tmp)) + { + return; + } + + if ((f = fopen (tmp, "r")) == NULL) + { +#if 1 + do_global_include (hdrname, pathname); + return; +#else + perror (tmp); + printf ("\n"); + exit (-1); +#endif + } + + sprintf (tmp, "%s ", tmp); + parse_f (f, pathname); + printf ("\\\n %s ", tmp); + + fclose (f); +} + +static void +parse_f (FILE * f, char *pathname) +{ + char line[1024], *p, *s; + + while (fgets (line, sizeof (line), f) != NULL) + { + if (*line != '#') + continue; + + s = line + 1; + + /* Skip space */ + while (*s && (*s == ' ' || *s == '\t')) + s++; + + /* Extract the preprocessor directive name (p) */ + p = s; + while (*s && (*s != ' ' && *s != '\t')) + s++; + *s++ = 0; + + if (strcmp (p, "include") != 0) + continue; + + /* Skip space */ + while (*s && (*s == ' ' || *s == '\t')) + s++; + + if (*s == '"') + { + s++; + + p = s; + while (*s && *s != '"') + s++; + *s = 0; + do_local_include (p, pathname); + continue; + } + + if (*s == '<') + { + s++; + + p = s; + while (*s && *s != '>') + s++; + *s = 0; + do_global_include (p, pathname); + continue; + } + } +} + +static void +parse_sourcefile (char *srcname) +{ + FILE *f; + char *s, *p; + char origname[64]; + + strcpy (origname, srcname); + + s = NULL; + + p = srcname; + while (*p) + { + if (*p == '.') + s = p; + p++; + } + + if (*s != '.') + { + fprintf (stderr, "Bad file name %s\n", srcname); + printf ("\n"); + exit (-1); + } + + if ((f = fopen (srcname, "r")) == NULL) + { + perror (srcname); + printf ("\n"); + exit (-1); + } + + *s++ = 0; + printf ("%s.o: %s ", srcname, origname); + + parse_f (f, "."); + printf ("\n"); + fclose (f); +} + +int +main (int argc, char *argv[]) +{ + int i; + + add_includedir ("/usr/include"); + add_includedir ("/usr/local/include"); + + for (i = 1; i < argc; i++) + if (argv[i][0] == '-') + switch (argv[i][1]) + { + case 'I': + add_includedir (argv[i] + 2); + break; + } + else + parse_sourcefile (argv[i]); + + exit (0); +} diff --git a/utils/phpmake b/utils/phpmake new file mode 100755 index 0000000..4000c25 --- /dev/null +++ b/utils/phpmake @@ -0,0 +1,27 @@ +#!/bin/bash + +if test ! -f Makefile.php +then + echo No Makefile.php in this directory + exit 0 +fi + +if ! php Makefile.php > Makefile +then + exit 1 +fi + +for n in */Makefile.php +do + N=`dirname $n` + + if test "$N " != '* ' + then + if ! (cd $N && phpmake $*) + then + exit 1 + fi + fi +done + +exit 0 diff --git a/utils/readtimings.c b/utils/readtimings.c new file mode 100644 index 0000000..99a385e --- /dev/null +++ b/utils/readtimings.c @@ -0,0 +1,61 @@ +/* + * Purpose: OSS built in tracing reader + * + * Description: + * This program is used to read timing/tracing information produced by the + * built in tracing facility of OSS. + * + * To use this program you need to rebuild OSS with the DO_TIMINGS macro + * defined. This macro is located in the os.h file for the target operating + * system. Output is written to stdout. Tracing information is currently + * produced only for the audio devices. + * + * To understand the output you need to be familiar with the internals of OSS. + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> + +int +main (void) +{ + int fd; + char buf[257 * 1024]; + int l; + + if ((fd = open ("/dev/mixer0", O_RDONLY, 0)) == -1) + { + perror ("/dev/mixer0"); + exit (-1); + } + + while (1) + { + if ((l = read (fd, buf, sizeof (buf))) < 0) + { + perror ("read"); + exit (-1); + } + + if (l) + write (1, buf, l); + + usleep (100000); + } + + close (fd); + exit (0); +} diff --git a/utils/snoopy.c b/utils/snoopy.c new file mode 100644 index 0000000..fede0e4 --- /dev/null +++ b/utils/snoopy.c @@ -0,0 +1,901 @@ +/* + * snoopy.c + * + * Purpose: Unsupported and undocumented diagnostic tool for hdaudio devices. + * + * This utility is an in-house tool used for examining capabilities and + * implementation details of HD audio codec chips. Only the first codec + * attached to the HD audio controller will be shown. + * + * You need to set the hdaudio_snoopy config option to 1 in hdaudio.conf. + * + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <string.h> +#include <soundcard.h> + +typedef int sound_os_info, mixer_create_controls_t, oss_device_t; + +#include <hdaudio.h> + +#define ioctl_arg int +#define mixer_ext_init_fn int +#include <hdaudio_codec.h> + +#undef corb_read +#undef corb_write + +int fd; +void *mixer = NULL; +int trace = 0; + +int cad = -1; + +int +corb_write (void *dc, unsigned int cad, unsigned int nid, unsigned int d, + unsigned int verb, unsigned int parm) +{ + unsigned int tmp; + + tmp = (cad << 28) | (d << 27) | (nid << 20) | (verb << 8) | parm; + if (trace) + printf ("WRITE %08x\n", tmp); + + if (ioctl (fd, HDA_IOCTL_WRITE, &tmp) == -1) + { + /* perror("HDA_IOCTL_WRITE"); */ + return 0; + } + + return 1; +} + +static int +corb_read (void *dc, unsigned int cad, unsigned int nid, unsigned int d, + unsigned int verb, unsigned int parm, unsigned int *upper, + unsigned int *lower) +{ + unsigned int tmp; + + tmp = (cad << 28) | (d << 27) | (nid << 20) | (verb << 8) | parm; + + if (ioctl (fd, HDA_IOCTL_READ, &tmp) == -1) + { + /* perror("HDA_IOCTL_READ"); */ + if (errno == EINVAL) + { + fprintf (stderr, "hdaudio_snoopy mode is not available\n"); + exit (-1); + } + return 0; + } + + *upper = tmp; + *lower = 0; + if (trace) + printf ("READ %08x\n", tmp); + + return 1; +} + +static void +dump_verbs (int ix, int ntype, int clen, unsigned int wcaps) +{ + int i; + unsigned int a, b, sel, state, fmt, spd, pstate, conv, sdi; + unsigned int unsol, pin, sense, eapd, beep, def, stripe; + + static const int bits[8] = { 8, 16, 20, 24, 32 }; + static const char *vrefs[8] = + { "Hi-Z", "50%", "Ground (0V)", "Reserved", "80%", "100%", "Reserved", + "Reserved" + }; + + if (ntype == NT_ADC || ntype == NT_SELECT || ntype == NT_PIN) + if (corb_read (mixer, cad, ix, 0, GET_SELECTOR, 0, &sel, &b)) + printf ("\tConnection select (701) = %08x\n", sel); + + if (ntype == NT_ADC || ntype == NT_DAC || ntype == NT_SELECT + || ntype == NT_PIN) + if (corb_read (mixer, cad, ix, 0, GET_PROCESSING_STATE, 0, &state, &b)) + printf ("\tProcessing state (703) = %08x\n", state); + + if (ntype == NT_ADC || ntype == NT_DAC) + if (corb_read (mixer, cad, ix, 0, GET_CONVERTER_FORMAT, 0, &fmt, &b)) + { + printf ("\tConverter format (00A) = %04x\n", fmt); + printf ("\t\tNon-PCM %d\n", (fmt >> 15) & 0x01); + printf ("\t\tSR base 44.1 kHz %d\n", (fmt >> 14) & 0x01); + printf ("\t\tSR multiplier %d\n", ((fmt >> 11) & 0x07) + 1); + printf ("\t\tSR divider %d\n", ((fmt >> 8) & 0x07) + 1); + printf ("\t\tBits %d\n", bits[(fmt >> 4) & 0x07]); + printf ("\t\tChannels %d\n", (fmt & 0x0f) + 1); + } + + if (ntype == NT_ADC || ntype == NT_DAC) + if (corb_read (mixer, cad, ix, 0, GET_CONVERTER, 0, &conv, &b)) + { + printf ("\tConverter control (F06) %02x\n", conv); + printf ("\t\tStream %d\n", (conv >> 4) & 0xf); + printf ("\t\tChannel %d\n", (conv >> 0) & 0xf); + } + + if (ntype == NT_PIN) + { + if (corb_read (mixer, cad, ix, 0, GET_PINCTL, 0, &pin, &b)) + { + printf ("\tPin widget control (F07) %02x\n", pin); + printf ("\t\tOutput amp enable %d\n", (pin >> 7) & 1); + printf ("\t\tOutput enable %d\n", (pin >> 6) & 1); + printf ("\t\tInput enable %d\n", (pin >> 5) & 1); + printf ("\t\tVRef enable %d %s\n", pin & 7, vrefs[pin & 7]); + } + + corb_write (mixer, cad, ix, 0, TRIGGER_PIN_SENSE, 0); + usleep (100 * 1000); + + if (corb_read (mixer, cad, ix, 0, GET_PIN_SENSE, 0, &sense, &b)) + { + printf ("\tPin sense (F09) %08x\n", sense); + printf ("\t\tPresence detect %d\n", (sense >> 31) & 1); + printf ("\t\tImpedance sense bits %08x\n", sense & ~0x80000000); + } + + if (corb_read (mixer, cad, ix, 0, GET_CONFIG_DEFAULT, 0, &def, &b)) + { + int v; + + printf ("\tConfiguration default (F1C) %08x\n", def); + + /* Port connectivity */ + v = (def >> 30) & 3; + printf ("\t\tPort connectivity %d ", v); + switch (v) + { + case 0: + printf ("Jack (1/8\", ATAPI, etc)"); + break; + case 1: + printf ("No physical connection for port"); + break; + case 2: + printf + ("A fixed function device (integrated speaker, mic, etc)"); + break; + case 3: + printf ("Both integrated device and a jack is connected"); + break; + } + printf ("\n"); + + /* Location */ + v = (def >> 24) & 0x3f; + printf ("\t\tLocation %02x ", v); + switch (v >> 4) + { + case 0: + printf ("External or primary chassis "); + break; + case 1: + printf ("Internal "); + break; + case 2: + printf ("Separate chassis "); + break; + case 3: + printf ("Other "); + break; + } + switch (v & 0xf) + { + case 0: + printf ("N/A"); + break; + case 1: + printf ("rear"); + break; + case 2: + printf ("front"); + break; + case 3: + printf ("left"); + break; + case 4: + printf ("right"); + break; + case 5: + printf ("top"); + break; + case 6: + printf ("bottom"); + break; + case 7: + printf ("special"); + break; + case 8: + printf ("special"); + break; + case 9: + printf ("special"); + break; + default: + printf ("reserved"); + break; + } + printf ("\n"); + + /* Default device */ + v = (def >> 20) & 0xf; + printf ("\t\tDefault device %d ", v); + switch (v) + { + case 0x0: + printf ("Line out"); + break; + case 0x1: + printf ("Speaker"); + break; + case 0x2: + printf ("Headphone out"); + break; + case 0x3: + printf ("CD"); + break; + case 0x4: + printf ("SPDIF out"); + break; + case 0x5: + printf ("Digital other out"); + break; + case 0x6: + printf ("Modem line side"); + break; + case 0x7: + printf ("Modem handset side"); + break; + case 0x8: + printf ("Line in"); + break; + case 0x9: + printf ("AUX"); + break; + case 0xa: + printf ("Mic in"); + break; + case 0xb: + printf ("Telephony"); + break; + case 0xc: + printf ("SPDIF in"); + break; + case 0xd: + printf ("Digital other in"); + break; + case 0xe: + printf ("Reserved"); + break; + case 0xf: + printf ("Other"); + break; + } + printf ("\n"); + + /* Cpnnection type */ + v = (def >> 16) & 0x0f; + printf ("\t\tConnection type %x ", v); + switch (v) + { + case 0x0: + printf ("Unknown"); + break; + case 0x1: + printf ("1/8\" stereo/mono"); + break; + case 0x2: + printf ("1/4\" stereo/mono"); + break; + case 0x3: + printf ("ATAPI internal"); + break; + case 0x4: + printf ("RCA"); + break; + case 0x5: + printf ("Optical"); + break; + case 0x6: + printf ("Other digital"); + break; + case 0x7: + printf ("Other analog"); + break; + case 0x8: + printf ("Multichannel analog (DIN)"); + break; + case 0x9: + printf ("XLR/professional"); + break; + case 0xa: + printf ("RJ-11 (modem)"); + break; + case 0xb: + printf ("Combination"); + break; + case 0xc: + printf ("Reserved"); + break; + case 0xd: + printf ("Reserved"); + break; + case 0xe: + printf ("Reserved"); + break; + case 0xf: + printf ("Other"); + break; + } + printf ("\n"); + + /* Color */ + v = (def >> 12) & 0xf; + printf ("\t\tColor %d ", v); + switch (v) + { + case 0x0: + printf ("Unknown"); + break; + case 0x1: + printf ("Black"); + break; + case 0x2: + printf ("Grey"); + break; + case 0x3: + printf ("Blue"); + break; + case 0x4: + printf ("Green"); + break; + case 0x5: + printf ("Red"); + break; + case 0x6: + printf ("Orange"); + break; + case 0x7: + printf ("Yellow"); + break; + case 0x8: + printf ("Purple"); + break; + case 0x9: + printf ("Pink"); + break; + case 0xa: + printf ("Reserved"); + break; + case 0xb: + printf ("Reserved"); + break; + case 0xc: + printf ("Reserved"); + break; + case 0xd: + printf ("Reserved"); + break; + case 0xe: + printf ("White"); + break; + case 0xf: + printf ("Other"); + break; + } + printf ("\n"); + + /* Mixc */ + v = (def >> 8) & 0xf; + printf ("\t\tMisc 0x%x ", v); + if (v & 0x1) + printf ("JackDetectOverride "); + if (v & 0x2) + printf ("reserved1 "); + if (v & 0x4) + printf ("reserved2 "); + if (v & 0x8) + printf ("reserved3 "); + printf ("\n"); + + /* Default association */ + v = (def >> 4) & 0xf; + printf ("\t\tDefault association %d ", v); + printf ("\n"); + + /* Sequence */ + v = (def >> 0) & 0xf; + printf ("\t\tSequence %d ", v); + printf ("\n"); + } + } + + if (corb_read (mixer, cad, ix, 0, GET_EAPD, 0, &eapd, &b)) + { + printf ("\tEAPD/BTL enable (F0C) %08x\n", eapd); + printf ("\t\tBTL %d\n", (eapd >> 0) & 1); + printf ("\t\tEAPD %d\n", (eapd >> 1) & 1); + printf ("\t\tL/R swap %d\n", (eapd >> 2) & 1); + } + + if (ntype == NT_ADC) + if (corb_read (mixer, cad, ix, 0, GET_SDI_SELECT, 0, &sdi, &b)) + { + printf ("\tSDI Select (F04) %d\n", sdi & 0x0f); + } + + if (ntype == NT_DAC) + if (corb_read (mixer, cad, ix, 0, GET_STRIPE_CONTROL, 0, &stripe, &b)) + { + printf ("\tStripe control (F24) %d\n", stripe); + } + + + if (ntype == NT_BEEP) + if (corb_read (mixer, cad, ix, 0, GET_BEEP, 0, &beep, &b)) + { + beep &= 0xff; + + if (beep == 0) + printf ("\tBeep OFF\n"); + else + printf ("Beep %d Hz\n", 48000 / beep); + } + + if (wcaps & (1 << 7)) + if (corb_read (mixer, cad, ix, 0, GET_UNSOLICITED, 0, &unsol, &b)) + { + printf ("\tUnsolicited response (F08) %02x\n", unsol); + printf ("\t\tEnabled %d\n", (unsol >> 7) & 1); + printf ("\t\tTag %d\n", unsol & 0x7f); + } + + if (ntype == NT_ADC || ntype == NT_DAC) + if (wcaps & (1 << 9)) /* Digital capable */ + if (corb_read (mixer, cad, ix, 0, GET_SPDIF_CONTROL, 0, &spd, &b)) + { + printf ("\tS/PDIF converter control (F0D) %08x\n", spd); + printf ("\t\tCategory code (CC) %02x\n", (spd >> 8) & 0x3f); + printf ("\t\tGeneration level (L) %d\n", (spd >> 7) & 1); + printf ("\t\tPRO %d\n", (spd >> 6) & 1); + printf ("\t\t/AUDIO %d\n", (spd >> 5) & 1); + printf ("\t\tCOPY %d\n", (spd >> 4) & 1); + printf ("\t\tPreemphasis (PRE) %d\n", (spd >> 3) & 1); + printf ("\t\tValidity config (VCFG) %d\n", (spd >> 2) & 1); + printf ("\t\tValidity FLAG (V) %d\n", (spd >> 1) & 1); + printf ("\t\tDigital Enable (DigEn) %d\n", (spd >> 0) & 1); + } + + if (corb_read (mixer, cad, ix, 0, GET_POWER_STATE, 0, &pstate, &b)) + printf ("\tPower state (F05) D%d\n", pstate & 3); + + + if (wcaps & (1 << 2)) /* Output amp present */ + { + if (corb_read (mixer, cad, ix, 0, GET_GAIN (1, 0), 0, &a, &b)) + printf ("\tLeft output gain %02x\n", a); + else + printf ("\tLeft output gain read error\n"); + if (corb_read (mixer, cad, ix, 0, GET_GAIN (1, 1), 0, &a, &b)) + printf ("\tRight output gain %02x\n", a); + else + printf ("\tRight output gain read error\n"); + } + + if (wcaps & (1 << 1)) /* Input amp(s) present */ + for (i = 0; i < clen; i++) + { + if (corb_read (mixer, cad, ix, 0, GET_GAIN (0, 0), 0, &a, &b)) + printf ("\tInput gain %2d %02x", i, a); + else + printf ("\tInput gain %2d - Read error\n"); + if (corb_read (mixer, cad, ix, 0, GET_GAIN (0, 1), 0, &a, &b)) + printf (", %02x", a); + else + printf (", Read error"); + printf ("\n"); + } +} + +static void +dump_node (int ix) +{ + int i; + unsigned int a, b, gtype, gcaps, wcaps, sizes, fmts, pincaps; + unsigned int inamp_caps, outamp_caps, clen, pstates, pcaps, gpio_count; + unsigned int vkcaps; + hda_name_t name; + int first_node = 0, num_nodes = 0; + char *s; + int ntype = -1; + + memset (&name, 0, sizeof (name)); + + name.cad = cad; + name.wid = ix; + ioctl (fd, HDA_IOCTL_NAME, &name); + + printf ("\n*** Widget 0x%02x (%d) name=%s\n", ix, ix, name.name); + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_GROUP_TYPE, >ype, &b)) + if ((gtype & 0x1ff) != 0) + { + s = "Unknown"; + + switch (gtype & 0xff) + { + case 0: + s = "Reserved"; + break; + case 1: + s = "Audio function group"; + break; + case 2: + s = "Vendor defined modem function group"; + break; + } + + printf ("\tGroup type=%08x (%s), UnSol capable %d\n", gtype & 0xff, s, + (gtype >> 8) & 1); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_AUDIO_GROUP_CAPS, &gcaps, &b)) + if ((gcaps & 0xffff) != 0) + { + printf ("\tAudio group capabilities %08x\n", gcaps); + printf ("\t\tBeep gen %d\n", (gcaps >> 16) & 1); + printf ("\t\tInput delay %d\n", (gcaps >> 8) & 0xf); + printf ("\t\tOutput delay %d\n", (gcaps) & 0xf); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_WIDGET_CAPS, &wcaps, &b)) + if (wcaps != 0) + { + int type; + + printf ("\tAudio widget capabilities %08x\n", wcaps); + + type = (wcaps >> 20) & 0xf; + s = "Unknown"; + + switch (type) + { + case 0: + s = "Audio output converter (DAC)"; + break; + case 1: + s = "Audio input converter (ADC)"; + break; + case 2: + s = "Audio mixer"; + break; + case 3: + s = "Audio selector"; + break; + case 4: + s = "Pin complex"; + break; + case 5: + s = "Power widget"; + break; + case 6: + s = "Volume knob widget"; + break; + case 7: + s = "Beep generator widget"; + break; + case 0xf: + s = "Vendor defined"; + break; + } + + ntype = type; + + printf ("\t\tType %x (%s)\n", type, s); + printf ("\t\tDelay %d\n", (wcaps >> 16) & 0xf); + printf ("\t\tL-R Swap %d\n", (wcaps >> 11) & 1); + printf ("\t\tPowerControl %d\n", (wcaps >> 10) & 1); + printf ("\t\tDigital %d\n", (wcaps >> 9) & 1); + printf ("\t\tConnList %d\n", (wcaps >> 8) & 1); + printf ("\t\tUnsol capable %d\n", (wcaps >> 7) & 1); + printf ("\t\tProc Widget %d\n", (wcaps >> 6) & 1); + printf ("\t\tStripe %d\n", (wcaps >> 5) & 1); + printf ("\t\tFormat Override %d\n", (wcaps >> 3) & 1); + printf ("\t\tAmp param Override %d\n", (wcaps >> 3) & 1); + printf ("\t\tOut amp present %d\n", (wcaps >> 2) & 1); + printf ("\t\tIn amp present %d\n", (wcaps >> 1) & 1); + printf ("\t\tStereo %d\n", (wcaps >> 0) & 1); + + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_CONNLIST_LEN, &clen, &b)) + if (clen != 0) + { + unsigned int clist; + int j; + + printf ("\tConnection list len %d (longform=%d): ", clen & 0x7f, + clen >> 7); + + clen &= 0x7f; + + for (i = 0; i < clen; i += 4) + if (corb_read + (mixer, cad, ix, 0, GET_CONNECTION_LIST_ENTRY, i, &clist, &b)) + for (j = 0; j < 4 && (i + j) < clen; j++) + { + printf ("0x%x ", (clist >> (j * 8)) & 0xff); + } + + printf ("\n"); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_PIN_CAPS, &pincaps, &b)) + if (pincaps != 0) + { + printf ("\tPin capabilities\n"); + if (pincaps & (1 << 16)) + printf ("\t\tEAPD capable\n"); + printf ("\t\tVref control %02x\n", (pincaps >> 8) & 0xff); + if (pincaps & (1 << 6)) + printf ("\t\tBalanced I/O pins\n"); + if (pincaps & (1 << 5)) + printf ("\t\tInput capable\n"); + if (pincaps & (1 << 4)) + printf ("\t\tOutput capable\n"); + if (pincaps & (1 << 3)) + printf ("\t\tHeadphone drive capable\n"); + if (pincaps & (1 << 2)) + printf ("\t\tPrecense detect capable\n"); + if (pincaps & (1 << 1)) + printf ("\t\tTrigger required\n"); + if (pincaps & (1 << 0)) + printf ("\t\tImpedance sense capable\n"); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_STREAM_FMTS, &fmts, &b)) + if (fmts != 0) + { + printf ("\tSupported stream formats %08x\n", fmts); + if (fmts & 0x01) + printf ("\t\tPCM\n"); + if (fmts & 0x02) + printf ("\t\tFloat32\n"); + if (fmts & 0x04) + printf ("\t\tAC3\n"); + } + + if (corb_read (mixer, cad, ix, 0, GET_PARAMETER, HDA_PCM_SIZES, &sizes, &b)) + if (sizes != 0) + { + printf ("\tSupported sample sizes/rates %08x\n", sizes); + + if (sizes & (1 << 20)) + printf ("\t\t32 bits\n"); + if (sizes & (1 << 19)) + printf ("\t\t24 bits\n"); + if (sizes & (1 << 18)) + printf ("\t\t20 bits\n"); + if (sizes & (1 << 17)) + printf ("\t\t16 bits\n"); + if (sizes & (1 << 16)) + printf ("\t\t8 bits\n"); + + if (sizes & (1 << 11)) + printf ("\t\t384 kHz\n"); + if (sizes & (1 << 10)) + printf ("\t\t192 kHz\n"); + if (sizes & (1 << 9)) + printf ("\t\t176.4 kHz\n"); + if (sizes & (1 << 8)) + printf ("\t\t96 kHz\n"); + if (sizes & (1 << 7)) + printf ("\t\t88.2 kHz\n"); + if (sizes & (1 << 6)) + printf ("\t\t48 kHz\n"); + if (sizes & (1 << 5)) + printf ("\t\t44.1 kHz\n"); + if (sizes & (1 << 4)) + printf ("\t\t32 kHz\n"); + if (sizes & (1 << 3)) + printf ("\t\t22.05 kHz\n"); + if (sizes & (1 << 2)) + printf ("\t\t16 kHz\n"); + if (sizes & (1 << 1)) + printf ("\t\t11.025 kHz\n"); + if (sizes & (1 << 0)) + printf ("\t\t8 kHz\n"); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_INPUTAMP_CAPS, &inamp_caps, &b)) + if (inamp_caps != 0) + { + printf ("\tInput amp caps %08x\n", inamp_caps); + printf ("\t\tMute Capable %d\n", (inamp_caps >> 31) & 0x1); + printf ("\t\tStep size %d\n", (inamp_caps >> 16) & 0x7f); + printf ("\t\tNum steps %d\n", (inamp_caps >> 8) & 0x7f); + printf ("\t\tOffset %d\n", (inamp_caps >> 0) & 0x7f); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_OUTPUTAMP_CAPS, &outamp_caps, + &b)) + if (outamp_caps != 0) + { + printf ("\tOutput amp caps %08x\n", outamp_caps); + printf ("\t\tMute Capable %d\n", (outamp_caps >> 31) & 0x1); + printf ("\t\tStep size %d\n", (outamp_caps >> 16) & 0x7f); + printf ("\t\tNum steps %d\n", (outamp_caps >> 8) & 0x7f); + printf ("\t\tOffset %d\n", (outamp_caps >> 0) & 0x7f); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_SUPPORTED_POWER_STATES, &pstates, + &b)) + if (pstates != 0) + { + printf ("\tSupported power states %08x\n", pstates); + if (pstates & (1 << 3)) + printf ("\t\tD3\n"); + if (pstates & (1 << 2)) + printf ("\t\tD2\n"); + if (pstates & (1 << 1)) + printf ("\t\tD1\n"); + if (pstates & (1 << 0)) + printf ("\t\tD0\n"); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_PROCESSING_CAPS, &pcaps, &b)) + if (pcaps != 0) + { + printf ("\tProcessing capabilities %08x\n", pcaps); + printf ("\t\tNumCoeff %d\n", (pcaps >> 8) & 0xff); + printf ("\t\tBening %d\n", pcaps & 1); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_GPIO_COUNT, &gpio_count, &b)) + if (gpio_count != 0) + { + printf ("\tGPIO count %08x\n", gpio_count); + printf ("\t\tGPIWake %d\n", (gpio_count >> 31) & 0x1); + printf ("\t\tGPIUnsol %d\n", (gpio_count >> 30) & 0x1); + printf ("\t\tNumGPIs %d\n", (gpio_count >> 16) & 0xff); + printf ("\t\tNumGPOs %d\n", (gpio_count >> 8) & 0xff); + printf ("\t\tNumGPIOs %d\n", (gpio_count >> 0) & 0xff); + } + + if (ntype >= 0) + dump_verbs (ix, ntype, clen, wcaps); + else + { + if (corb_read (mixer, cad, ix, 0, GET_SUBSYSTEM_ID, 0, &a, &b)) + printf ("\tSubsystem ID %08x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPI_DATA, 0, &a, &b)) + printf ("\tGPI data %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPI_WAKE, 0, &a, &b)) + printf ("\tGPI wake mask %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPI_UNSOL, 0, &a, &b)) + printf ("\tGPI unsolicited mask %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPI_STICKY, 0, &a, &b)) + printf ("\tGPI sticky mask %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPO_DATA, 0, &a, &b)) + printf ("\tGPO data %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPIO_DATA, 0, &a, &b)) + printf ("\tGPIO data %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPIO_ENABLE, 0, &a, &b)) + printf ("\tGPIO enable %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPIO_DIR, 0, &a, &b)) + printf ("\tGPIO direction %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPIO_WKEN, 0, &a, &b)) + printf ("\tGPIO wake enable %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPIO_UNSOL, 0, &a, &b)) + printf ("\tGPIO unsolicited enable mask %02x\n", a); + if (corb_read (mixer, cad, ix, 0, GET_GPIO_STICKY, 0, &a, &b)) + printf ("\tGPIO sticky mask %02x\n", a); + } + + if (corb_read + (mixer, cad, ix, 0, GET_PARAMETER, HDA_VOLUMEKNOB_CAPS, &vkcaps, &b)) + if ((vkcaps & 0xff) != 0) + { + printf ("\tVolume knob capabilities %08x\n", vkcaps); + } + + if (corb_read (mixer, cad, ix, 0, GET_PARAMETER, HDA_NODE_COUNT, &a, &b)) + { + first_node = (a >> 16) & 0xff; + num_nodes = a & 0xff; + } + else + num_nodes = 0; + + if (num_nodes > 0) + { + printf ("\tFirst node %02x, num nodes %d\n", first_node, num_nodes); + + for (i = first_node; i < first_node + num_nodes; i++) + dump_node (i); + } +} + +int +main (int argc, char *argv[]) +{ + unsigned int a, b; + int first_node, num_nodes; + int i; + + if ((fd = open ("/dev/oss/oss_hdaudio0/pcm0", O_RDWR | O_EXCL, 0)) == -1) + { + perror ("/dev/oss/oss_hdaudio0/pcm0"); + exit (-1); + } + + if (argc > 1) + cad = atoi (argv[1]); + if (cad == -1) /* Not given on command line so find it. */ + for (cad = 0; cad < 16; cad++) + if (corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_VENDOR, &a, &b)) + break; + + printf ("Codec index is %d\n", cad); + printf ("Codec vendor %04x:%04x\n", a >> 16, a & 0xffff); + + if (corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_REVISION, &a, &b)) + { + printf ("HD codec revision %d.%d (%d.%d) (0x%08x)\n", + (a >> 20) & 0xf, (a >> 16) & 0xf, (a >> 8) & 0xff, a & 0xff, a); + } + else + printf ("hdaudio: Can't get codec revision\n"); + +/* + * Find out the primary group list + */ + + if (!corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_NODE_COUNT, &a, &b)) + exit(1); + + first_node = (a >> 16) & 0xff; + num_nodes = a & 0xff; + + printf ("First node %02x, num nodes %d\n", first_node, num_nodes); + + for (i = first_node; i < first_node + num_nodes; i++) + dump_node (i); + + exit (0); +} diff --git a/utils/vib b/utils/vib new file mode 100755 index 0000000..1117197 --- /dev/null +++ b/utils/vib @@ -0,0 +1,9 @@ +#!/bin/sh + +TOP=. +if test -d origdir +then + TOP=origdir +fi + +vi `find $TOP/kernel/OS/FreeBSD $TOP/setup/FreeBSD $TOP/os_cmd/FreeBSD -name $1` diff --git a/utils/vif b/utils/vif new file mode 100755 index 0000000..6b70707 --- /dev/null +++ b/utils/vif @@ -0,0 +1,9 @@ +#!/bin/sh + +TOP=. +if test -d origdir +then + TOP=origdir/ +fi + +vi `find $TOP -name $1` diff --git a/utils/vil b/utils/vil new file mode 100755 index 0000000..7ed0c94 --- /dev/null +++ b/utils/vil @@ -0,0 +1,9 @@ +#!/bin/sh + +TOP=. +if test -d origdir +then + TOP=origdir +fi + +vi `find $TOP/kernel/OS/Linux $TOP/setup/Linux $TOP/os_cmd/Linux -name $1` diff --git a/utils/vil24 b/utils/vil24 new file mode 100755 index 0000000..a657daf --- /dev/null +++ b/utils/vil24 @@ -0,0 +1,3 @@ +#!/bin/sh + +vi `find ./kernel/OS/Linux24 setup/Linux24 os_cmd/Linux24 -name $1` diff --git a/utils/vis b/utils/vis new file mode 100755 index 0000000..572b786 --- /dev/null +++ b/utils/vis @@ -0,0 +1,9 @@ +#!/bin/sh + +TOP=. +if test -d origdir +then + TOP=origdir +fi + +vi `find $TOP/kernel/OS/SunOS $TOP/setup/SunOS $TOP/os_cmd/SunOS -name $1` diff --git a/utils/viu b/utils/viu new file mode 100755 index 0000000..d6e322d --- /dev/null +++ b/utils/viu @@ -0,0 +1,9 @@ +#!/bin/sh + +TOP=. +if test -d origdir +then + TOP=origdir +fi + +vi `find $TOP/kernel/OS/SCO_SV $TOP/setup/SCO_SV $TOP/os_cmd/SCO_SV -name $1` diff --git a/utils/viv b/utils/viv new file mode 100755 index 0000000..3e0803d --- /dev/null +++ b/utils/viv @@ -0,0 +1,9 @@ +#!/bin/sh + +TOP=. +if test -d origdir +then + TOP=origdir +fi + +vi `find $TOP/kernel/OS/VxWorks $TOP/setup/VxWorks -name $1` |