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 17 static isa_module_info* gISA; 18 19 20 static void 21 hw_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 36 static int 37 hw_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 51 static void 52 hw_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 60 static int 61 hw_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 69 static int 70 hw_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 88 static void 89 hw_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 107 static void 108 hw_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 133 static void 134 hw_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 152 static void 153 hw_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 160 static int32 161 hw_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 205 static status_t 206 hw_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 227 static status_t 228 hw_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 249 status_t 250 sb16_stream_setup_buffers(sb16_dev_t* dev, sb16_stream_t* s, const char* desc) 251 { 252 return B_OK; 253 } 254 255 256 status_t 257 sb16_stream_start(sb16_dev_t* dev, sb16_stream_t* s) 258 { 259 return B_OK; 260 } 261 262 263 status_t 264 sb16_stream_stop(sb16_dev_t* dev, sb16_stream_t* s) 265 { 266 return B_OK; 267 } 268 269 270 void 271 sb16_stream_buffer_done(sb16_stream_t* stream) 272 { 273 } 274 275 276 //#pragma mark - 277 278 279 status_t 280 sb16_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 300 void 301 sb16_hw_stop(sb16_dev_t* dev) 302 { 303 } 304 305 306 void 307 sb16_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