@@ -260,18 +260,16 @@ void highlight_current_cell(minefield *mf)
260
260
old_y = y ;
261
261
}
262
262
263
-
264
- #ifdef USE_DEBUG_MODE
265
- /* Thanks to OSDev Wiki for the serial initialization sequence! */
266
-
267
- #define SERIAL_PORT_ADDR 0x3f8
268
263
static inline uint8_t inb (uint16_t port )
269
264
{
270
265
uint8_t value ;
271
266
asm __volatile ("inb %1, %0" : "=Ral" (value ) : "Nd" (port ));
272
267
return value ;
273
268
}
274
269
270
+ #ifdef USE_DEBUG_MODE
271
+ /* Thanks to OSDev Wiki for the serial initialization sequence! */
272
+ #define SERIAL_PORT_ADDR 0x3f8
275
273
276
274
static void serial_debug_init (void )
277
275
{
@@ -334,6 +332,92 @@ void debug_mode(uint8_t mode)
334
332
}
335
333
#endif
336
334
335
+ static union {
336
+ uint32_t dword ;
337
+ struct {
338
+ uint16_t low_word , high_word ;
339
+ };
340
+ } orig_bios_irq0_isr ;
341
+ static uint16_t sample_rate_counter ;
342
+
343
+ static inline void audio_set_sample_rate (const uint16_t sample_rate )
344
+ {
345
+ uint32_t corrected = sample_rate ? (0x1234dc / (uint32_t )sample_rate ) : 0 ;
346
+
347
+ sample_rate_counter = corrected & 0xfffe ;
348
+
349
+ asm __volatile ("cli" );
350
+ outb (0x43 , 0x36 );
351
+ outb (0x40 , sample_rate_counter & 0xff );
352
+ outb (0x40 , sample_rate_counter >> 8 );
353
+ asm __volatile ("sti" );
354
+ }
355
+
356
+ static inline void audio_play_sample (uint8_t sample )
357
+ {
358
+ outb (0x43 , 0xb0 );
359
+ outb (0x42 , sample );
360
+ outb (0x42 , 0 );
361
+ }
362
+
363
+ __attribute__((used )) static void audio_tick (void )
364
+ {
365
+ static uint16_t tick ;
366
+ uint8_t sample = rand () & 255 ;
367
+
368
+ outb (0x43 , 0xb0 );
369
+ outb (0x42 , sample >> 1 );
370
+ outb (0x42 , 0 );
371
+
372
+ uint32_t v = (uint32_t )tick + sample_rate_counter ;
373
+ tick = (uint16_t )v ;
374
+
375
+ if ((uint32_t )tick != v ) {
376
+ asm __volatile ("pushf" );
377
+ void (* far_void_func )(void ) __far =
378
+ (void (* )(void ) __far )orig_bios_irq0_isr .dword ;
379
+ far_void_func ();
380
+ } else {
381
+ outb (0x20 , 0x20 ); /* acknowledge IRQ */
382
+ }
383
+ }
384
+
385
+ extern void audio_tick_isr (void );
386
+ __asm__(".global audio_tick_isr\n"
387
+ "audio_tick_isr:\n"
388
+ "call audio_tick\n"
389
+ "iret\n" );
390
+
391
+ static inline void audio_init (void )
392
+ {
393
+ /* Save original BIOS IRQ0 handler */
394
+ asm __volatile ("int $0x21\n"
395
+ : "=b" (orig_bios_irq0_isr .low_word ),
396
+ "=e" (orig_bios_irq0_isr .high_word )
397
+ : "a" (0x3508 ));
398
+
399
+ /* Replace it with ours */
400
+ asm __volatile ("int $0x21" : : "d" (audio_tick_isr ), "a" (0x2508 ));
401
+
402
+ /* Connect speaker to PIT channel 2 */
403
+ outb (0x61 , inb (0x61 ) | 0x3 );
404
+
405
+ /* Reprogram PIT Channel 0 to fire IRQ0 at 16KHz */
406
+ audio_set_sample_rate (16000 );
407
+ }
408
+
409
+ static inline void audio_shutdown (void )
410
+ {
411
+ audio_set_sample_rate (0 );
412
+
413
+ /* Restore original BIOS IRQ0 routine */
414
+ asm __volatile ("int $0x21\n"
415
+ :
416
+ : "Rds" (orig_bios_irq0_isr .low_word ),
417
+ "d" (orig_bios_irq0_isr .high_word ), "a" (0x2508 ));
418
+
419
+ outb (0x61 , inb (0x61 ) & 0xfc );
420
+ }
337
421
338
422
void platform_init ()
339
423
{
@@ -345,6 +429,8 @@ void platform_init()
345
429
srand (time (NULL ));
346
430
347
431
video_init ();
432
+ audio_init ();
433
+
348
434
draw_scenario ();
349
435
}
350
436
@@ -357,5 +443,6 @@ void platform_shutdown()
357
443
free (mines_xpm [0 ]);
358
444
free (mines_xpm );
359
445
set_mode (VGA_TEXT_MODE );
446
+ audio_shutdown ();
360
447
exit (0 );
361
448
}
0 commit comments