1 /*
2 * Auich BeOS Driver for Intel Southbridge audio
3 *
4 * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <KernelExport.h>
29 #include <PCI.h>
30 #include <driver_settings.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "auich.h"
35 #include "debug.h"
36 #include "config.h"
37 #include "util.h"
38 #include "io.h"
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include "ac97.h"
42
43 status_t init_hardware(void);
44 status_t init_driver(void);
45 void uninit_driver(void);
46 const char ** publish_devices(void);
47 device_hooks * find_device(const char *);
48 int32 auich_int(void *arg);
49 status_t auich_init(auich_dev * card);
50
51 pci_module_info *pci;
52
53 int32 num_cards;
54 auich_dev cards[NUM_CARDS];
55 int32 num_names;
56 char * names[NUM_CARDS*20+1];
57
58 volatile bool int_thread_exit = false;
59 thread_id int_thread_id = -1;
60
61 extern device_hooks multi_hooks;
62
63 auich_settings current_settings = {
64 48000, // sample rate
65 4096, // buffer frames
66 4, // buffer count
67 false // use thread
68 };
69
70 /* The SIS7012 chipset has SR and PICB registers swapped when compared to Intel */
71 #define GET_REG_PICB(x) (IS_SIS7012(x) ? AUICH_REG_X_SR : AUICH_REG_X_PICB)
72 #define GET_REG_SR(x) (IS_SIS7012(x) ? AUICH_REG_X_PICB : AUICH_REG_X_SR)
73
74 static void
dump_hardware_regs(device_config * config)75 dump_hardware_regs(device_config *config)
76 {
77 LOG(("GLOB_CNT = %#08x\n", auich_reg_read_32(config, AUICH_REG_GLOB_CNT)));
78 LOG(("GLOB_STA = %#08x\n", auich_reg_read_32(config, AUICH_REG_GLOB_STA)));
79 LOG(("PI AUICH_REG_X_BDBAR = %#x\n", auich_reg_read_32(config, AUICH_REG_X_BDBAR + AUICH_REG_PI_BASE)));
80 LOG(("PI AUICH_REG_X_CIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CIV + AUICH_REG_PI_BASE)));
81 LOG(("PI AUICH_REG_X_LVI = %#x\n", auich_reg_read_8(config, AUICH_REG_X_LVI + AUICH_REG_PI_BASE)));
82 LOG(("PI REG_X_SR = %#x\n", auich_reg_read_16(config, AUICH_REG_X_SR + AUICH_REG_PI_BASE)));
83 LOG(("PI REG_X_PICB = %#x\n", auich_reg_read_16(config, AUICH_REG_X_PICB + AUICH_REG_PI_BASE)));
84 LOG(("PI AUICH_REG_X_PIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_PIV + AUICH_REG_PI_BASE)));
85 LOG(("PI AUICH_REG_X_CR = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CR + AUICH_REG_PI_BASE)));
86 LOG(("PO AUICH_REG_X_BDBAR = %#x\n", auich_reg_read_32(config, AUICH_REG_X_BDBAR + AUICH_REG_PO_BASE)));
87 LOG(("PO AUICH_REG_X_CIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CIV + AUICH_REG_PO_BASE)));
88 LOG(("PO AUICH_REG_X_LVI = %#x\n", auich_reg_read_8(config, AUICH_REG_X_LVI + AUICH_REG_PO_BASE)));
89 LOG(("PO REG_X_SR = %#x\n", auich_reg_read_16(config, AUICH_REG_X_SR + AUICH_REG_PO_BASE)));
90 LOG(("PO REG_X_PICB = %#x\n", auich_reg_read_16(config, AUICH_REG_X_PICB + AUICH_REG_PO_BASE)));
91 LOG(("PO AUICH_REG_X_PIV = %#x\n", auich_reg_read_8(config, AUICH_REG_X_PIV + AUICH_REG_PO_BASE)));
92 LOG(("PO AUICH_REG_X_CR = %#x\n", auich_reg_read_8(config, AUICH_REG_X_CR + AUICH_REG_PO_BASE)));
93 }
94
95 /* auich Memory management */
96
97 static auich_mem *
auich_mem_new(auich_dev * card,size_t size)98 auich_mem_new(auich_dev *card, size_t size)
99 {
100 auich_mem *mem;
101
102 if ((mem = malloc(sizeof(*mem))) == NULL)
103 return (NULL);
104
105 mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "auich buffer",
106 true);
107 mem->size = size;
108 if (mem->area < B_OK) {
109 free(mem);
110 return NULL;
111 }
112 return mem;
113 }
114
115
116 static void
auich_mem_delete(auich_mem * mem)117 auich_mem_delete(auich_mem *mem)
118 {
119 if (mem->area > B_OK)
120 delete_area(mem->area);
121 free(mem);
122 }
123
124
125 static void *
auich_mem_alloc(auich_dev * card,size_t size)126 auich_mem_alloc(auich_dev *card, size_t size)
127 {
128 auich_mem *mem;
129
130 mem = auich_mem_new(card, size);
131 if (mem == NULL)
132 return (NULL);
133
134 LIST_INSERT_HEAD(&(card->mems), mem, next);
135
136 return mem;
137 }
138
139
140 static void
auich_mem_free(auich_dev * card,void * ptr)141 auich_mem_free(auich_dev *card, void *ptr)
142 {
143 auich_mem *mem;
144
145 LIST_FOREACH(mem, &card->mems, next) {
146 if (mem->log_base != ptr)
147 continue;
148 LIST_REMOVE(mem, next);
149
150 auich_mem_delete(mem);
151 break;
152 }
153 }
154
155 /* auich stream functions */
156
157 status_t
auich_stream_set_audioparms(auich_stream * stream,uint8 channels,uint8 b16,uint32 sample_rate)158 auich_stream_set_audioparms(auich_stream *stream, uint8 channels,
159 uint8 b16, uint32 sample_rate)
160 {
161 uint8 sample_size, frame_size;
162 LOG(("auich_stream_set_audioparms\n"));
163
164 if ((stream->channels == channels)
165 && (stream->b16 == b16)
166 && (stream->sample_rate == sample_rate))
167 return B_OK;
168
169 if (stream->buffer)
170 auich_mem_free(stream->card, stream->buffer->log_base);
171
172 stream->b16 = b16;
173 stream->sample_rate = sample_rate;
174 stream->channels = channels;
175
176 sample_size = stream->b16 + 1;
177 frame_size = sample_size * stream->channels;
178
179 stream->buffer = auich_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount);
180
181 stream->trigblk = 0; /* This shouldn't be needed */
182 stream->blkmod = stream->bufcount;
183 stream->blksize = stream->bufframes * frame_size;
184
185 return B_OK;
186 }
187
188
189 status_t
auich_stream_commit_parms(auich_stream * stream)190 auich_stream_commit_parms(auich_stream *stream)
191 {
192 uint32 *page;
193 uint32 i;
194 LOG(("auich_stream_commit_parms\n"));
195
196 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, 0);
197 snooze(10000); // 10 ms
198
199 auich_reg_write_8(&stream->card->config,
200 stream->base + AUICH_REG_X_CR, CR_RR);
201 for (i = 10000; i > 0; i--) {
202 if (0 == auich_reg_read_8(&stream->card->config,
203 stream->base + AUICH_REG_X_CR)) {
204 LOG(("channel reset finished, %x, %d\n", stream->base, i));
205 break;
206 }
207 spin(1);
208 }
209
210 if (i == 0)
211 PRINT(("channel reset failed after 10ms\n"));
212
213 page = stream->dmaops_log_base;
214
215 for (i = 0; i < AUICH_DMALIST_MAX; i++) {
216 page[2 * i] = ((uint32)stream->buffer->phy_base)
217 + (i % stream->bufcount) * stream->blksize;
218 page[2 * i + 1] = AUICH_DMAF_IOC | (stream->blksize
219 / (IS_SIS7012(&stream->card->config) ? 1 : 2));
220 }
221
222 // set physical buffer descriptor base address
223 auich_reg_write_32(&stream->card->config, stream->base + AUICH_REG_X_BDBAR,
224 (uint32)stream->dmaops_phy_base);
225
226 if (stream->use & AUICH_USE_RECORD)
227 auich_codec_write(&stream->card->config, AC97_PCM_L_R_ADC_RATE, (uint16)stream->sample_rate);
228 else
229 auich_codec_write(&stream->card->config, AC97_PCM_FRONT_DAC_RATE, (uint16)stream->sample_rate);
230
231 if (stream->use & AUICH_USE_RECORD)
232 LOG(("rate : %d\n", auich_codec_read(&stream->card->config, AC97_PCM_L_R_ADC_RATE)));
233 else
234 LOG(("rate : %d\n", auich_codec_read(&stream->card->config, AC97_PCM_FRONT_DAC_RATE)));
235 return B_OK;
236 }
237
238
239 status_t
auich_stream_get_nth_buffer(auich_stream * stream,uint8 chan,uint8 buf,char ** buffer,size_t * stride)240 auich_stream_get_nth_buffer(auich_stream *stream, uint8 chan, uint8 buf,
241 char** buffer, size_t *stride)
242 {
243 uint8 sample_size, frame_size;
244 LOG(("auich_stream_get_nth_buffer\n"));
245
246 sample_size = stream->b16 + 1;
247 frame_size = sample_size * stream->channels;
248
249 *buffer = (char*)stream->buffer->log_base
250 + (buf * stream->bufframes * frame_size) + chan * sample_size;
251 *stride = frame_size;
252
253 return B_OK;
254 }
255
256
257 static uint8
auich_stream_curaddr(auich_stream * stream)258 auich_stream_curaddr(auich_stream *stream)
259 {
260 uint8 index = auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CIV);
261 TRACE(("stream_curaddr %d\n", index));
262 return index;
263 }
264
265
266 void
auich_stream_start(auich_stream * stream,void (* inth)(void *),void * inthparam)267 auich_stream_start(auich_stream *stream, void (*inth) (void *), void *inthparam)
268 {
269 int32 civ;
270 LOG(("auich_stream_start\n"));
271
272 stream->inth = inth;
273 stream->inthparam = inthparam;
274
275 stream->state |= AUICH_STATE_STARTED;
276
277 civ = auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CIV);
278
279 // step 1: clear status bits
280 auich_reg_write_16(&stream->card->config,
281 stream->base + GET_REG_SR(&stream->card->config),
282 auich_reg_read_16(&stream->card->config, stream->base + GET_REG_SR(&stream->card->config)));
283 auich_reg_read_16(&stream->card->config, stream->base + GET_REG_SR(&stream->card->config));
284 // step 2: prepare buffer transfer
285 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_LVI, (civ + 2) % AUICH_DMALIST_MAX);
286 auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_LVI);
287 // step 3: enable interrupts & busmaster transfer
288 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, CR_RPBM | CR_LVBIE | CR_FEIE | CR_IOCE);
289 auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CR);
290
291 #ifdef DEBUG
292 dump_hardware_regs(&stream->card->config);
293 #endif
294 }
295
296
297 void
auich_stream_halt(auich_stream * stream)298 auich_stream_halt(auich_stream *stream)
299 {
300 LOG(("auich_stream_halt\n"));
301
302 stream->state &= ~AUICH_STATE_STARTED;
303
304 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR,
305 auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CR) & ~CR_RPBM);
306 }
307
308
309 auich_stream *
auich_stream_new(auich_dev * card,uint8 use,uint32 bufframes,uint8 bufcount)310 auich_stream_new(auich_dev *card, uint8 use, uint32 bufframes, uint8 bufcount)
311 {
312 auich_stream *stream;
313 cpu_status status;
314 LOG(("auich_stream_new\n"));
315
316 stream = malloc(sizeof(auich_stream));
317 if (stream == NULL)
318 return (NULL);
319 stream->card = card;
320 stream->use = use;
321 stream->state = !AUICH_STATE_STARTED;
322 stream->b16 = 0;
323 stream->sample_rate = 0;
324 stream->channels = 0;
325 stream->bufframes = bufframes;
326 stream->bufcount = bufcount;
327 stream->inth = NULL;
328 stream->inthparam = NULL;
329 stream->buffer = NULL;
330 stream->blksize = 0;
331 stream->trigblk = 0;
332 stream->blkmod = 0;
333
334 if (use & AUICH_USE_PLAY) {
335 stream->base = AUICH_REG_PO_BASE;
336 stream->sta = STA_POINT;
337 } else {
338 stream->base = AUICH_REG_PI_BASE;
339 stream->sta = STA_PIINT;
340 }
341
342 stream->frames_count = 0;
343 stream->real_time = 0;
344 stream->buffer_cycle = 0;
345 stream->update_needed = false;
346
347 /* allocate memory for our dma ops */
348 stream->dmaops_area = alloc_mem(&stream->dmaops_phy_base, &stream->dmaops_log_base,
349 sizeof(auich_dmalist) * AUICH_DMALIST_MAX, "auich dmaops", false);
350
351 if (stream->dmaops_area < B_OK) {
352 PRINT(("couldn't allocate memory\n"));
353 free(stream);
354 return NULL;
355 }
356
357 status = lock();
358 LIST_INSERT_HEAD((&card->streams), stream, next);
359 unlock(status);
360
361 return stream;
362 }
363
364
365 void
auich_stream_delete(auich_stream * stream)366 auich_stream_delete(auich_stream *stream)
367 {
368 cpu_status status;
369 int32 i;
370 LOG(("auich_stream_delete\n"));
371
372 auich_stream_halt(stream);
373
374 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, 0);
375 snooze(10000); // 10 ms
376
377 auich_reg_write_8(&stream->card->config, stream->base + AUICH_REG_X_CR, CR_RR);
378 for (i = 10000; i>=0; i--) {
379 if (0 == auich_reg_read_8(&stream->card->config, stream->base + AUICH_REG_X_CR)) {
380 LOG(("channel reset finished, %x, %d\n", stream->base, i));
381 break;
382 }
383 spin(1);
384 }
385
386 if (i < 0) {
387 LOG(("channel reset failed after 10ms\n"));
388 }
389
390 auich_reg_write_32(&stream->card->config, stream->base + AUICH_REG_X_BDBAR, 0);
391
392 if (stream->dmaops_area > B_OK)
393 delete_area(stream->dmaops_area);
394
395 if (stream->buffer)
396 auich_mem_free(stream->card, stream->buffer->log_base);
397
398 status = lock();
399 LIST_REMOVE(stream, next);
400 unlock(status);
401
402 free(stream);
403 }
404
405 /* auich interrupt */
406
407 int32
auich_int(void * arg)408 auich_int(void *arg)
409 {
410 auich_dev *card = arg;
411 bool gotone = false;
412 uint8 curblk;
413 auich_stream *stream = NULL;
414 uint32 sta;
415 uint16 sr;
416
417 // TRACE(("auich_int(%p)\n", card));
418
419 sta = auich_reg_read_32(&card->config, AUICH_REG_GLOB_STA) & STA_INTMASK;
420 if (sta & (STA_S0RI | STA_S1RI | STA_S2RI)) {
421 // ignore and clear resume interrupt(s)
422 auich_reg_write_32(&card->config, AUICH_REG_GLOB_STA, sta & (STA_S0RI | STA_S1RI | STA_S2RI));
423 TRACE(("interrupt !! %x\n", sta));
424 gotone = true;
425 sta &= ~(STA_S0RI | STA_S1RI | STA_S2RI);
426 }
427
428 if (sta & card->interrupt_mask) {
429 //TRACE(("interrupt !! %x\n", sta));
430
431 LIST_FOREACH(stream, &card->streams, next)
432 if (sta & stream->sta) {
433 sr = auich_reg_read_16(&card->config,
434 stream->base + GET_REG_SR(&stream->card->config));
435 sr &= SR_MASK;
436
437 if (!sr)
438 continue;
439
440 gotone = true;
441
442 if (sr & SR_BCIS) {
443 curblk = auich_stream_curaddr(stream);
444
445 auich_reg_write_8(&card->config, stream->base + AUICH_REG_X_LVI,
446 (curblk + 2) % AUICH_DMALIST_MAX);
447
448 stream->trigblk = (curblk) % stream->blkmod;
449
450 if (stream->inth)
451 stream->inth(stream->inthparam);
452 } else {
453 TRACE(("interrupt !! sta %x, sr %x\n", sta, sr));
454 }
455
456 auich_reg_write_16(&card->config,
457 stream->base + GET_REG_SR(&stream->card->config), sr);
458 auich_reg_write_32(&card->config, AUICH_REG_GLOB_STA, stream->sta);
459 sta &= ~stream->sta;
460 }
461
462 if (sta != 0) {
463 dprintf("global status not fully handled %" B_PRIx32 "!\n", sta);
464 auich_reg_write_32(&card->config, AUICH_REG_GLOB_STA, sta);
465 }
466 } else if (sta != 0) {
467 dprintf("interrupt masked %" B_PRIx32 ", sta %" B_PRIx32 "\n",
468 card->interrupt_mask, sta);
469 }
470
471 if (gotone)
472 return B_INVOKE_SCHEDULER;
473
474 TRACE(("Got unhandled interrupt\n"));
475 return B_UNHANDLED_INTERRUPT;
476 }
477
478
479 static int32
auich_int_thread(void * data)480 auich_int_thread(void *data)
481 {
482 cpu_status status;
483 while (!int_thread_exit) {
484 status = disable_interrupts();
485 auich_int(data);
486 restore_interrupts(status);
487 snooze(1500);
488 }
489 return 0;
490 }
491
492
493 /* auich driver functions */
494
495 static status_t
map_io_memory(device_config * config)496 map_io_memory(device_config *config)
497 {
498 if ((config->type & TYPE_ICH4) == 0)
499 return B_OK;
500
501 config->area_mmbar = map_mem(&config->log_mmbar, config->mmbar, ICH4_MMBAR_SIZE, "auich mmbar io");
502 if (config->area_mmbar <= B_OK) {
503 LOG(("mapping of mmbar io failed, error = %#x\n",config->area_mmbar));
504 return B_ERROR;
505 }
506 LOG(("mapping of mmbar: area %#x, phys %#x, log %#x\n", config->area_mmbar, config->mmbar, config->log_mmbar));
507
508 config->area_mbbar = map_mem(&config->log_mbbar, config->mbbar, ICH4_MBBAR_SIZE, "auich mbbar io");
509 if (config->area_mbbar <= B_OK) {
510 LOG(("mapping of mbbar io failed, error = %#x\n",config->area_mbbar));
511 delete_area(config->area_mmbar);
512 config->area_mmbar = -1;
513 return B_ERROR;
514 }
515 LOG(("mapping of mbbar: area %#x, phys %#x, log %#x\n", config->area_mbbar, config->mbbar, config->log_mbbar));
516
517 return B_OK;
518 }
519
520
521 static status_t
unmap_io_memory(device_config * config)522 unmap_io_memory(device_config *config)
523 {
524 status_t rv;
525 if ((config->type & TYPE_ICH4) == 0)
526 return B_OK;
527 rv = delete_area(config->area_mmbar);
528 rv |= delete_area(config->area_mbbar);
529 return rv;
530 }
531
532 /* detect presence of our hardware */
533 status_t
init_hardware(void)534 init_hardware(void)
535 {
536 int ix=0;
537 pci_info info;
538 status_t err = ENODEV;
539
540 LOG_CREATE();
541
542 PRINT(("init_hardware()\n"));
543
544 if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci))
545 return ENOSYS;
546
547 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
548 if ((info.vendor_id == INTEL_VENDOR_ID &&
549 (info.device_id == INTEL_82443MX_AC97_DEVICE_ID
550 || info.device_id == INTEL_82801AA_AC97_DEVICE_ID
551 || info.device_id == INTEL_82801AB_AC97_DEVICE_ID
552 || info.device_id == INTEL_82801BA_AC97_DEVICE_ID
553 || info.device_id == INTEL_82801CA_AC97_DEVICE_ID
554 || info.device_id == INTEL_82801DB_AC97_DEVICE_ID
555 || info.device_id == INTEL_82801EB_AC97_DEVICE_ID
556 || info.device_id == INTEL_82801FB_AC97_DEVICE_ID
557 || info.device_id == INTEL_82801GB_AC97_DEVICE_ID
558 || info.device_id == INTEL_6300ESB_AC97_DEVICE_ID
559 || info.device_id == INTEL_631xESB_AC97_DEVICE_ID
560 ))
561 || (info.vendor_id == SIS_VENDOR_ID &&
562 (info.device_id == SIS_SI7012_AC97_DEVICE_ID
563 ))
564 || (info.vendor_id == NVIDIA_VENDOR_ID &&
565 (info.device_id == NVIDIA_nForce_AC97_DEVICE_ID
566 || info.device_id == NVIDIA_nForce2_AC97_DEVICE_ID
567 || info.device_id == NVIDIA_nForce2_400_AC97_DEVICE_ID
568 || info.device_id == NVIDIA_nForce3_AC97_DEVICE_ID
569 || info.device_id == NVIDIA_nForce3_250_AC97_DEVICE_ID
570 || info.device_id == NVIDIA_CK804_AC97_DEVICE_ID
571 || info.device_id == NVIDIA_MCP51_AC97_DEVICE_ID
572 || info.device_id == NVIDIA_MCP04_AC97_DEVICE_ID
573 ))
574 || (info.vendor_id == AMD_VENDOR_ID &&
575 (info.device_id == AMD_AMD8111_AC97_DEVICE_ID
576 || info.device_id == AMD_AMD768_AC97_DEVICE_ID
577 ))
578 )
579 {
580 err = B_OK;
581 }
582 ix++;
583 }
584
585 put_module(B_PCI_MODULE_NAME);
586
587 return err;
588 }
589
590
591 static void
make_device_names(auich_dev * card)592 make_device_names(
593 auich_dev * card)
594 {
595 sprintf(card->name, "audio/hmulti/auich/%ld", card-cards+1);
596 names[num_names++] = card->name;
597
598 names[num_names] = NULL;
599 }
600
601
602 status_t
auich_init(auich_dev * card)603 auich_init(auich_dev * card)
604 {
605 card->interrupt_mask = STA_PIINT | STA_POINT; //STA_INTMASK;
606
607 /* Init streams list */
608 LIST_INIT(&(card->streams));
609
610 /* Init mems list */
611 LIST_INIT(&(card->mems));
612
613 return B_OK;
614 }
615
616
617 static status_t
auich_setup(auich_dev * card)618 auich_setup(auich_dev * card)
619 {
620 status_t err = B_OK;
621 status_t rv;
622 unsigned char cmd;
623 int i;
624
625 PRINT(("auich_setup(%p)\n", card));
626
627 make_device_names(card);
628
629 card->config.subvendor_id = card->info.u.h0.subsystem_vendor_id;
630 card->config.subsystem_id = card->info.u.h0.subsystem_id;
631 card->config.nabmbar = card->info.u.h0.base_registers[0];
632 card->config.irq = card->info.u.h0.interrupt_line;
633 card->config.type = 0;
634 if ((card->info.device_id == INTEL_82801DB_AC97_DEVICE_ID)
635 || (card->info.device_id == INTEL_82801EB_AC97_DEVICE_ID)
636 || (card->info.device_id == INTEL_82801FB_AC97_DEVICE_ID)
637 || (card->info.device_id == INTEL_82801GB_AC97_DEVICE_ID)
638 || (card->info.device_id == INTEL_6300ESB_AC97_DEVICE_ID))
639 card->config.type |= TYPE_ICH4;
640 if (card->info.device_id == SIS_SI7012_AC97_DEVICE_ID)
641 card->config.type |= TYPE_SIS7012;
642
643 PRINT(("%s deviceid = %#04x chiprev = %x model = %x "
644 "enhanced at %" B_PRIx32 "lx\n",
645 card->name, card->info.device_id, card->info.revision,
646 card->info.u.h0.subsystem_id, card->config.nabmbar));
647
648 if (IS_ICH4(&card->config)) {
649 // memory mapped access
650 card->config.mmbar = 0xfffffffe & (*pci->read_pci_config)
651 (card->info.bus, card->info.device, card->info.function, 0x18, 4);
652 card->config.mbbar = 0xfffffffe & (*pci->read_pci_config)
653 (card->info.bus, card->info.device, card->info.function, 0x1C, 4);
654 if (card->config.mmbar == 0 || card->config.mbbar == 0) {
655 PRINT(("memory mapped IO not configured\n"));
656 return B_ERROR;
657 }
658 } else {
659 // pio access
660 card->config.nambar = 0xfffffffe & (*pci->read_pci_config)
661 (card->info.bus, card->info.device, card->info.function, 0x10, 4);
662 card->config.nabmbar = 0xfffffffe & (*pci->read_pci_config)
663 (card->info.bus, card->info.device, card->info.function, 0x14, 4);
664 if (card->config.nambar == 0 || card->config.nabmbar == 0) {
665 PRINT(("IO space not configured\n"));
666 return B_ERROR;
667 }
668 }
669
670 /* before doing anything else, map the IO memory */
671 rv = map_io_memory(&card->config);
672 if (rv != B_OK) {
673 PRINT(("mapping of memory IO space failed\n"));
674 return B_ERROR;
675 }
676
677 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
678 card->info.function, PCI_command, 2);
679 PRINT(("PCI command before: %x\n", cmd));
680 cmd |= PCI_command_master;
681 if (IS_ICH4(&card->config)) {
682 (*pci->write_pci_config)(card->info.bus, card->info.device,
683 card->info.function, PCI_command, 2, cmd | PCI_command_memory);
684 } else {
685 (*pci->write_pci_config)(card->info.bus, card->info.device,
686 card->info.function, PCI_command, 2, cmd | PCI_command_io);
687 }
688 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device,
689 card->info.function, PCI_command, 2);
690 PRINT(("PCI command after: %x\n", cmd));
691
692 /* do a cold reset */
693 LOG(("cold reset\n"));
694 auich_reg_write_32(&card->config, AUICH_REG_GLOB_CNT, 0);
695 snooze(50000); // 50 ms
696 auich_reg_write_32(&card->config, AUICH_REG_GLOB_CNT, CNT_COLD | CNT_PRIE);
697 LOG(("cold reset finished\n"));
698 rv = auich_reg_read_32(&card->config, AUICH_REG_GLOB_CNT);
699 if ((rv & CNT_COLD) == 0) {
700 LOG(("cold reset failed\n"));
701 }
702
703 for (i = 0; i < 500; i++) {
704 rv = auich_reg_read_32(&card->config, AUICH_REG_GLOB_STA);
705 if (rv & STA_S0CR)
706 break;
707 snooze(1000);
708 }
709
710 if (!(rv & STA_S0CR)) { /* reset failure */
711 /* It never return STA_S0CR in some cases */
712 PRINT(("reset failure\n"));
713 }
714
715 /* attach the codec */
716 PRINT(("codec attach\n"));
717 ac97_attach(&card->config.ac97, (codec_reg_read)auich_codec_read,
718 (codec_reg_write)auich_codec_write, &card->config,
719 card->config.subvendor_id, card->config.subsystem_id);
720
721 /* Print capabilities though there are no supports for now */
722 if ((rv & STA_SAMPLE_CAP) == STA_POM20) {
723 LOG(("20 bit precision support\n"));
724 }
725 if ((rv & STA_CHAN_CAP) == STA_PCM4) {
726 LOG(("4ch PCM output support\n"));
727 }
728 if ((rv & STA_CHAN_CAP) == STA_PCM6) {
729 LOG(("6ch PCM output support\n"));
730 }
731
732 if (current_settings.use_thread || card->config.irq == 0
733 || card->config.irq == 0xff) {
734 int_thread_id = spawn_kernel_thread(auich_int_thread,
735 "auich interrupt poller", B_REAL_TIME_PRIORITY, card);
736 resume_thread(int_thread_id);
737 } else {
738 PRINT(("installing interrupt : %" B_PRIx32 "\n", card->config.irq));
739 err = install_io_interrupt_handler(card->config.irq, auich_int,
740 card, 0);
741 if (err != B_OK) {
742 PRINT(("failed to install interrupt\n"));
743 ac97_detach(card->config.ac97);
744 unmap_io_memory(&card->config);
745 return err;
746 }
747 }
748
749 if ((err = auich_init(card)) != B_OK)
750 return err;
751
752 PRINT(("init_driver done\n"));
753
754 return err;
755 }
756
757
758 status_t
init_driver(void)759 init_driver(void)
760 {
761 int ix = 0;
762 void *settings_handle;
763 pci_info info;
764 status_t err;
765 num_cards = 0;
766
767 PRINT(("init_driver()\n"));
768
769 // get driver settings
770 settings_handle = load_driver_settings(AUICH_SETTINGS);
771 if (settings_handle != NULL) {
772 current_settings.use_thread = get_driver_boolean_parameter (settings_handle, "use_thread", false, false);
773 unload_driver_settings (settings_handle);
774 }
775
776 if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci))
777 return ENOSYS;
778
779 while ((*pci->get_nth_pci_info)(ix++, &info) == B_OK) {
780 if ((info.vendor_id == INTEL_VENDOR_ID
781 && (info.device_id == INTEL_82443MX_AC97_DEVICE_ID
782 || info.device_id == INTEL_82801AA_AC97_DEVICE_ID
783 || info.device_id == INTEL_82801AB_AC97_DEVICE_ID
784 || info.device_id == INTEL_82801BA_AC97_DEVICE_ID
785 || info.device_id == INTEL_82801CA_AC97_DEVICE_ID
786 || info.device_id == INTEL_82801DB_AC97_DEVICE_ID
787 || info.device_id == INTEL_82801EB_AC97_DEVICE_ID
788 || info.device_id == INTEL_82801FB_AC97_DEVICE_ID
789 || info.device_id == INTEL_82801GB_AC97_DEVICE_ID
790 || info.device_id == INTEL_6300ESB_AC97_DEVICE_ID
791 ))
792 || (info.vendor_id == SIS_VENDOR_ID
793 && (info.device_id == SIS_SI7012_AC97_DEVICE_ID
794 ))
795 || (info.vendor_id == NVIDIA_VENDOR_ID
796 && (info.device_id == NVIDIA_nForce_AC97_DEVICE_ID
797 || info.device_id == NVIDIA_nForce2_AC97_DEVICE_ID
798 || info.device_id == NVIDIA_nForce2_400_AC97_DEVICE_ID
799 || info.device_id == NVIDIA_nForce3_AC97_DEVICE_ID
800 || info.device_id == NVIDIA_nForce3_250_AC97_DEVICE_ID
801 || info.device_id == NVIDIA_CK804_AC97_DEVICE_ID
802 || info.device_id == NVIDIA_MCP51_AC97_DEVICE_ID
803 || info.device_id == NVIDIA_MCP04_AC97_DEVICE_ID
804 ))
805 || (info.vendor_id == AMD_VENDOR_ID
806 && (info.device_id == AMD_AMD8111_AC97_DEVICE_ID
807 || info.device_id == AMD_AMD768_AC97_DEVICE_ID
808 ))
809 ) {
810 if (num_cards == NUM_CARDS) {
811 PRINT(("Too many auich cards installed!\n"));
812 break;
813 }
814 memset(&cards[num_cards], 0, sizeof(auich_dev));
815 cards[num_cards].info = info;
816 #ifdef __HAIKU__
817 if ((err = (*pci->reserve_device)(info.bus, info.device, info.function,
818 DRIVER_NAME, &cards[num_cards])) < B_OK) {
819 dprintf("%s: failed to reserve_device(%d, %d, %d,): %s\n",
820 DRIVER_NAME, info.bus, info.device, info.function,
821 strerror(err));
822 continue;
823 }
824 #endif
825 if (auich_setup(&cards[num_cards])) {
826 PRINT(("Setup of auich %" B_PRId32 " failed\n",
827 num_cards + 1));
828 #ifdef __HAIKU__
829 (*pci->unreserve_device)(info.bus, info.device, info.function,
830 DRIVER_NAME, &cards[num_cards]);
831 #endif
832 }
833 else {
834 num_cards++;
835 }
836 }
837 }
838 if (!num_cards) {
839 PRINT(("no cards\n"));
840 put_module(B_PCI_MODULE_NAME);
841 PRINT(("no suitable cards found\n"));
842 return ENODEV;
843 }
844
845
846 #if DEBUG
847 //add_debugger_command("auich", auich_debug, "auich [card# (1-n)]");
848 #endif
849 return B_OK;
850 }
851
852
853 static void
auich_shutdown(auich_dev * card)854 auich_shutdown(auich_dev *card)
855 {
856 PRINT(("shutdown(%p)\n", card));
857 ac97_detach(card->config.ac97);
858
859 card->interrupt_mask = 0;
860
861 if (current_settings.use_thread) {
862 status_t exit_value;
863 int_thread_exit = true;
864 wait_for_thread(int_thread_id, &exit_value);
865 } else
866 remove_io_interrupt_handler(card->config.irq, auich_int, card);
867
868 unmap_io_memory(&card->config);
869 }
870
871
872 void
uninit_driver(void)873 uninit_driver(void)
874 {
875 int ix, cnt = num_cards;
876 num_cards = 0;
877
878 PRINT(("uninit_driver()\n"));
879 //remove_debugger_command("auich", auich_debug);
880
881 for (ix=0; ix<cnt; ix++) {
882 auich_shutdown(&cards[ix]);
883 #ifdef __HAIKU__
884 (*pci->unreserve_device)(cards[ix].info.bus,
885 cards[ix].info.device, cards[ix].info.function,
886 DRIVER_NAME, &cards[ix]);
887 #endif
888 }
889 memset(&cards, 0, sizeof(cards));
890 put_module(B_PCI_MODULE_NAME);
891 }
892
893
894 const char **
publish_devices(void)895 publish_devices(void)
896 {
897 int ix = 0;
898 PRINT(("publish_devices()\n"));
899
900 for (ix=0; names[ix]; ix++) {
901 PRINT(("publish %s\n", names[ix]));
902 }
903 return (const char **)names;
904 }
905
906
907 device_hooks *
find_device(const char * name)908 find_device(const char * name)
909 {
910 int ix;
911
912 PRINT(("find_device(%s)\n", name));
913
914 for (ix=0; ix<num_cards; ix++) {
915 if (!strcmp(cards[ix].name, name)) {
916 return &multi_hooks;
917 }
918 }
919 PRINT(("find_device(%s) failed\n", name));
920 return NULL;
921 }
922
923 int32 api_version = B_CUR_DRIVER_API_VERSION;
924