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
hw_codec_write_byte(sb16_dev_t * dev,uint8 value)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
hw_codec_read_byte(sb16_dev_t * dev)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
hw_codec_reg_write(sb16_dev_t * dev,uint8 index,uint8 value)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
hw_codec_reg_read(sb16_dev_t * dev,uint8 index)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
hw_codec_read_version(sb16_dev_t * dev)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
hw_codec_write_irq_setup(sb16_dev_t * dev)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
hw_codec_write_dma_setup(sb16_dev_t * dev)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
hw_codec_inth(void * cookie)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
hw_codec_reset(sb16_dev_t * dev)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
hw_codec_detect(sb16_dev_t * dev)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
sb16_stream_setup_buffers(sb16_dev_t * dev,sb16_stream_t * s,const char * desc)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
sb16_stream_start(sb16_dev_t * dev,sb16_stream_t * s)257 sb16_stream_start(sb16_dev_t* dev, sb16_stream_t* s)
258 {
259 return B_OK;
260 }
261
262
263 status_t
sb16_stream_stop(sb16_dev_t * dev,sb16_stream_t * s)264 sb16_stream_stop(sb16_dev_t* dev, sb16_stream_t* s)
265 {
266 return B_OK;
267 }
268
269
270 void
sb16_stream_buffer_done(sb16_stream_t * stream)271 sb16_stream_buffer_done(sb16_stream_t* stream)
272 {
273 }
274
275
276 //#pragma mark -
277
278
279 status_t
sb16_hw_init(sb16_dev_t * dev)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
sb16_hw_stop(sb16_dev_t * dev)301 sb16_hw_stop(sb16_dev_t* dev)
302 {
303 }
304
305
306 void
sb16_hw_uninit(sb16_dev_t * dev)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