xref: /haiku/src/add-ons/kernel/drivers/audio/cmedia/cm.c (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 /*
2 	Copyright 1999, Be Incorporated.   All Rights Reserved.
3 	This file may be used under the terms of the Be Sample Code License.
4 */
5 
6 #include "cmedia_pci.h"
7 #include "cm_private.h"
8 
9 #include <string.h>
10 #include <stdio.h>
11 
12 #if !defined(_KERNEL_EXPORT_H)
13 #include <KernelExport.h>
14 #endif
15 
16 
17 #if DEBUG
18 #define KPRINTF(x) kprintf x
19 #else
20 #define KPRINTF(x)
21 #endif
22 
23 EXPORT status_t init_hardware(void);
24 EXPORT status_t init_driver(void);
25 EXPORT void uninit_driver(void);
26 EXPORT const char ** publish_devices(void);
27 EXPORT device_hooks * find_device(const char *);
28 
29 
30 static char pci_name[] = B_PCI_MODULE_NAME;
31 static pci_module_info	*pci;
32 static char gameport_name[] = "generic/gameport/v1";
33 generic_gameport_module * gameport;
34 static char mpu401_name[] = B_MPU_401_MODULE_NAME;
35 generic_mpu401_module * mpu401;
36 
37 #define DO_JOY 1
38 #define DO_MIDI 1
39 #define DO_PCM 1
40 #define DO_MUX 0
41 #define DO_MIXER 0
42 
43 #if DO_MIDI
44 extern device_hooks midi_hooks;
45 #endif /* DO_MIDI */
46 #if DO_JOY
47 extern device_hooks joy_hooks;
48 #endif /* DO_JOY */
49 #if DO_PCM
50 extern device_hooks pcm_hooks;
51 #endif /* DO_PCM */
52 #if DO_MUX
53 extern device_hooks mux_hooks;
54 #endif /* DO_MUX */
55 #if DO_MIXER
56 extern device_hooks mixer_hooks;
57 #endif /* DO_MIXER */
58 
59 
60 int32 num_cards;
61 cmedia_pci_dev cards[NUM_CARDS];
62 int num_names;
63 char * names[NUM_CARDS * 7 + 1];
64 /* vuchar *io_base; */
65 
66 
67 /* ----------
68 	PCI_IO_RD - read a byte from pci i/o space
69 ----- */
70 
71 uint8
72 PCI_IO_RD (int offset)
73 {
74 	return (*pci->read_io_8) (offset);
75 }
76 
77 
78 /* ----------
79 	PCI_IO_RD_32 - read a 32 bit value from pci i/o space
80 ----- */
81 
82 uint32
83 PCI_IO_RD_32 (int offset)
84 {
85 	return (*pci->read_io_32) (offset);
86 }
87 /* ----------
88 	PCI_IO_WR - write a byte to pci i/o space
89 ----- */
90 
91 void
92 PCI_IO_WR (int offset, uint8 val)
93 {
94 	(*pci->write_io_8) (offset, val);
95 }
96 
97 
98 /* detect presence of our hardware */
99 status_t
100 init_hardware(void)
101 {
102 	int ix=0;
103 	pci_info info;
104 	status_t err = ENODEV;
105 
106 	ddprintf(("cmedia_pci: init_hardware()\n"));
107 
108 	if (get_module(pci_name, (module_info **)&pci))
109 		return ENOSYS;
110 
111 	while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
112 		if (info.vendor_id == CMEDIA_PCI_VENDOR_ID &&
113 			(info.device_id == CMEDIA_8338A_DEVICE_ID ||
114 			 info.device_id == CMEDIA_8338B_DEVICE_ID ||
115 			 info.device_id == CMEDIA_8738A_DEVICE_ID ||
116 			 info.device_id == CMEDIA_8738B_DEVICE_ID )) {
117 			err = B_OK;
118 		}
119 		ix++;
120 	}
121 #if defined(__POWERPC__) && 0
122 	{
123 		char		area_name [32];
124 		area_info	area;
125 		area_id		id;
126 
127 		sprintf (area_name, "pci_bus%d_isa_io", info.bus);
128 		id = find_area (area_name);
129 		if (id < 0)
130 			err = id;
131 		else if ((err = get_area_info (id, &area)) == B_OK)
132 			io_base = area.address;
133 	}
134 #endif
135 
136 	put_module(pci_name);
137 
138 	return err;
139 }
140 
141 
142 void set_direct(cmedia_pci_dev * card, int regno, uchar value, uchar mask)
143 {
144 	if (mask == 0) {
145 		return;
146 	}
147 	if (mask != 0xff) {
148 		uchar old = PCI_IO_RD(card->enhanced+regno);
149 		value = (value&mask)|(old&~mask);
150 	}
151 	PCI_IO_WR(card->enhanced+regno, value);
152 	ddprintf(("cmedia_pci: CM%02x  = %02x\n", regno, value));
153 }
154 
155 
156 uchar get_direct(cmedia_pci_dev * card, int regno)
157 {
158 	uchar ret = PCI_IO_RD(card->enhanced+regno);
159 	return ret;
160 }
161 
162 
163 
164 void set_indirect(cmedia_pci_dev * card, int regno, uchar value, uchar mask)
165 {
166 	PCI_IO_WR(card->enhanced+0x23, regno);
167 	EIEIO();
168 	if (mask == 0) {
169 		return;
170 	}
171 	if (mask != 0xff) {
172 		uchar old = PCI_IO_RD(card->enhanced+0x22);
173 		value = (value&mask)|(old&~mask);
174 	}
175 	PCI_IO_WR(card->enhanced+0x22, value);
176 	EIEIO();
177 	ddprintf(("cmedia_pci: CMX%02x = %02x\n", regno, value));
178 }
179 
180 
181 
182 uchar get_indirect(cmedia_pci_dev * card,int regno)
183 {
184 	uchar ret;
185 	PCI_IO_WR(card->enhanced+0x23, regno);
186 	EIEIO();
187 	ret = PCI_IO_RD(card->enhanced+0x22);
188 	return ret;
189 }
190 
191 
192 #if 0
193 void dump_card(cmedia_pci_dev * card)
194 {
195 	int ix;
196 	dprintf("\n");
197 	dprintf("CM:   ");
198 	for (ix=0; ix<6; ix++) {
199 		if (ix == 2 || ix == 3) dprintf("   ");
200 		else dprintf(" %02x", get_direct(card, ix));
201 	}
202 	for (ix=0; ix<0x32; ix++) {
203 		if (!(ix & 7)) {
204 			dprintf("\nCMX%02x:", ix);
205 		}
206 		dprintf(" %02x", get_indirect(card, ix));
207 	}
208 	dprintf("\n");
209 	dprintf("\n");
210 }
211 #else
212 void dump_card(cmedia_pci_dev * card)
213 {
214 }
215 #endif
216 
217 
218 static void
219 disable_card_interrupts(cmedia_pci_dev * card)
220 {
221 	set_direct(card, 0x0e, 0x00, 0x03);
222 }
223 
224 
225 static status_t
226 setup_dma(cmedia_pci_dev * card)
227 {
228 	/* we're appropriating some ISA space here... */
229 	/* need kernel support to do it right */
230 	const uint16 base = card->enhanced + 0x80;
231 	ddprintf(("cmedia_pci: dma base is 0x%04x\n", base));
232 	if (base == 0)
233 		return B_DEV_RESOURCE_CONFLICT;
234 	card->dma_base = base;
235 	return B_OK;
236 }
237 
238 
239 static void
240 set_default_registers(cmedia_pci_dev * card)
241 {
242 	static uchar values[] = {
243 #ifdef DO_JOY
244 		0x04, 0x02, 0x02,	/* enable joystick */
245 #endif
246 
247 		0x0a, 0x01, 0x01,	/* enable SPDIF inverse before SPDIF_LOOP */
248 		0x04, 0x80, 0x80,	/* enable SPDIF_LOOP */
249 
250 		0x1a, 0x00, 0x20,	/* SPD32SEL disable */
251 		0x1a, 0x00, 0x10,	/* SPDFLOOPI disable */
252 
253 		0x1b, 0x04, 0x04,	/* dual channel mode enable */
254 		0x1a, 0x00, 0x80,	/* Double DAC structure disable */
255 
256 		0x24, 0x00, 0x02,	/* 3D surround disable */
257 
258 		0x24, 0x00, 0x01,	/* disable SPDIF_IN PCM to DAC */
259 #ifdef DO_MIDI
260 		0x04, 0x04, 0x04,	/* enable MPU-401 */
261 		0x17, 0x00, 0x60,	/* default at 0x330 */
262 #endif
263 	};
264 	uchar * ptr = values;
265 
266 	while (ptr < values+sizeof(values)) {
267 		set_direct(card, ptr[0], ptr[1], ptr[2]);
268 		ptr += 3;
269 	}
270 }
271 
272 
273 static void
274 make_device_names(cmedia_pci_dev * card)
275 {
276 	char * name = card->name;
277 	sprintf(name, "cmedia_pci/%ld", card-cards + 1);
278 
279 #if DO_MIDI
280 	sprintf(card->midi.name, "midi/%s", name);
281 	names[num_names++] = card->midi.name;
282 #endif /* DO_MIDI */
283 #if DO_JOY
284 	sprintf(card->joy.name1, "joystick/%s", name);
285 	names[num_names++] = card->joy.name1;
286 #endif /* DO_JOY */
287 #if DO_PCM
288 	/* cmedia_pci DMA doesn't work when physical NULL isn't NULL from PCI */
289 	/* this is a hack to not export bad devices on BeBox hardware */
290 	if ((*pci->ram_address)(NULL) == NULL) {
291 		sprintf(card->pcm.name, "audio/raw/%s", name);
292 		names[num_names++] = card->pcm.name;
293 		sprintf(card->pcm.oldname, "audio/old/%s", name);
294 		names[num_names++] = card->pcm.oldname;
295 	}
296 #endif /* DO_PCM */
297 #if DO_MUX
298 	sprintf(card->mux.name, "audio/mux/%s", name);
299 	names[num_names++] = card->mux.name;
300 #endif /* DO_MUX */
301 #if DO_MIXER
302 	sprintf(card->mixer.name, "audio/mix/%s", name);
303 	names[num_names++] = card->mixer.name;
304 #endif /* DO_MIXER */
305 	names[num_names] = NULL;
306 }
307 
308 
309 /* We use the SV chip in ISA DMA addressing mode, which is 24 bits */
310 /* so we need to find suitable, locked, contiguous memory in that */
311 /* physical address range. */
312 
313 static status_t
314 find_low_memory(cmedia_pci_dev * card)
315 {
316 	size_t low_size = (MIN_MEMORY_SIZE + (B_PAGE_SIZE - 1))
317 		&~ (B_PAGE_SIZE - 1);
318 	physical_entry where;
319 	size_t trysize;
320 	area_id curarea;
321 	void * addr;
322 	char name[DEVNAME];
323 
324 	sprintf(name, "%s_low", card->name);
325 	if (low_size < MIN_MEMORY_SIZE) {
326 		low_size = MIN_MEMORY_SIZE;
327 	}
328 	trysize = low_size;
329 
330 	curarea = find_area(name);
331 	if (curarea >= 0) {	/* area there from previous run */
332 		area_info ainfo;
333 		ddprintf(("cmedia_pci: testing likely candidate...\n"));
334 		if (get_area_info(curarea, &ainfo)) {
335 			ddprintf(("cmedia_pci: no info\n"));
336 			goto allocate;
337 		}
338 		/* test area we found */
339 		trysize = ainfo.size;
340 		addr = ainfo.address;
341 		if (trysize < low_size) {
342 			ddprintf(("cmedia_pci: too small (%lx)\n", trysize));
343 			goto allocate;
344 		}
345 		if (get_memory_map(addr, trysize, &where, 1) < B_OK) {
346 			ddprintf(("cmedia_pci: no memory map\n"));
347 			goto allocate;
348 		}
349 		if ((where.address & ~(phys_addr_t)0xffffff) != 0) {
350 			ddprintf(("cmedia_pci: bad physical address\n"));
351 			goto allocate;
352 		}
353 		if (ainfo.lock < B_FULL_LOCK || where.size < low_size) {
354 			ddprintf(("cmedia_pci: lock not contiguous\n"));
355 			goto allocate;
356 		}
357 dprintf("cmedia_pci: physical %#" B_PRIxPHYSADDR "  logical %p\n",
358 where.address, ainfo.address);
359 		goto a_o_k;
360 	}
361 
362 allocate:
363 	if (curarea >= 0) {
364 		delete_area(curarea); /* area didn't work */
365 		curarea = -1;
366 	}
367 	ddprintf(("cmedia_pci: allocating new low area\n"));
368 
369 	curarea = create_area(name, &addr, B_ANY_KERNEL_ADDRESS,
370 		trysize, B_LOMEM, B_READ_AREA | B_WRITE_AREA);
371 	ddprintf(("cmedia_pci: create_area(%lx) returned %lx logical %p\n",
372 		trysize, curarea, addr));
373 	if (curarea < 0) {
374 		goto oops;
375 	}
376 	if (get_memory_map(addr, low_size, &where, 1) < 0) {
377 		delete_area(curarea);
378 		curarea = B_ERROR;
379 		goto oops;
380 	}
381 	ddprintf(("cmedia_pci: physical %p\n", where.address));
382 	if ((where.address & ~(phys_addr_t)0xffffff) != 0) {
383 		delete_area(curarea);
384 		curarea = B_ERROR;
385 		goto oops;
386 	}
387 	if (((where.address + low_size) & ~(phys_addr_t)0xffffff) != 0) {
388 		delete_area(curarea);
389 		curarea = B_ERROR;
390 		goto oops;
391 	}
392 	/* hey, it worked! */
393 	if (trysize > low_size) {	/* don't waste */
394 		resize_area(curarea, low_size);
395 	}
396 
397 oops:
398 	if (curarea < 0) {
399 		dprintf("cmedia_pci: failed to create low_mem area\n");
400 		return curarea;
401 	}
402 a_o_k:
403 	ddprintf(("cmedia_pci: successfully found or created low area!\n"));
404 	card->low_size = low_size;
405 	card->low_mem = addr;
406 	card->low_phys = (vuchar *)(addr_t)where.address;
407 	card->map_low = curarea;
408 	return B_OK;
409 }
410 
411 
412 static status_t
413 setup_cmedia_pci(cmedia_pci_dev * card)
414 {
415 	status_t err = B_OK;
416 /*	cpu_status cp; */
417 
418 	ddprintf(("cmedia_pci: setup_cmedia_pci(%p)\n", card));
419 
420 	if ((card->pcm.init_sem = create_sem(1, "cm pcm init")) < B_OK)
421 		goto bail;
422 #if 1
423 	if ((*mpu401->create_device)(0x330, &card->midi.driver,
424 #else
425 	if ((*mpu401->create_device)(card->info.u.h0.base_registers[3], &card->midi.driver,
426 #endif
427 		0, midi_interrupt_op, &card->midi) < B_OK)
428 		goto bail3;
429 #if 1
430 	if ((*gameport->create_device)(0x201, &card->joy.driver) < B_OK)
431 #else
432 	if ((*gameport->create_device)(card->info.u.h0.base_registers[4], &card->joy.driver) < B_OK)
433 #endif
434 		goto bail4;
435 	ddprintf(("midi %p  gameport %p\n", card->midi.driver, card->joy.driver));
436 	card->midi.card = card;
437 
438 	err = find_low_memory(card);
439 	if (err < B_OK) {
440 		goto bail5;
441 	}
442 
443 	//cp = disable_interrupts();
444 	//acquire_spinlock(&card->hardware);
445 
446 	make_device_names(card);
447 	card->enhanced = card->info.u.h0.base_registers[0];
448 	ddprintf(("cmedia_pci: %s enhanced at %x\n", card->name, card->enhanced));
449 
450 	ddprintf(("cmedia_pci: revision %x\n", get_indirect(card, 0x15)));
451 
452 	disable_card_interrupts(card);
453 	if (setup_dma(card) != B_OK) {
454 		dprintf("cmedia pci: can't setup DMA\n");
455 		goto bail6;
456 	}
457 
458 	set_default_registers(card);
459 
460 	//release_spinlock(&card->hardware);
461 	//restore_interrupts(cp);
462 
463 	return B_OK;
464 
465 bail6:
466 	//	deallocate low memory
467 bail5:
468 	(*gameport->delete_device)(card->joy.driver);
469 bail4:
470 	(*mpu401->delete_device)(card->midi.driver);
471 bail3:
472 	delete_sem(card->pcm.init_sem);
473 bail:
474 	return err < B_OK ? err : B_ERROR;
475 }
476 
477 
478 static int
479 debug_cmedia(int argc, char * argv[])
480 {
481 	int ix = 0;
482 	if (argc == 2) {
483 		ix = parse_expression(argv[1]) - 1;
484 	}
485 	if (argc > 2 || ix < 0 || ix >= num_cards) {
486 		dprintf("cmedia_pci: dude, you gotta watch your syntax!\n");
487 		return -1;
488 	}
489 	dprintf("%s: enhanced registers at 0x%x\n", cards[ix].name,
490 		cards[ix].enhanced);
491 	dprintf("%s: open %ld   dma_a at 0x%x   dma_c 0x%x\n", cards[ix].pcm.name,
492 		cards[ix].pcm.open_count, cards[ix].pcm.dma_a, cards[ix].pcm.dma_c);
493 	if (cards[ix].pcm.open_count) {
494 		dprintf("    dma_a: 0x%lx+0x%lx   dma_c: 0x%lx+0x%lx\n",
495 			PCI_IO_RD_32((int)cards[ix].pcm.dma_a), PCI_IO_RD_32((int)cards[ix].pcm.dma_a+4),
496 			PCI_IO_RD_32((int)cards[ix].pcm.dma_c), PCI_IO_RD_32((int)cards[ix].pcm.dma_c+4));
497 	}
498 	return 0;
499 }
500 
501 
502 status_t
503 init_driver(void)
504 {
505 	pci_info info;
506 	int ix = 0;
507 	status_t err;
508 
509 	num_cards = 0;
510 
511 	ddprintf(("cmedia_pci: init_driver()\n"));
512 
513 	if (get_module(pci_name, (module_info **)&pci))
514 		return ENOSYS;
515 
516 	if (get_module(gameport_name, (module_info **)&gameport)) {
517 		put_module(pci_name);
518 		return ENOSYS;
519 	}
520 	ddprintf(("MPU\n"));
521 	if (get_module(mpu401_name, (module_info **)&mpu401)) {
522 		put_module(gameport_name);
523 		put_module(pci_name);
524 		return ENOSYS;
525 	}
526 
527 	ddprintf(("MPU: %p\n", mpu401));
528 
529 	while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
530 		if (info.vendor_id == CMEDIA_PCI_VENDOR_ID &&
531 			(info.device_id == CMEDIA_8338A_DEVICE_ID ||
532 			 info.device_id == CMEDIA_8338B_DEVICE_ID ||
533 			 info.device_id == CMEDIA_8738A_DEVICE_ID ||
534 			 info.device_id == CMEDIA_8738B_DEVICE_ID )) {
535 			if (num_cards == NUM_CARDS) {
536 				dprintf("Too many C-Media cards installed!\n");
537 				break;
538 			}
539 			memset(&cards[num_cards], 0, sizeof(cmedia_pci_dev));
540 			cards[num_cards].info = info;
541 #ifdef __HAIKU__
542 			if ((err = (*pci->reserve_device)(info.bus, info.device, info.function,
543 				DRIVER_NAME, &cards[num_cards])) < B_OK) {
544 				dprintf("%s: failed to reserve_device(%d, %d, %d,): %s\n",
545 					DRIVER_NAME, info.bus, info.device, info.function,
546 					strerror(err));
547 				continue;
548 			}
549 #endif
550 			if (setup_cmedia_pci(&cards[num_cards])) {
551 				dprintf("Setup of C-Media %ld failed\n", num_cards+1);
552 #ifdef __HAIKU__
553 				(*pci->unreserve_device)(info.bus, info.device, info.function,
554 					DRIVER_NAME, &cards[num_cards]);
555 #endif
556 			}
557 			else {
558 				num_cards++;
559 			}
560 		}
561 		ix++;
562 	}
563 	if (!num_cards) {
564 		KPRINTF(("no cards\n"));
565 		put_module(mpu401_name);
566 		put_module(gameport_name);
567 		put_module(pci_name);
568 		ddprintf(("cmedia_pci: no suitable cards found\n"));
569 		return ENODEV;
570 	}
571 
572 #if DEBUG
573 	add_debugger_command("cmedia", debug_cmedia, "cmedia [card# (1-n)]");
574 #endif
575 	return B_OK;
576 }
577 
578 
579 static void
580 teardown_cmedia_pci(cmedia_pci_dev * card)
581 {
582 	static uchar regs[] = {
583 #ifdef DO_JOY
584 		0x04, 0x00, 0x02,	/* enable joystick */
585 #endif
586 #ifdef DO_MIDI
587 		0x04, 0x00, 0x04,	/* enable MPU-401 */
588 #endif
589 	};
590 	uchar * ptr = regs;
591 	cpu_status cp;
592 
593 	/* remove created devices */
594 	(*gameport->delete_device)(card->joy.driver);
595 	(*mpu401->delete_device)(card->midi.driver);
596 
597 	cp = disable_interrupts();
598 	acquire_spinlock(&card->hardware);
599 
600 	while (ptr < regs + sizeof(regs)) {
601 		set_direct(card, ptr[0], ptr[1], ptr[2]);
602 		ptr += 3;
603 	}
604 	disable_card_interrupts(card);
605 
606 	release_spinlock(&card->hardware);
607 	restore_interrupts(cp);
608 
609 	delete_sem(card->pcm.init_sem);
610 
611 #ifdef __HAIKU__
612 	(*pci->unreserve_device)(card->info.bus, card->info.device,
613 		card->info.function, DRIVER_NAME, card);
614 #endif
615 }
616 
617 
618 void
619 uninit_driver(void)
620 {
621 	int ix, cnt = num_cards;
622 	num_cards = 0;
623 
624 	ddprintf(("cmedia_pci: uninit_driver()\n"));
625 	remove_debugger_command("cmedia", debug_cmedia);
626 
627 	for (ix = 0; ix < cnt; ix++) {
628 		teardown_cmedia_pci(&cards[ix]);
629 	}
630 	memset(&cards, 0, sizeof(cards));
631 	put_module(mpu401_name);
632 	put_module(gameport_name);
633 	put_module(pci_name);
634 }
635 
636 
637 const char **
638 publish_devices(void)
639 {
640 	int ix = 0;
641 	ddprintf(("cmedia_pci: publish_devices()\n"));
642 
643 	for (ix = 0; names[ix]; ix++) {
644 		ddprintf(("cmedia_pci: publish %s\n", names[ix]));
645 	}
646 	return (const char **)names;
647 }
648 
649 
650 device_hooks *
651 find_device(const char * name)
652 {
653 	int ix;
654 
655 	ddprintf(("cmedia_pci: find_device(%s)\n", name));
656 
657 	for (ix = 0; ix < num_cards; ix++) {
658 #if DO_MIDI
659 		if (!strcmp(cards[ix].midi.name, name)) {
660 			return &midi_hooks;
661 		}
662 #endif /* DO_MIDI */
663 #if DO_JOY
664 		if (!strcmp(cards[ix].joy.name1, name)) {
665 			return &joy_hooks;
666 		}
667 #endif /* DO_JOY */
668 #if DO_PCM
669 		if (!strcmp(cards[ix].pcm.name, name)) {
670 			return &pcm_hooks;
671 		}
672 		if (!strcmp(cards[ix].pcm.oldname, name)) {
673 			return &pcm_hooks;
674 		}
675 #endif /* DO_PCM */
676 #if DO_MUX
677 		if (!strcmp(cards[ix].mux.name, name)) {
678 			return &mux_hooks;
679 		}
680 
681 #endif /* DO_MUX */
682 #if DO_MIXER
683 		if (!strcmp(cards[ix].mixer.name, name)) {
684 			return &mixer_hooks;
685 		}
686 #endif /* DO_MIXER */
687 	}
688 	ddprintf(("cmedia_pci: find_device(%s) failed\n", name));
689 	return NULL;
690 }
691 
692 int32	api_version = B_CUR_DRIVER_API_VERSION;
693 
694 static int32
695 cmedia_pci_interrupt(void * data)
696 {
697 	cpu_status cp = disable_interrupts();
698 	cmedia_pci_dev * card = (cmedia_pci_dev *)data;
699 	uchar status;
700 	int32 handled = B_UNHANDLED_INTERRUPT;
701 
702 /*	KTRACE(); / * */
703 	acquire_spinlock(&card->hardware);
704 
705 	status = get_direct(card, 0x10);
706 
707 #if DEBUG
708 /*	kprintf("%x\n", status); / * */
709 #endif
710 #if DO_PCM
711 	if (status & 0x02) {
712 		if (dma_c_interrupt(card)) {
713 			handled = B_INVOKE_SCHEDULER;
714 		}
715 		else {
716 			handled = B_HANDLED_INTERRUPT;
717 		}
718 		/* acknowledge interrupt */
719 		set_direct(card, 0x0e, 0x00, 0x02);
720 		set_direct(card, 0x0e, 0x02, 0x02);
721 	}
722 	if (status & 0x01) {
723 		if (dma_a_interrupt(card)) {
724 			handled = B_INVOKE_SCHEDULER;
725 		}
726 		else {
727 			handled = B_HANDLED_INTERRUPT;
728 		}
729 		/* acknowledge interrupt */
730 		set_direct(card, 0x0e, 0x00, 0x01);
731 		set_direct(card, 0x0e, 0x01, 0x01);
732 	}
733 #endif
734 #if DO_MIDI
735 	status = get_direct(card, 0x12);
736 	if (status & 0x01) {
737 		if (midi_interrupt(card)) {
738 			handled = B_INVOKE_SCHEDULER;
739 		} else {
740 			handled = B_HANDLED_INTERRUPT;
741 		}
742 	}
743 #endif
744 
745 	/*  Sometimes, the Sonic Vibes will receive a byte of Midi data...
746 	**  And duly note it in the MPU401 status register...
747 	**  And generate an interrupt...
748 	**  But not bother setting the midi interrupt bit in the ISR.
749 	**  Thanks a lot, S3.
750 	*/
751 	if (handled == B_UNHANDLED_INTERRUPT) {
752 		if (midi_interrupt(card)) {
753 			handled = B_INVOKE_SCHEDULER;
754 		}
755 	}
756 
757 /*	KTRACE(); / * */
758 	release_spinlock(&card->hardware);
759 	restore_interrupts(cp);
760 
761 	return handled;
762 //	return (handled == B_INVOKE_SCHEDULER) ? B_HANDLED_INTERRUPT : handled;
763 }
764 
765 
766 void
767 increment_interrupt_handler(cmedia_pci_dev * card)
768 {
769 	KPRINTF(("cmedia_pci: increment_interrupt_handler()\n"));
770 	if (atomic_add(&card->inth_count, 1) == 0) {
771 	// !!!
772 		KPRINTF(("cmedia_pci: intline %d int %p\n", card->info.u.h0.interrupt_line, cmedia_pci_interrupt));
773 		install_io_interrupt_handler(card->info.u.h0.interrupt_line,
774 			cmedia_pci_interrupt, card, 0);
775 	}
776 }
777 
778 
779 void
780 decrement_interrupt_handler(cmedia_pci_dev * card)
781 {
782 	KPRINTF(("cmedia_pci: decrement_interrupt_handler()\n"));
783 	if (atomic_add(&card->inth_count, -1) == 1) {
784 		KPRINTF(("cmedia_pci: remove_io_interrupt_handler()\n"));
785 		remove_io_interrupt_handler(card->info.u.h0.interrupt_line, cmedia_pci_interrupt, card);
786 	}
787 }
788 
789 
790