Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Bit: 7 6 5 4 3 2 1 0
value: 128 64 32 16 8 4 2 1
------- ------- ----------- ---
channel order mode format
I'm not going in too deeply on the modes, we will use mode:
0 1 1, so this means we have to set bit 1 and 2.
As for the channels:
channel 0 bits 0 0
channel 1 bits 0 1
channel 2 bits 1 0
so naturally we need to set bits 6 and 7 to: 1 0, we don't
wanna mess up our DMA refreshing.
The format bit specifies wether it's in BCD (Binary Code
Decimal) or binary. We'll use the last one.
After sending this control byte, we want to change the
value of of channel 2, so we have to put in the new
countdown value. This countdown value is calculated in the
following way:
Bit: 7 6 5 4 3 2 1 0
value: 128 64 32 16 8 4 2 1
cond.: 1 0 1 1 0 1 1 0
------- ------- ----------- ---
channel order mode format
#include <stdio.h>
#include <stdlib.h>
FreeBSD:
#include <sys/types.h>
#include <machine/cpufunc.h>
#include <machine/sysarch.h>
#include <unistd.h>
Linux:
#include <sys/io.h>
#include <unistd.h>
Win32/DOS:
#include <conio.h>
9. Programming: getting the correct permissions.
ok, now, to control hardware devices we must have
permission to use these devices, right? On FreeBSD and
Linux we can use the ioperm permission functions, but Win32
doesn't have these. It's offcourse logical that all users
can mess up devices right? (sarcasm)
FreeBSD:
i386_get_ioperm(int start, int length, int enable);
Linux:
ioperm(int start, int length, int enable);
FreeBSD:
i386_set_ioperm(0x61, 0x20, 1);
i386_set_ioperm(0x42, 0x02, 1);
Linux:
ioperm(0x61, 0x20, 1);
ioperm(0x42, 0x02, 1);
FreeBSD:
int inb(port);
outb(int port, int value);
Linux:
int inb(port);
outb(int value, int port);
Win32/DOS:
int _inp(port);
_outp((unsigned short)int port, int value);
__asm__ (
"mov %%ax, %%bx;"//move our byte in 16bits: ax
"movb %%bl, %%cl;"//move lower byte reg to cl
"movb %%bh, %%dl;"//move higher byte reg to dl
:"=c"(lo), "=d"(hi) //our output
:"a"(byte) //our input
);
FreeBSD:
outb(0x43, 0x6b);
outb(0x42, lowerbyte);
outb(0x42, higherbyte);
int value = inb(0x61);
value = value | 3;
outb(0x61, value);
sleep(1);
value = inb(0x61);
value = value & 0xfc;
outb(0x61, value);
Linux:
outb(0x6b, 0x43);
outb(lowerbyte, 0x42);
outb(higherbyte, 0x42);
int value = inb(0x61);
value = value | 3;
outb(value, 0x61);
sleep(1);
value = inb(0x61);
value = value & 0xfc;
outb(value, 0x61);
Win32/DOS:
_outp(0x43, 0x6b);
_outp(0x42, lowerbyte);
_outp(0x42, higherbyte);
int value = _inp(0x61);
value = value | 3;
_outp(0x61, value);
sleep(1);
value = _inp(0x61);
value = value & 0xfc;
_outp(0x61, value)
ok, let's review:
we use int value = inb(0x61); to get the current value of
this port. After this we make sure bit 0 and 1 (values: 1 +
2 = 3) are set, by doing: value = value | 3; outb(0x61,
value);
by doing this, the speaker makes noise. Then after sleep
(1); the speaker stops by doing:
value = inb(0x61);
value = value & 0xfc;
outb(0x61, value);
11. References / Sources of information.
1 /*
2
3 DarkSpeaker 0.6
4 pc speaker control program
5 Linux, FreeBSD, Win9x
6
7 author: dodo <dodo@darkwired.org>
8 contact: http://www.darkwired.org/
9
10 this code is licensed under the GNU GPL
11 by compiling this, you agree to this license
12
13 notes:
14 - now compat with MSVC++ / win9x (juckie:p)
15 - for porting to WinNT, change _outp/_inp
16
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21
22 #ifdef __FreeBSD__
23 #include <sys/types.h>
24 #include <machine/cpufunc.h>
25 #include <machine/sysarch.h>
26 #include <unistd.h>
27 #elif defined WIN32
28 #include <conio.h>
29 #else
30 #include <sys/io.h>
31 #include <unistd.h>
32 #endif
33
34
35 class DarkSpeaker {
36 public:
37 //main functions:
38 bool TimerSetFrequency(int herz);
39 bool TimerSpeakerConnect(void);
40 bool TimerSpeakerDisconnect(void);
41 bool SpeakerBeep(int herz, int microseconds);
42 //io functions:
43 bool IOperm(int port, int num);
44 bool IOoutb(int port, int value);
45 long IOinb(int port);
46 //misc funtions:
47 void GetHLbytes(int byte, int *low, int *high);
48 };
49
50 int port_timer2a = 0x43;
51 int port_timer2b = 0x42;
52 int port_speaker = 0x61;
53 DarkSpeaker DarkSpeaker;
54
55 int main(int argc, char *argv[])
56 {
57
58 if(argc<3) {
59 printf(
60 "usage: %s <frequency/hz> <duration/ms>\n"
61 "DarkSpeaker by dodo <dodo@darkwired.org>\n"
62 ,argv[0]
63 );
64 return 0;
65 }
66
67 if(DarkSpeaker.IOperm(port_speaker, 0x20)==false) {
68 printf("could not get 0x61 I/O permissions\n");
69 return 0;
70 }
71
72 if(DarkSpeaker.IOperm(port_timer2b, 0x02)==false) {
73 printf("could not get 0x42 I/O permissions\n");
74 return 0;
75 }
76
77
78 DarkSpeaker.SpeakerBeep(atoi(argv[1]), atoi(argv[2]));
79 return 1; //MSVC++
80 }
81
82
83 bool DarkSpeaker::TimerSetFrequency(int herz)
84 {
85 int countdown;
86 int lc, hc;
87 /* we need to know the countdown value for timer2 */
88 countdown = 1193180 / herz;
89
90 GetHLbytes(countdown, &lc, &hc);
91 IOoutb(port_timer2a, 0xb6); // tell timer 2 we want to
change countdown
92 IOoutb(port_timer2b, lc); //put in lower byte of
countdown value
93 IOoutb(port_timer2b, hc); //put in higher byte of
countdown value
94
95 return false;
96 }
97
98
99 bool DarkSpeaker::TimerSpeakerConnect(void)
100 {
101 int value;
102 value = IOinb(port_speaker);
103 //printf("value: %d\n", value);
104 value = value | 3;
105 IOoutb(port_speaker, value);
106 return false;
107 }
108
109 bool DarkSpeaker::TimerSpeakerDisconnect(void)
110 {
111 int value;
112 value = IOinb(port_speaker);
113 //printf("value: %d\n", value);
114 value = value & 0xfc;
115 IOoutb(port_speaker, value);
116 return false;
117 }
118
119 bool DarkSpeaker::IOperm(int port, int num)
120 {
121 #ifdef WIN32
122 return true;
123 #elif defined __FreeBSD__
124 if(i386_set_ioperm(port, num, 1))
125 #else
126 if(ioperm(port, num, 1))
127 #endif
128 return false;
129 return true;
130 }
131
132 bool DarkSpeaker::IOoutb(int port, int value)
133 {
134 #ifdef __FreeBSD__
135
136 outb(port, value);
137
138 #elif defined WIN32
139
140 /* old win32 stuff
141 unsigned short int prt = (unsigned short int)port;
142 char val = (char)value;
143
144 __asm
145 {
146 mov dx, prt
147 mov al, val
148 out dx, al
149 }
150 */
151 _outp((unsigned short)port, value);
152
153 #else
154
155 outb(value, port);
156
157 #endif
158
159 return false;
160 }
161
162
163 long DarkSpeaker::IOinb(int port)
164 {
165 #ifdef WIN32
166 int val;
167 /* old win32 stuff
168 unsigned short int prt = (unsigned short int)port;
169 unsigned char val;
170
171 __asm
172 {
173 mov dx, prt
174 in al, dx
175 mov val, al
176 }
178 val = _inp(port);
179
180 return val;
181
182 #else
183
184 return inb(port);
185
186 #endif
187 }
188
189 void DarkSpeaker::GetHLbytes(int byte, int *low, int *high)
190 {
191 char lo;
192 char hi;
193
194 #ifdef __Linux__
195 __asm__ (
196 "mov %%ax, %%bx;" //move the byte in 16bits: ax
197 "movb %%bl, %%cl;" //move lower byte reg to cl
198 "movb %%bh, %%dl;" //move higher byte reg to dl
199
200 :"=c"(lo), "=d"(hi) //the output
201 :"a"(byte) //the input
202 );
203 #else
204 lo = byte & 0xff;
205 hi = (byte >> 8) & 0xff;
206 #endif
207
208 //printf("high = %d\nlow = %d\nbyte = %d\n\n", hi, lo, byte);
209
210 *low = (int)lo;
211 *high = (int)hi;
212 }
213
214 bool DarkSpeaker::SpeakerBeep(int herz, int microseconds)
215 {
216 TimerSetFrequency(herz);
217 TimerSpeakerConnect();
218 #ifdef WIN32
219 _sleep((int)(microseconds/1000000)); // need something for this
220 #else
221 usleep(microseconds);
222 #endif
223
224 TimerSpeakerDisconnect();
225 return false;
226 }
227