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