Originally Posted by Mathiasdm
I basically just want to be able to work with pcspkr, by sending commands to it.
I know it should be possible to create a location like /dev/beep , to which I could send commands (so pcspkr receives them and produces a 'beep' sound). I just don't know how to do this ('mknod' requires knowing the major and minor device numbers, which I don't).
Well, the driver is very different from the type you wrote before. A device node will be created, but it happens to be very different from what you’d expect. The device for pcspkr
is (mainly for historical reasons) an “input device” (which means it provides a way to relay input events from the kernel to userspace, as well as process the events themselves). This is much like a mouse device or a keyboard device. Anyway the input event device will be provided with major number 13 and a dynamically-assigned minor number (starting at 64 and incrementing for each event device). You don’t have to worry about manually mknod
ing since udev
will take care of it for you. For example, on my system it goes like this (after I’ve done “modprobe pcspkr
/dev/input/event0: AT Translated Set 2 keyboard
/dev/input/event1: ImPS/2 Logitech Wheel Mouse
/dev/input/event2: Power Button (FF)
/dev/input/event3: Power Button (CM)
/dev/input/event4: PC Speaker
Now each of these devices give you nice input events if you read them from userspace. As an example, you might try
od -tx1 -w32 /dev/input/event0
Since this is a keyboard, when I do any thing keyboardy (such as pressing or releasing a key), an nice 32-byte value is written to my screen. This value contains lots of information such as the timestamp, the event type, the event code, and the value associated with the event. Of course to really make sense of this information, it would be easiest to do something like this from a loop in a C program:
struct input_event ie;
fd = open("/dev/input/event0", 0);
read(fd, &ie, sizeof(struct input_event));
Anyway, that’s the only way you’re supposed to use input event devices from userspace (namely, you’re not supposed to write to them).
But you’re probably saying, “making a speaker beep obviously requires some sort of ‘write’ operation” and you’re correct. The only thing is that you don’t do it through the driver’s device node. Currently the way to do this is by using an ioctl()
on the root console (i.e., on /dev/console
). Basically, it goes like this:
#define DESIRED_FREQ 440 /* We want the frequency to be of note A */
fd = open("/dev/console", O_WRONLY);
ioctl(fd, KIOCSOUND, CLOCK_TICK_RATE / DESIRED_FREQ) /* Now, the speaker is made to beep */
ioctl(fd, KIOCSOUND, 0); /* Now, the speaker is silenced */
Note that there is also a different type of beep: the one implemented by the BIOS itself. I.e., if you do a rudimentary “putchar” of 0x7 (\a
) to the BIOS you get an implementation-specific beep. This is not seen by the input event device at all.