Warning, cross-references for /kernel/drivers/sb16/sound.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include "types.h"
0019 #include "drivers/sb16/sound.h"
0020 #include "kernel.h"
0021 #include "mem/mem.h"
0022 #include "fs/filesys.h"
0023 #include "smp/smp.h"
0024 #include "smp/apic.h"
0025 #include "util/printf.h"
0026
0027 PRIVATE uint16 dsp_version;
0028
0029
0030 PRIVATE SB_CAPABILITY driver_capability;
0031
0032 PRIVATE uint16 dsp_base_address = 0x220;
0033 PRIVATE uint8 dsp_irq_number = 5;
0034 PRIVATE uint8 dsp_dma_channel_8 = 1;
0035 PRIVATE uint8 dsp_dma_channel_16 = 5;
0036
0037 #ifdef __8_BIT__
0038
0039 PRIVATE uint8 driver_dma_page[4] = { 0x87, 0x83, 0x81, 0x82 };
0040 PRIVATE uint8 driver_dma_length[4] = { 0x01, 0x03, 0x05, 0x07 };
0041 PRIVATE uint8 driver_dma_address[4] = { 0x00, 0x02, 0x04, 0x06 };
0042 #endif
0043
0044
0045 PRIVATE uint8 driver_dma_page[4] = { 0x8F, 0x8B, 0x89, 0x8A };
0046 PRIVATE uint8 driver_dma_length[4] = { 0xC2, 0xC6, 0xCA, 0xCE };
0047 PRIVATE uint8 driver_dma_address[4] = { 0xC0, 0xC4, 0xC8, 0xCC };
0048
0049
0050 static uint32 dma_buffer_virt_base;
0051
0052 uint32 dma_buffer_phys_base;
0053
0054 static int filesize;
0055 static char filebuffer[0x10000];
0056
0057 bool
0058 sb_dsp_reset (uint16 base_address)
0059 {
0060 int i, timeout;
0061
0062
0063
0064 outb (1, base_address + SB_DSP_RESET);
0065
0066
0067 for (i = 0; i < 6; i++)
0068 inb (base_address + SB_DSP_WRITE_BUFFER_STATUS);
0069
0070
0071 outb (0, base_address + SB_DSP_RESET);
0072
0073 timeout = 1000;
0074
0075
0076 while (timeout > 0 && (inb (base_address + SB_DSP_READ_BUFFER_STATUS) < 0x80))
0077 timeout--;
0078
0079 if (timeout <= 0)
0080 return SB_RESET_DSP;
0081
0082 timeout = 1000;
0083
0084
0085 while (timeout > 0 && ((i = inb (base_address + SB_DSP_READ_DATA)) != 0xAA))
0086 timeout--;
0087
0088 if (i != 0xAA)
0089 return (SB_RESET_DSP);
0090 return (SB_OK);
0091 }
0092
0093
0094 bool
0095 sb_dsp_detect_base_address (uint16 * base_address)
0096 {
0097
0098 uint16 address;
0099
0100 for (address = 0x220; address <= 0x280; address += 0x020)
0101 if (!sb_dsp_reset (address)) {
0102 *base_address = address;
0103 dsp_base_address = address;
0104 return (SB_OK);
0105 }
0106
0107 return (SB_DETECT_DSP);
0108 }
0109
0110
0111 bool
0112 sb_dsp_detect_irq_number (uint16 base_address, uint8 * irq_number)
0113 {
0114
0115 uint8 b;
0116
0117 outb (INTERRUPT_SETUP, base_address + MIXER_REG_ADDR_PORT);
0118 b = inb (base_address + MIXER_DATA_PORT);
0119
0120 switch (b) {
0121 case 1:
0122 dsp_irq_number = 2;
0123 break;
0124 case 2:
0125 dsp_irq_number = 5;
0126 break;
0127 case 4:
0128 dsp_irq_number = 7;
0129 break;
0130 case 8:
0131 dsp_irq_number = 10;
0132 break;
0133 default:
0134 dsp_irq_number = 0;
0135 }
0136
0137 if ((*irq_number = dsp_irq_number))
0138 return (SB_OK);
0139 else
0140 return (SB_INVALID_IRQ);
0141 }
0142
0143
0144 bool
0145 sb_dsp_detect_dma (uint16 base_address, uint8 * dma8, uint8 * dma16)
0146 {
0147
0148 uint8 b;
0149
0150 outb (DMA_SETUP, base_address + MIXER_REG_ADDR_PORT);
0151 b = inb (base_address + MIXER_DATA_PORT);
0152
0153 *dma8 = b & 0x08 ? 3 : b & 0x02 ? 1 : 0;
0154 *dma16 = b >> 7 ? 7 : b >> 6 ? 6 : 5;
0155
0156 if (*dma8 && *dma16)
0157 return (SB_OK);
0158 else
0159 return (SB_INVALID_DMA);
0160 }
0161
0162
0163
0164 bool
0165 sb_dsp_write (uint8 value)
0166 {
0167
0168 if (!dsp_base_address)
0169 return (SB_NOT_INITIALIZED);
0170
0171
0172 while (inb (dsp_base_address + SB_DSP_WRITE_BUFFER_STATUS) & 0x80);
0173
0174
0175 outb (value, dsp_base_address + SB_DSP_WRITE);
0176 return (SB_OK);
0177 }
0178
0179
0180 bool
0181 sb_dsp_read (uint8 * value)
0182 {
0183
0184 if (!dsp_base_address)
0185 return (SB_NOT_INITIALIZED);
0186
0187
0188 while (inb (dsp_base_address + SB_DSP_READ_BUFFER_STATUS) < 0x80);
0189
0190
0191 *value = inb (dsp_base_address + SB_DSP_READ_DATA);
0192 return (SB_OK);
0193 }
0194
0195
0196 bool
0197 sb_speaker_on (void)
0198 {
0199
0200 return (sb_dsp_write (SB_SPEAKER_ON));
0201 }
0202
0203 bool
0204 sb_speaker_off (void)
0205 {
0206
0207 return (sb_dsp_write (SB_SPEAKER_OFF));
0208 }
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 bool
0219 sb_dsp_get_version (uint16 * version)
0220 {
0221 uint8 value;
0222 bool result;
0223
0224 if ((result = sb_dsp_write (SB_DSP_VERSION)))
0225 return (result);
0226
0227 if ((result = sb_dsp_read (&value)))
0228 return (result);
0229
0230 dsp_version = (uint16) value << 8;
0231 if ((result = sb_dsp_read (&value)))
0232 return (result);
0233 dsp_version += value;
0234 *version = dsp_version;
0235
0236 if (dsp_version >= 0x040C)
0237 driver_capability = capability_sb_awe32;
0238 else if (dsp_version >= 0x0400)
0239 driver_capability = capability_sb_16;
0240 else if (dsp_version >= 0x0300)
0241 driver_capability = capability_sb_pro;
0242 else if (dsp_version >= 0x0201)
0243 driver_capability = capability_sb_20;
0244 else
0245 driver_capability = capability_sb_10;
0246 return (SB_OK);
0247 }
0248
0249
0250 PRIVATE bool
0251 driver_set_time_constant (uint16 frequency)
0252 {
0253
0254
0255 sb_mixer_register_set (MIXER_RESET, 0);
0256
0257
0258 sb_mixer_register_set (MIXER_OUTPUT, 0x13);
0259
0260
0261
0262 sb_dsp_write (0x41);
0263 sb_dsp_write (frequency >> 8);
0264 sb_dsp_write (frequency & 0xFF);
0265
0266 return (SB_OK);
0267 }
0268
0269
0270 PRIVATE void
0271 driver_setup_dma_transfer (int memory_size)
0272 {
0273
0274
0275 outb (0x04 + dsp_dma_channel_8, SB_DMA_MASK_16);
0276
0277
0278 outb (0, SB_DMA_CLEAR_16);
0279
0280
0281 outb (0x48 + dsp_dma_channel_8, SB_DMA_MODE_16);
0282
0283
0284 outb ((dma_buffer_phys_base >> 16) & 0xFF,
0285 driver_dma_page[dsp_dma_channel_8]);
0286 outb (0 ,
0287 driver_dma_address[dsp_dma_channel_8]);
0288 outb (0 ,
0289 driver_dma_address[dsp_dma_channel_8]);
0290 outb ((memory_size - 1) & 0xFF ,
0291 driver_dma_length[dsp_dma_channel_8]);
0292 outb ((memory_size - 1) >> 8 ,
0293 driver_dma_length[dsp_dma_channel_8]);
0294
0295
0296 outb (0x00 + dsp_dma_channel_8, SB_DMA_MASK_16);
0297 }
0298
0299 PRIVATE void
0300 driver_setup_dsp_transfer (int memory_size)
0301 {
0302
0303 memory_size >>= 1;
0304
0305
0306 sb_dsp_write (0xB0);
0307 sb_dsp_write (0x00);
0308 sb_dsp_write ((memory_size - 1) & 0xFF);
0309 sb_dsp_write ((memory_size - 1) >> 8);
0310 }
0311
0312
0313
0314 bool
0315 sb_mixer_register_set (uint8 index, uint8 value)
0316 {
0317 if (!dsp_base_address)
0318 return (SB_NOT_INITIALIZED);
0319
0320
0321 outb (index, dsp_base_address + MIXER_REG_ADDR_PORT);
0322
0323
0324 outb (value, dsp_base_address + MIXER_DATA_PORT);
0325 return (SB_OK);
0326 }
0327
0328
0329
0330 bool
0331 sb_mixer_register_get (uint8 index, uint8 * value)
0332 {
0333 if (!dsp_base_address)
0334 return (SB_NOT_INITIALIZED);
0335
0336
0337 outb (index, dsp_base_address + MIXER_REG_ADDR_PORT);
0338
0339
0340 *value = inb (dsp_base_address + MIXER_DATA_PORT);
0341 return (SB_OK);
0342 }
0343
0344
0345 static void
0346 play_sample (void)
0347 {
0348
0349 static int fileoffset;
0350 int chunksize;
0351
0352 if (!filesize)
0353
0354 return;
0355
0356 chunksize = filesize > SB_MEMORY_SIZE ? SB_MEMORY_SIZE : filesize;
0357
0358 memcpy ((void *) dma_buffer_virt_base, filebuffer + fileoffset, chunksize);
0359 fileoffset += chunksize;
0360
0361
0362 driver_setup_dma_transfer (chunksize);
0363 driver_setup_dsp_transfer (chunksize);
0364
0365 filesize -= chunksize;
0366 }
0367
0368
0369
0370
0371 void
0372 _soundcard (void)
0373 {
0374
0375 inb (dsp_base_address + SB_IRQ_ACK_16);
0376
0377 play_sample ();
0378
0379
0380
0381
0382
0383
0384
0385 send_eoi ();
0386 }
0387
0388
0389
0390
0391
0392 bool
0393 sb_install_driver (uint16 frequency, bool use_stereo)
0394 {
0395 bool result;
0396
0397 if ((result = driver_set_time_constant (frequency)))
0398 return (result);
0399
0400 play_sample ();
0401
0402 return (SB_OK);
0403 }
0404
0405
0406 bool
0407 sb_read_raw (char *pathname)
0408 {
0409
0410 filesize = vfs_dir (pathname);
0411
0412 vfs_read (pathname, filebuffer, filesize);
0413
0414 return (SB_OK);
0415 }
0416
0417
0418 bool
0419 sb16_init (void)
0420 {
0421
0422 int i;
0423
0424
0425
0426
0427
0428 for (i = 0; i < 0x80; i++)
0429 if ((mm_table[i] & 0xFFFF) == 0xFFFF) {
0430
0431 mm_table[i] &= 0xFFFF0000;
0432 dma_buffer_phys_base = i << 17;
0433 break;
0434 } else if ((mm_table[i] & 0xFFFF0000) == 0xFFFF0000) {
0435
0436 mm_table[i] &= 0xFFFF;
0437 dma_buffer_phys_base = (i << 17) | 0x10000;
0438 break;
0439 }
0440
0441 if (i >= 0x80)
0442 panic ("No suitable DMA buffer found");
0443
0444 sb_read_raw ("/boot/welcome.raw");
0445
0446
0447 dma_buffer_virt_base = (uint32) map_virtual_page (dma_buffer_phys_base | 3);
0448 if (sb_dsp_detect_base_address (&dsp_base_address) != SB_OK)
0449 goto fail;
0450 sb_dsp_detect_irq_number (dsp_base_address, &dsp_irq_number);
0451 sb_dsp_detect_dma (dsp_base_address,
0452 &dsp_dma_channel_8, &dsp_dma_channel_16);
0453 sb_dsp_get_version (&dsp_version);
0454 sb_speaker_on ();
0455 sb_install_driver (11025, FALSE);
0456 com1_printf ("SB16 initialized.\n");
0457 return TRUE;
0458
0459 fail:
0460 com1_printf ("SB16 not detected.\n");
0461 unmap_virtual_page ((void *)dma_buffer_virt_base);
0462 free_phys_frames (dma_buffer_phys_base, 0x10);
0463 return FALSE;
0464 }
0465
0466
0467
0468 #include "module/header.h"
0469
0470 static const struct module_ops mod_ops = {
0471 .init = sb16_init
0472 };
0473
0474 DEF_MODULE (sound___sb16, "Sound Blaster 16 driver", &mod_ops, {"vfs"});
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485