Sound card as a console device

    Poul-Henning Kamp on the freebsd-arch mailing list has shown code examples that allow console I / O through a sound card. The original of his letter is here , and I offer my translation, as close as possible to the original. I could not translate some words, therefore I leave in the original and in parentheses I give my assumptions.

    Yesterday, when I suffered from garbage while working with my new laptop and the functions of pausing / resuming ACPI, I again found myself cursing the crazy guy who removed our serial ports from laptops.

    I thought a little and it suddenly dawned on me: all modern devices have built-in support for AC97 audio equipment, which provides pretty good bandwidth.

    This morning I started a simple experiment. The result makes it clear that the idea is working, although it works from userland (maybe in the user space ? Google definitions give just that answer - approx. Transl.).

    I used the following format for transmission: sending a short-term negative edge to the beginning of a character, and then N discrete, then a positive edge. N - ASCII value of the character + small constant.

    I am attaching a code that confirms the concept ( proof-of-concept in the original - approx. Transl.), Which uses two stereo channels on a differential pair (not sure if this is a good idea).

    In the first attempt, I was able to transmit about 320 characters per second with 1% error.

    What remains to be done:

        * Optimize transmission scheme.

            This can be done with two computers, a jack-in-jack cable and a bit of C code.

            The difference in sampling rate between the two computers leads to an error of understating or overstating by one. I don’t know if the peak detector with interpolation can solve this problem, or we will be forced to use frequency sampling ( oversampling - approx. Transl.) In the receiver.

            Two pulses can have different polarities, i.e. we can transmit two bits, which can increase the transmission speed by a factor of four ( factor of four probably means exactly this - approx. transl.) if we find a way to properly synchronize.

            Two stereo channels can be used independently, doubling the speed.

        * write a kernel level console driver that works with audio equipment without using interrupts.

            I don’t know what the interface to the sound card looks like, but I suspect it’s pretty simple.

    Even if the connection is unidirectional, kernel hackers like me will honor anyone who finishes this work.

    Come on!

    Poul-hening

    /* proof of concept transmission code */
    #include 
    #include 
    #include 
    #include 
    #define OFF 5
    static short int buf[2*128 + 2 * OFF];
    int
    main(int argc __unused, char **argv __unused)
    {
    	int fd_dsp;
    	int i, j, k, c;
    	fd_dsp = open("/dev/dsp0.1", O_RDWR);
    	if (fd_dsp < 0)
    		err(1, "open /dev/dsp");
    	i = ioctl(fd_dsp, SNDCTL_DSP_RESET, &j);
    	assert(i == 0);
    	j = 2;
    	i = ioctl(fd_dsp, SNDCTL_DSP_CHANNELS, &j);
    	assert(i == 0);
    	j = 44100;
    	i = ioctl(fd_dsp, SNDCTL_DSP_SPEED, &j);
    	assert(i == 0);
    	j = 16;
    	i = ioctl(fd_dsp, SNDCTL_DSP_SETFMT, &j);
    	assert(i == 0);
    	while (1) {
    		c = getchar();
    		if (c == EOF)
    			break;
    		buf[OFF] =  32000;
    		buf[OFF + 1] = -32000;
    		buf[OFF + 2 * c] = -32000;
    		buf[OFF + 2 * c + 1] =  32000;
    		i = write(fd_dsp, buf, sizeof buf);
    		assert(i == sizeof buf);
    		buf[OFF + 2 * c] = 0;
    		buf[OFF + 1 + 2 * c] = 0;
    	}
    	exit (0);
    }


    /* proof of concept reception code */
    #include 
    #include 
    static int
    sample(FILE *f, const char *p)
    {
            short l, r;
            int i, s;
            i = fread(&l, sizeof l, 1, stdin);
            assert(i == 1);
            i = fread(&r, sizeof l, 1, stdin);
            assert(i == 1);
            s = l;
            s -= r;
            if (0 && p != NULL)
                    printf("%6d %s\n", s, p);
            return (s);
    }
    static void
    find_neg_peak(FILE *f)
    {
            int s, sl;
            while (1) {
                    s = sample(stdin, "v");
                    if (s < -10000)
                            break;
            }
            sl = s;
            while (1) {
                    s = sample(stdin, "N");
                    if (s > sl)
                            return;
                    sl = s;
            }
    }
    static int
    find_pos_peak(FILE *f)
    {
            int s, sl, k;
            k = 0;
            while (1) {
                    k++;
                    s = sample(stdin, "^");
                    if (s > 10000)
                            break;
            }
            sl = s;
            while (1) {
                    k++;
                    s = sample(stdin, "P");
                    if (s < sl)
                            return (k);
                    sl = s;
            }
    }
    int
    main(int argc __unused, char **argv)
    {
            short l, r;
            int i, k, p, s, sl;
            k = 0;
            p = 0;
            while (1) {
                    find_neg_peak(stdin);
                    k = find_pos_peak(stdin);
                    if (k == 10)
                            printf("\\n\n");
                    else if (k >= ' ' && k <= '~')
                            printf("%c", k);
                    else
                            printf("\\x%02x", k);
            }
            exit (0);
    }


    Also popular now: