Method 2 for Controlling PC Speaker with C Programming

In the article “Controlling PC Speaker with C Programming”, we learned to manipulate hardware through IO ports. However, for some readers, this can be too vague and easily confusing. This time, we will use the most basic write system call to write input_event data to achieve the same functionality. For more information on input_event, please refer to the article “Method 2 for Blinking Keyboard LED with C Programming”. Additionally, we need to load the pcspkr driver first, which can be understood by reviewing the article “Controlling Speaker Sound with Shell Commands”.

First, execute the sudo modprobe pcspkr command to load the driver, and then check the /proc/bus/input/devices file. The output on my side is as follows:

I: Bus=0010 Vendor=001f Product=0001 Version=0100N: Name="PC Speaker"P: Phys=isa0061/input0S: Sysfs=/devices/platform/pcspkr/input/input17U: Uniq=H: Handlers=kbd event15B: PROP=0B: EV=40001B: SND=6

This is the output generated after loading the Linux kernel drivers/input/misc/pcspkr.c file corresponding to the pcspkr driver. In our input_event settings, the type is set to EV_SND, and the code can be set to SND_TONE and SND_BELL. The former only accepts value between 20 and 32767, while other values will be silent. The latter accepts 0 for silence, and any other value will be converted to 1000.

Next, let’s look at the code. You can see our processing in the code:

#include <stdio.h>#include <linux/input.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define PCSPKR_EVENT_PATH "/dev/input/event15"int main(int argc,char * argv[]){        unsigned int val;        int fd = 0;        struct input_event ev;        ev.type = EV_SND;        if (argc != 2) {                printf("Usage:%s value\n 20<value<32767\n",argv[0]);                return 0;        }        fd = open(PCSPKR_EVENT_PATH, O_RDWR);        if (fd < 0) {                printf("Open PCSPKR failed!\n");                return 1;        }        val = atoi(argv[1]);        if (val > 20 && val < 32767) {                ev.code = SND_TONE;                ev.value = val;                write(fd, &ev, sizeof(ev));        } else {                //when val = 0,it'll mute;other value will all set 1000                ev.code = SND_BELL;                ev.value = val;                write(fd, &ev, sizeof(ev));        }        if (val)                sleep(5);        ev.value = 0;        write(fd, &ev, sizeof(ev));        close(fd);        return 0;}

The corresponding content of the Makefile is as follows:

all:        make beep#gcc -o beep beep.cclean:        rm -rf beep

The directory tree of the source files is as follows:

/home/xinu/xinu/c_cpp/beep_input_event/├── beep.c└── Makefile

Thus, we have implemented another method to control the speaker, but the core remains the operation of the IO port. However, it is still important to understand the system call method for input_event, as this is commonly used for input devices in Android. Remember to run the command with sudo.

Leave a Comment