Do sometimes think about how would it be if your programs had not only visual effects, but also some sound?
Programming the sound cards (especially the modern ones) can be quite troublesome. Fortunately, the good old PC-speaker is a device which you can program quite easily. This is what I'm going to prove here. First some theory.
Linux is an operating system which works fully in protected mode. This is why we can't use the interesting (42h, 43h, 61h) input/output ports directly without root privileges.
Fortunately, the system function sys_ioctl (number 54) will help us in bringing the PC-speaker alive. This function expects the following parameters:
But this is not all. We'd like our sound to last for a while. For that we'll use the system function sys_nanosleep (number 162). Its syntax is simple:
struc timespec
{
.tv_sec rd 1
.tv_nsec rd 1
}
containing number of seconds and nanoseconds to wait for.As you can see, the algorithm of our program is simple:
Example program follows (using my library isn't necessary - the comments tell what to change):
; A program making sounds from the PC-speaker using sys_ioctl
; Author: Bogdan D.
; Contact: bogdandr (at) op (dot) pl
;
; assemble:
; fasm spkr.asm spkr
format ELF executable
entry _start
segment readable executable
include "bibl/incl/linuxbsd/fasm/fasm_system.inc"
KIOCSOUND = 0x4B2F
_start:
mov eax, sys_open ; sys_open = 5
mov ebx, konsola
mov ecx, O_WRONLY ; O_WRONLY = 1
mov edx, 777o
int 80h
cmp eax, 0 ; was there an error (EAX < 0) ?
jg .otw_ok
mov eax, 1 ;if we didn't open the console, use STDOUT (1)
.otw_ok:
mov ebx, eax ; EBX = file handle
mov eax, sys_ioctl ; sys_ioctl = 54
mov ecx, KIOCSOUND
xor edx, edx ; turning off the current sound
int 80h
mov eax, sys_ioctl
mov edx, 2711 ; 2711 = 1234DDh/440. 440 Hz is the 'A' note
int 80h
mov cx, 0fh
mov dx, 4240h ; 0F4240h is 1 decimal million in hexadecimal
call pauza
mov eax, sys_ioctl
mov ecx, KIOCSOUND
xor edx, edx ; turning off the sound
int 80h
cmp ebx, 2 ; check if using /dev/console or STDOUT
jbe .koniec
mov eax, sys_close ; sys_close = 6
int 80h ; close the open console file
.koniec:
mov eax, 1
xor ebx, ebx
int 80h
pauza: ;procedure pausing for CX:DX milliseconds
push ebx
push ecx
push edx
mov ax, cx
shl eax, 16
mov ebx, 1000000
mov ax, dx ; EAX = CX:DX
xor edx, edx
div ebx ; divide CX:DX by 1 million
mov [t1.tv_sec], eax ; EAX = number of seconds
mov ebx, 1000
mov eax, edx ;EAX = number of microseconds left
mul ebx
mov [t1.tv_nsec], eax ; EAX = number of nanoseconds
mov eax, sys_nanosleep ; function number 162
mov ebx, t1
mov ecx, t2
int 80h
pop edx
pop ecx
pop ebx
ret
segment readable writeable
konsola db "/dev/console", 0
struc timespec
{
.tv_sec rd 1
.tv_nsec rd 1
}
t1 timespec
t2 timespec
I hope to have given enough information for you to start programming the speaker on your own. If the program isn't working, you may need to compile pc-speaker support into your kernel (or insert the needed modules). Sometimes root privileges are necessary.
Have fun!