xref: /haiku/src/add-ons/kernel/drivers/audio/cmedia/cm.c (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
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 void dump_card(cmedia_pci_dev* card);
191 #if 0
192 void dump_card(cmedia_pci_dev* card)
193 {
194 	int ix;
195 	dprintf("\n");
196 	dprintf("CM:   ");
197 	for (ix=0; ix<6; ix++) {
198 		if (ix == 2 || ix == 3) dprintf("   ");
199 		else dprintf(" %02x", get_direct(card, ix));
200 	}
201 	for (ix=0; ix<0x32; ix++) {
202 		if (!(ix & 7)) {
203 			dprintf("\nCMX%02x:", ix);
204 		}
205 		dprintf(" %02x", get_indirect(card, ix));
206 	}
207 	dprintf("\n");
208 	dprintf("\n");
209 }
210 #else
211 void dump_card(cmedia_pci_dev* card)
212 {
213 }
214 #endif
215 
216 
217 static void
218 disable_card_interrupts(cmedia_pci_dev * card)
219 {
220 	set_direct(card, 0x0e, 0x00, 0x03);
221 }
222 
223 
224 static status_t
225 setup_dma(cmedia_pci_dev * card)
226 {
227 	/* we're appropriating some ISA space here... */
228 	/* need kernel support to do it right */
229 	const uint16 base = card->enhanced + 0x80;
230 	ddprintf(("cmedia_pci: dma base is 0x%04x\n", base));
231 	if (base == 0)
232 		return B_DEV_RESOURCE_CONFLICT;
233 	card->dma_base = base;
234 	return B_OK;
235 }
236 
237 
238 static void
239 set_default_registers(cmedia_pci_dev * card)
240 {
241 	static uchar values[] = {
242 #ifdef DO_JOY
243 		0x04, 0x02, 0x02,	/* enable joystick */
244 #endif
245 
246 		0x0a, 0x01, 0x01,	/* enable SPDIF inverse before SPDIF_LOOP */
247 		0x04, 0x80, 0x80,	/* enable SPDIF_LOOP */
248 
249 		0x1a, 0x00, 0x20,	/* SPD32SEL disable */
250 		0x1a, 0x00, 0x10,	/* SPDFLOOPI disable */
251 
252 		0x1b, 0x04, 0x04,	/* dual channel mode enable */
253 		0x1a, 0x00, 0x80,	/* Double DAC structure disable */
254 
255 		0x24, 0x00, 0x02,	/* 3D surround disable */
256 
257 		0x24, 0x00, 0x01,	/* disable SPDIF_IN PCM to DAC */
258 #ifdef DO_MIDI
259 		0x04, 0x04, 0x04,	/* enable MPU-401 */
260 		0x17, 0x00, 0x60,	/* default at 0x330 */
261 #endif
262 	};
263 	uchar * ptr = values;
264 
265 	while (ptr < values+sizeof(values)) {
266 		set_direct(card, ptr[0], ptr[1], ptr[2]);
267 		ptr += 3;
268 	}
269 }
270 
271 
272 static void
273 make_device_names(cmedia_pci_dev * card)
274 {
275 	char * name = card->name;
276 	sprintf(name, "cmedia_pci/%ld", card-cards + 1);
277 
278 #if DO_MIDI
279 	sprintf(card->midi.name, "midi/%s", name);
280 	names[num_names++] = card->midi.name;
281 #endif /* DO_MIDI */
282 #if DO_JOY
283 	sprintf(card->joy.name1, "joystick/%s", name);
284 	names[num_names++] = card->joy.name1;
285 #endif /* DO_JOY */
286 #if DO_PCM
287 	/* cmedia_pci DMA doesn't work when physical NULL isn't NULL from PCI */
288 	/* this is a hack to not export bad devices on BeBox hardware */
289 	if ((*pci->ram_address)(0) == 0) {
290 		sprintf(card->pcm.name, "audio/raw/%s", name);
291 		names[num_names++] = card->pcm.name;
292 		sprintf(card->pcm.oldname, "audio/old/%s", name);
293 		names[num_names++] = card->pcm.oldname;
294 	}
295 #endif /* DO_PCM */
296 #if DO_MUX
297 	sprintf(card->mux.name, "audio/mux/%s", name);
298 	names[num_names++] = card->mux.name;
299 #endif /* DO_MUX */
300 #if DO_MIXER
301 	sprintf(card->mixer.name, "audio/mix/%s", name);
302 	names[num_names++] = card->mixer.name;
303 #endif /* DO_MIXER */
304 	names[num_names] = NULL;
305 }
306 
307 
308 /* We use the SV chip in ISA DMA addressing mode, which is 24 bits */
309 /* so we need to find suitable, locked, contiguous memory in that */
310 /* physical address range. */
311 
312 static status_t
313 find_low_memory(cmedia_pci_dev * card)
314 {
315 	size_t low_size = (MIN_MEMORY_SIZE + (B_PAGE_SIZE - 1))
316 		&~ (B_PAGE_SIZE - 1);
317 	physical_entry where;
318 	size_t trysize;
319 	area_id curarea;
320 	void * addr;
321 	char name[DEVNAME];
322 
323 	sprintf(name, "%s_low", card->name);
324 	if (low_size < MIN_MEMORY_SIZE) {
325 		low_size = MIN_MEMORY_SIZE;
326 	}
327 	trysize = low_size;
328 
329 	curarea = find_area(name);
330 	if (curarea >= 0) {	/* area there from previous run */
331 		area_info ainfo;
332 		ddprintf(("cmedia_pci: testing likely candidate...\n"));
333 		if (get_area_info(curarea, &ainfo)) {
334 			ddprintf(("cmedia_pci: no info\n"));
335 			goto allocate;
336 		}
337 		/* test area we found */
338 		trysize = ainfo.size;
339 		addr = ainfo.address;
340 		if (trysize < low_size) {
341 			ddprintf(("cmedia_pci: too small (%lx)\n", trysize));
342 			goto allocate;
343 		}
344 		if (get_memory_map(addr, trysize, &where, 1) < B_OK) {
345 			ddprintf(("cmedia_pci: no memory map\n"));
346 			goto allocate;
347 		}
348 		if ((where.address & ~(phys_addr_t)0xffffff) != 0) {
349 			ddprintf(("cmedia_pci: bad physical address\n"));
350 			goto allocate;
351 		}
352 		if (ainfo.lock < B_FULL_LOCK || where.size < low_size) {
353 			ddprintf(("cmedia_pci: lock not contiguous\n"));
354 			goto allocate;
355 		}
356 dprintf("cmedia_pci: physical %#" B_PRIxPHYSADDR "  logical %p\n",
357 where.address, ainfo.address);
358 		goto a_o_k;
359 	}
360 
361 allocate:
362 	if (curarea >= 0) {
363 		delete_area(curarea); /* area didn't work */
364 		curarea = -1;
365 	}
366 	ddprintf(("cmedia_pci: allocating new low area\n"));
367 
368 	curarea = create_area(name, &addr, B_ANY_KERNEL_ADDRESS,
369 		trysize, B_LOMEM, B_READ_AREA | B_WRITE_AREA);
370 	ddprintf(("cmedia_pci: create_area(%lx) returned %lx logical %p\n",
371 		trysize, curarea, addr));
372 	if (curarea < 0) {
373 		goto oops;
374 	}
375 	if (get_memory_map(addr, low_size, &where, 1) < 0) {
376 		delete_area(curarea);
377 		curarea = B_ERROR;
378 		goto oops;
379 	}
380 	ddprintf(("cmedia_pci: physical %p\n", where.address));
381 	if ((where.address & ~(phys_addr_t)0xffffff) != 0) {
382 		delete_area(curarea);
383 		curarea = B_ERROR;
384 		goto oops;
385 	}
386 	if (((where.address + low_size) & ~(phys_addr_t)0xffffff) != 0) {
387 		delete_area(curarea);
388 		curarea = B_ERROR;
389 		goto oops;
390 	}
391 	/* hey, it worked! */
392 	if (trysize > low_size) {	/* don't waste */
393 		resize_area(curarea, low_size);
394 	}
395 
396 oops:
397 	if (curarea < 0) {
398 		dprintf("cmedia_pci: failed to create low_mem area\n");
399 		return curarea;
400 	}
401 a_o_k:
402 	ddprintf(("cmedia_pci: successfully found or created low area!\n"));
403 	card->low_size = low_size;
404 	card->low_mem = addr;
405 	card->low_phys = where.address;
406 	card->map_low = curarea;
407 	return B_OK;
408 }
409 
410 
411 static status_t
412 setup_cmedia_pci(cmedia_pci_dev * card)
413 {
414 	status_t err = B_OK;
415 /*	cpu_status cp; */
416 
417 	ddprintf(("cmedia_pci: setup_cmedia_pci(%p)\n", card));
418 
419 	if ((card->pcm.init_sem = create_sem(1, "cm pcm init")) < B_OK)
420 		goto bail;
421 #if 1
422 	if ((*mpu401->create_device)(0x330, &card->midi.driver,
423 #else
424 	if ((*mpu401->create_device)(card->info.u.h0.base_registers[3], &card->midi.driver,
425 #endif
426 		0, midi_interrupt_op, &card->midi) < B_OK)
427 		goto bail3;
428 #if 1
429 	if ((*gameport->create_device)(0x201, &card->joy.driver) < B_OK)
430 #else
431 	if ((*gameport->create_device)(card->info.u.h0.base_registers[4], &card->joy.driver) < B_OK)
432 #endif
433 		goto bail4;
434 	ddprintf(("midi %p  gameport %p\n", card->midi.driver, card->joy.driver));
435 	card->midi.card = card;
436 
437 	err = find_low_memory(card);
438 	if (err < B_OK) {
439 		goto bail5;
440 	}
441 
442 	//cp = disable_interrupts();
443 	//acquire_spinlock(&card->hardware);
444 
445 	make_device_names(card);
446 	card->enhanced = card->info.u.h0.base_registers[0];
447 	ddprintf(("cmedia_pci: %s enhanced at %x\n", card->name, card->enhanced));
448 
449 	ddprintf(("cmedia_pci: revision %x\n", get_indirect(card, 0x15)));
450 
451 	disable_card_interrupts(card);
452 	if (setup_dma(card) != B_OK) {
453 		dprintf("cmedia pci: can't setup DMA\n");
454 		goto bail6;
455 	}
456 
457 	set_default_registers(card);
458 
459 	//release_spinlock(&card->hardware);
460 	//restore_interrupts(cp);
461 
462 	return B_OK;
463 
464 bail6:
465 	//	deallocate low memory
466 bail5:
467 	(*gameport->delete_device)(card->joy.driver);
468 bail4:
469 	(*mpu401->delete_device)(card->midi.driver);
470 bail3:
471 	delete_sem(card->pcm.init_sem);
472 bail:
473 	return err < B_OK ? err : B_ERROR;
474 }
475 
476 
477 static int
478 debug_cmedia(int argc, char * argv[])
479 {
480 	int ix = 0;
481 	if (argc == 2) {
482 		ix = parse_expression(argv[1]) - 1;
483 	}
484 	if (argc > 2 || ix < 0 || ix >= num_cards) {
485 		dprintf("cmedia_pci: dude, you gotta watch your syntax!\n");
486 		return -1;
487 	}
488 	dprintf("%s: enhanced registers at 0x%x\n", cards[ix].name,
489 		cards[ix].enhanced);
490 	dprintf("%s: open %" B_PRId32 "   dma_a at 0x%x   dma_c 0x%x\n", cards[ix].pcm.name,
491 		cards[ix].pcm.open_count, cards[ix].pcm.dma_a, cards[ix].pcm.dma_c);
492 	if (cards[ix].pcm.open_count) {
493 		dprintf("    dma_a: 0x%" B_PRIu32 "+0x%" B_PRIu32 "   dma_c: 0x%" B_PRIu32 "+0x%" B_PRIu32
494 				"\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 %d 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