# 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);
}``````