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