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