1/* 2 * This code is very much based on the BeOS R4_ sb16 driver, which is: 3 * Copyright (C) 1998 Carlos Hasan. All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 */ 10 11#include "driver.h" 12#include "hardware.h" 13 14#include <drivers/ISA.h> 15 16 17static isa_module_info* gISA; 18 19 20static void 21hw_codec_write_byte(sb16_dev_t* dev, uint8 value) 22{ 23 int i; 24 25 /* wait until the DSP is ready to receive data */ 26 for (i = 0; i < SB16_CODEC_IO_DELAY; i++) { 27 if (!(gISA->read_io_8(dev->port + SB16_CODEC_WRITE_STATUS) & 0x80)) 28 break; 29 } 30 31 /* write a byte to the DSP data port */ 32 gISA->write_io_8(dev->port + SB16_CODEC_WRITE_DATA, value); 33} 34 35 36static int 37hw_codec_read_byte(sb16_dev_t* dev) 38{ 39 int i; 40 /* wait until the DSP has data available */ 41 for (i = 0; i < SB16_CODEC_IO_DELAY; i++) { 42 if (gISA->read_io_8(dev->port + SB16_CODEC_READ_STATUS) & 0x80) 43 break; 44 } 45 46 /* read a byte from the DSP data port */ 47 return gISA->read_io_8(dev->port + SB16_CODEC_READ_DATA); 48} 49 50 51static void 52hw_codec_reg_write(sb16_dev_t* dev, uint8 index, uint8 value) 53{ 54 /* write a Mixer indirect register */ 55 gISA->write_io_8(dev->port + SB16_MIXER_ADDRESS, index); 56 gISA->write_io_8(dev->port + SB16_MIXER_DATA, value); 57} 58 59 60static int 61hw_codec_reg_read(sb16_dev_t* dev, uint8 index) 62{ 63 /* read a Mixer indirect register */ 64 gISA->write_io_8(dev->port + SB16_MIXER_ADDRESS, index); 65 return gISA->read_io_8(dev->port + SB16_MIXER_DATA); 66} 67 68 69static int 70hw_codec_read_version(sb16_dev_t* dev) 71{ 72 int minor, major; 73 74 /* query the DSP hardware version number */ 75 hw_codec_write_byte(dev, SB16_CODEC_VERSION); 76 major = hw_codec_read_byte(dev); 77 minor = hw_codec_read_byte(dev); 78 79 dprintf("%s: SB16 version %d.%d\n", __func__, major, minor); 80 81 return (major << 8) + minor; 82} 83 84 85#if 0 86// TODO for recording support 87 88static void 89hw_codec_read_irq_setup(sb16_dev_t* dev) 90{ 91 /* query the current IRQ line resource */ 92 int mask = hw_codec_reg_read(dev, SB16_IRQ_SETUP); 93 94 dev->irq = 5; 95 96 if (mask & 0x01) 97 dev->irq = 2; 98 if (mask & 0x02) 99 dev->irq = 5; 100 if (mask & 0x04) 101 dev->irq = 7; 102 if (mask & 0x08) 103 dev->irq = 10; 104} 105 106 107static void 108hw_codec_read_dma_setup(sb16_dev_t* dev) 109{ 110 /* query the current DMA channel resources */ 111 int mask = hw_codec_reg_read(dev, SB16_DMA_SETUP); 112 113 dev->dma8 = 1; 114 115 if (mask & 0x01) 116 dev->dma8 = 0; 117 if (mask & 0x02) 118 dev->dma8 = 1; 119 if (mask & 0x08) 120 dev->dma8 = 3; 121 122 dev->dma16 = dev->dma8; 123 if (mask & 0x20) 124 dev->dma16 = 5; 125 if (mask & 0x40) 126 dev->dma16 = 6; 127 if (mask & 0x80) 128 dev->dma16 = 7; 129} 130#endif 131 132 133static void 134hw_codec_write_irq_setup(sb16_dev_t* dev) 135{ 136 /* change programmable IRQ line resource */ 137 int mask = 0x02; 138 139 if (dev->irq == 2) 140 mask = 0x01; 141 if (dev->irq == 5) 142 mask = 0x02; 143 if (dev->irq == 7) 144 mask = 0x04; 145 if (dev->irq == 10) 146 mask = 0x08; 147 148 hw_codec_reg_write(dev, SB16_IRQ_SETUP, mask); 149} 150 151 152static void 153hw_codec_write_dma_setup(sb16_dev_t* dev) 154{ 155 /* change programmable DMA channel resources */ 156 hw_codec_reg_write(dev, SB16_DMA_SETUP, (1 << dev->dma8) | (1 << dev->dma16)); 157} 158 159 160static int32 161hw_codec_inth(void* cookie) 162{ 163 sb16_dev_t* dev = (sb16_dev_t*)cookie; 164 int32 rc = B_UNHANDLED_INTERRUPT; 165 166 /* read the IRQ interrupt status register */ 167 int status = hw_codec_reg_read(dev, SB16_IRQ_STATUS); 168 169 /* check if this hardware raised this interrupt */ 170 if (status & 0x03) { 171 rc = B_HANDLED_INTERRUPT; 172 173 /* acknowledge DMA memory transfers */ 174 if (status & 0x01) 175 gISA->read_io_8(dev->port + SB16_CODEC_ACK_8_BIT); 176 if (status & 0x02) 177 gISA->read_io_8(dev->port + SB16_CODEC_ACK_16_BIT); 178 179 /* acknowledge PIC interrupt signal */ 180 if (dev->irq >= 8) 181 gISA->write_io_8(0xa0, 0x20); 182 183 gISA->write_io_8(0x20, 0x20); 184 185 /* handle buffer finished interrupt */ 186 if (((dev->playback_stream.bits >> 3) & status) != 0) { 187 sb16_stream_buffer_done(&dev->playback_stream); 188 rc = B_INVOKE_SCHEDULER; 189 } 190 if (((dev->record_stream.bits >> 3) & status) != 0) { 191 sb16_stream_buffer_done(&dev->record_stream); 192 rc = B_INVOKE_SCHEDULER; 193 } 194 195 if ((status & 0x04) != 0) { 196 /* MIDI stream done */ 197 rc = B_INVOKE_SCHEDULER; 198 } 199 } 200 201 return rc; 202} 203 204 205static status_t 206hw_codec_reset(sb16_dev_t* dev) 207{ 208 int times, delay; 209 210 /* try to reset the DSP hardware */ 211 for (times = 0; times < 10; times++) { 212 gISA->write_io_8(dev->port + SB16_CODEC_RESET, 1); 213 214 for (delay = 0; delay < SB16_CODEC_RESET_DELAY; delay++) 215 gISA->read_io_8(dev->port + SB16_CODEC_RESET); 216 217 gISA->write_io_8(dev->port + SB16_CODEC_RESET, 0); 218 219 if (hw_codec_read_byte(dev) == 0xaa) 220 return B_OK; 221 } 222 223 return B_IO_ERROR; 224} 225 226 227static status_t 228hw_codec_detect(sb16_dev_t* dev) 229{ 230 status_t rc; 231 232 if ((rc=hw_codec_reset(dev)) == B_OK) { 233 if (hw_codec_read_version(dev) >= 0x400) { 234 hw_codec_write_irq_setup(dev); 235 hw_codec_write_dma_setup(dev); 236 rc = B_OK; 237 } else { 238 rc = B_BAD_VALUE; 239 } 240 } 241 242 return rc; 243} 244 245 246//#pragma mark - 247 248 249status_t 250sb16_stream_setup_buffers(sb16_dev_t* dev, sb16_stream_t* s, const char* desc) 251{ 252 return B_OK; 253} 254 255 256status_t 257sb16_stream_start(sb16_dev_t* dev, sb16_stream_t* s) 258{ 259 return B_OK; 260} 261 262 263status_t 264sb16_stream_stop(sb16_dev_t* dev, sb16_stream_t* s) 265{ 266 return B_OK; 267} 268 269 270void 271sb16_stream_buffer_done(sb16_stream_t* stream) 272{ 273} 274 275 276//#pragma mark - 277 278 279status_t 280sb16_hw_init(sb16_dev_t* dev) 281{ 282 status_t rc; 283 284 /* First of all, grab the ISA module */ 285 if ((rc=get_module(B_ISA_MODULE_NAME, (module_info**)&gISA)) != B_OK) 286 return rc; 287 288 /* Check if the hardware is sensible... */ 289 if ((rc=hw_codec_detect(dev)) == B_OK) { 290 if ((rc=gISA->lock_isa_dma_channel(dev->dma8)) == B_OK && 291 (rc=gISA->lock_isa_dma_channel(dev->dma16)) == B_OK) { 292 rc = install_io_interrupt_handler(dev->irq, hw_codec_inth, dev, 0); 293 } 294 } 295 296 return rc; 297} 298 299 300void 301sb16_hw_stop(sb16_dev_t* dev) 302{ 303} 304 305 306void 307sb16_hw_uninit(sb16_dev_t* dev) 308{ 309 remove_io_interrupt_handler(dev->irq, hw_codec_inth, dev); 310 311 if (gISA != NULL) { 312 gISA->unlock_isa_dma_channel(dev->dma8); 313 314 if (dev->dma8 != dev->dma16) 315 gISA->unlock_isa_dma_channel(dev->dma16); 316 317 put_module(B_ISA_MODULE_NAME); 318 } 319 320} 321 322