xref: /haiku/src/add-ons/kernel/drivers/audio/cmedia/cm.c (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
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 ((where.address & ~(phys_addr_t)0xffffff) != 0) {
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 %#" B_PRIxPHYSADDR "  logical %p\n",
364 where.address, ainfo.address);
365 		goto a_o_k;
366 	}
367 
368 allocate:
369 	if (curarea >= 0) {
370 		delete_area(curarea); /* area didn't work */
371 		curarea = -1;
372 	}
373 	ddprintf(("cmedia_pci: allocating new low area\n"));
374 
375 	curarea = create_area(name, &addr, B_ANY_KERNEL_ADDRESS,
376 		trysize, B_LOMEM, B_READ_AREA | B_WRITE_AREA);
377 	ddprintf(("cmedia_pci: create_area(%lx) returned %lx logical %p\n",
378 		trysize, curarea, addr));
379 	if (curarea < 0) {
380 		goto oops;
381 	}
382 	if (get_memory_map(addr, low_size, &where, 1) < 0) {
383 		delete_area(curarea);
384 		curarea = B_ERROR;
385 		goto oops;
386 	}
387 	ddprintf(("cmedia_pci: physical %p\n", where.address));
388 	if ((where.address & ~(phys_addr_t)0xffffff) != 0) {
389 		delete_area(curarea);
390 		curarea = B_ERROR;
391 		goto oops;
392 	}
393 	if (((where.address + low_size) & ~(phys_addr_t)0xffffff) != 0) {
394 		delete_area(curarea);
395 		curarea = B_ERROR;
396 		goto oops;
397 	}
398 	/* hey, it worked! */
399 	if (trysize > low_size) {	/* don't waste */
400 		resize_area(curarea, low_size);
401 	}
402 
403 oops:
404 	if (curarea < 0) {
405 		dprintf("cmedia_pci: failed to create low_mem area\n");
406 		return curarea;
407 	}
408 a_o_k:
409 	ddprintf(("cmedia_pci: successfully found or created low area!\n"));
410 	card->low_size = low_size;
411 	card->low_mem = addr;
412 	card->low_phys = (vuchar *)(addr_t)where.address;
413 	card->map_low = curarea;
414 	return B_OK;
415 }
416 
417 
418 static status_t
419 setup_cmedia_pci(
420 	cmedia_pci_dev * card)
421 {
422 	status_t err = B_OK;
423 /*	cpu_status cp; */
424 
425 	ddprintf(("cmedia_pci: setup_cmedia_pci(%p)\n", card));
426 
427 	if ((card->pcm.init_sem = create_sem(1, "cm pcm init")) < B_OK)
428 		goto bail;
429 #if 1
430 	if ((*mpu401->create_device)(0x330, &card->midi.driver,
431 #else
432 	if ((*mpu401->create_device)(card->info.u.h0.base_registers[3], &card->midi.driver,
433 #endif
434 		0, midi_interrupt_op, &card->midi) < B_OK)
435 		goto bail3;
436 #if 1
437 	if ((*gameport->create_device)(0x201, &card->joy.driver) < B_OK)
438 #else
439 	if ((*gameport->create_device)(card->info.u.h0.base_registers[4], &card->joy.driver) < B_OK)
440 #endif
441 		goto bail4;
442 	ddprintf(("midi %p  gameport %p\n", card->midi.driver, card->joy.driver));
443 	card->midi.card = card;
444 
445 	err = find_low_memory(card);
446 	if (err < B_OK) {
447 		goto bail5;
448 	}
449 
450 	//cp = disable_interrupts();
451 	//acquire_spinlock(&card->hardware);
452 
453 	make_device_names(card);
454 	card->enhanced = card->info.u.h0.base_registers[0];
455 	ddprintf(("cmedia_pci: %s enhanced at %x\n", card->name, card->enhanced));
456 
457 	ddprintf(("cmedia_pci: revision %x\n", get_indirect(card, 0x15)));
458 
459 	disable_card_interrupts(card);
460 	if (setup_dma(card) != B_OK)
461 	{
462 		dprintf("cmedia pci: can't setup DMA\n");
463 		goto bail6;
464 	}
465 
466 	set_default_registers(card);
467 
468 	//release_spinlock(&card->hardware);
469 	//restore_interrupts(cp);
470 
471 	return B_OK;
472 
473 bail6:
474 	//	deallocate low memory
475 bail5:
476 	(*gameport->delete_device)(card->joy.driver);
477 bail4:
478 	(*mpu401->delete_device)(card->midi.driver);
479 bail3:
480 	delete_sem(card->pcm.init_sem);
481 bail:
482 	return err < B_OK ? err : B_ERROR;
483 }
484 
485 
486 static int
487 debug_cmedia(
488 	int argc,
489 	char * argv[])
490 {
491 	int ix = 0;
492 	if (argc == 2) {
493 		ix = parse_expression(argv[1])-1;
494 	}
495 	if (argc > 2 || ix < 0 || ix >= num_cards) {
496 		dprintf("cmedia_pci: dude, you gotta watch your syntax!\n");
497 		return -1;
498 	}
499 	dprintf("%s: enhanced registers at 0x%x\n", cards[ix].name,
500 		cards[ix].enhanced);
501 	dprintf("%s: open %ld   dma_a at 0x%x   dma_c 0x%x\n", cards[ix].pcm.name,
502 		cards[ix].pcm.open_count, cards[ix].pcm.dma_a, cards[ix].pcm.dma_c);
503 	if (cards[ix].pcm.open_count) {
504 		dprintf("    dma_a: 0x%lx+0x%lx   dma_c: 0x%lx+0x%lx\n",
505 			PCI_IO_RD_32((int)cards[ix].pcm.dma_a), PCI_IO_RD_32((int)cards[ix].pcm.dma_a+4),
506 			PCI_IO_RD_32((int)cards[ix].pcm.dma_c), PCI_IO_RD_32((int)cards[ix].pcm.dma_c+4));
507 	}
508 	return 0;
509 }
510 
511 
512 status_t
513 init_driver(void)
514 {
515 	pci_info info;
516 	int ix = 0;
517 
518 	num_cards = 0;
519 
520 	ddprintf(("cmedia_pci: init_driver()\n"));
521 
522 	if (get_module(pci_name, (module_info **)&pci))
523 		return ENOSYS;
524 
525 	if (get_module(gameport_name, (module_info **)&gameport)) {
526 		put_module(pci_name);
527 		return ENOSYS;
528 	}
529 	ddprintf(("MPU\n"));
530 	if (get_module(mpu401_name, (module_info **) &mpu401)) {
531 		put_module(gameport_name);
532 		put_module(pci_name);
533 		return ENOSYS;
534 	}
535 
536 	ddprintf(("MPU: %p\n", mpu401));
537 
538 	while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) {
539 		if (info.vendor_id == CMEDIA_PCI_VENDOR_ID &&
540 			(info.device_id == CMEDIA_8338A_DEVICE_ID ||
541 			 info.device_id == CMEDIA_8338B_DEVICE_ID ||
542 			 info.device_id == CMEDIA_8738A_DEVICE_ID ||
543 			 info.device_id == CMEDIA_8738B_DEVICE_ID )) {
544 			if (num_cards == NUM_CARDS) {
545 				dprintf("Too many C-Media cards installed!\n");
546 				break;
547 			}
548 			memset(&cards[num_cards], 0, sizeof(cmedia_pci_dev));
549 			cards[num_cards].info = info;
550 			if (setup_cmedia_pci(&cards[num_cards])) {
551 				dprintf("Setup of C-Media %ld failed\n", num_cards+1);
552 			}
553 			else {
554 				num_cards++;
555 			}
556 		}
557 		ix++;
558 	}
559 	if (!num_cards) {
560 		KPRINTF(("no cards\n"));
561 		put_module(mpu401_name);
562 		put_module(gameport_name);
563 		put_module(pci_name);
564 		ddprintf(("cmedia_pci: no suitable cards found\n"));
565 		return ENODEV;
566 	}
567 
568 #if DEBUG
569 	add_debugger_command("cmedia", debug_cmedia, "cmedia [card# (1-n)]");
570 #endif
571 	return B_OK;
572 }
573 
574 
575 static void
576 teardown_cmedia_pci(
577 	cmedia_pci_dev * card)
578 {
579 	static uchar regs[] = {
580 #ifdef DO_JOY
581 		0x04, 0x00, 0x02,	/* enable joystick */
582 #endif
583 #ifdef DO_MIDI
584 		0x04, 0x00, 0x04,	/* enable MPU-401 */
585 #endif
586 	};
587 	uchar * ptr = regs;
588 	cpu_status cp;
589 
590 	/* remove created devices */
591 	(*gameport->delete_device)(card->joy.driver);
592 	(*mpu401->delete_device)(card->midi.driver);
593 
594 	cp = disable_interrupts();
595 	acquire_spinlock(&card->hardware);
596 
597 	while (ptr < regs+sizeof(regs)) {
598 		set_direct(card, ptr[0], ptr[1], ptr[2]);
599 		ptr += 3;
600 	}
601 	disable_card_interrupts(card);
602 
603 	release_spinlock(&card->hardware);
604 	restore_interrupts(cp);
605 
606 	delete_sem(card->pcm.init_sem);
607 }
608 
609 
610 void
611 uninit_driver(void)
612 {
613 	int ix, cnt = num_cards;
614 	num_cards = 0;
615 
616 	ddprintf(("cmedia_pci: uninit_driver()\n"));
617 	remove_debugger_command("cmedia", debug_cmedia);
618 
619 	for (ix=0; ix<cnt; ix++) {
620 		teardown_cmedia_pci(&cards[ix]);
621 	}
622 	memset(&cards, 0, sizeof(cards));
623 	put_module(mpu401_name);
624 	put_module(gameport_name);
625 	put_module(pci_name);
626 }
627 
628 
629 const char **
630 publish_devices(void)
631 {
632 	int ix = 0;
633 	ddprintf(("cmedia_pci: publish_devices()\n"));
634 
635 	for (ix=0; names[ix]; ix++) {
636 		ddprintf(("cmedia_pci: publish %s\n", names[ix]));
637 	}
638 	return (const char **)names;
639 }
640 
641 
642 device_hooks *
643 find_device(
644 	const char * name)
645 {
646 	int ix;
647 
648 	ddprintf(("cmedia_pci: find_device(%s)\n", name));
649 
650 	for (ix=0; ix<num_cards; ix++) {
651 #if DO_MIDI
652 		if (!strcmp(cards[ix].midi.name, name)) {
653 			return &midi_hooks;
654 		}
655 #endif /* DO_MIDI */
656 #if DO_JOY
657 		if (!strcmp(cards[ix].joy.name1, name)) {
658 			return &joy_hooks;
659 		}
660 #endif /* DO_JOY */
661 #if DO_PCM
662 		if (!strcmp(cards[ix].pcm.name, name)) {
663 			return &pcm_hooks;
664 		}
665 		if (!strcmp(cards[ix].pcm.oldname, name)) {
666 			return &pcm_hooks;
667 		}
668 #endif /* DO_PCM */
669 #if DO_MUX
670 		if (!strcmp(cards[ix].mux.name, name)) {
671 			return &mux_hooks;
672 		}
673 
674 #endif /* DO_MUX */
675 #if DO_MIXER
676 		if (!strcmp(cards[ix].mixer.name, name)) {
677 			return &mixer_hooks;
678 		}
679 #endif /* DO_MIXER */
680 	}
681 	ddprintf(("cmedia_pci: find_device(%s) failed\n", name));
682 	return NULL;
683 }
684 
685 int32	api_version = B_CUR_DRIVER_API_VERSION;
686 
687 static int32
688 cmedia_pci_interrupt(
689 	void * data)
690 {
691 	cpu_status cp = disable_interrupts();
692 	cmedia_pci_dev * card = (cmedia_pci_dev *)data;
693 	uchar status;
694 	int32 handled = B_UNHANDLED_INTERRUPT;
695 
696 /*	KTRACE(); / * */
697 	acquire_spinlock(&card->hardware);
698 
699 	status = get_direct(card, 0x10);
700 
701 #if DEBUG
702 /*	kprintf("%x\n", status); / * */
703 #endif
704 #if DO_PCM
705 	if (status & 0x02) {
706 		if (dma_c_interrupt(card)) {
707 			handled = B_INVOKE_SCHEDULER;
708 		}
709 		else {
710 			handled = B_HANDLED_INTERRUPT;
711 		}
712 		/* acknowledge interrupt */
713 		set_direct(card, 0x0e, 0x00, 0x02);
714 		set_direct(card, 0x0e, 0x02, 0x02);
715 	}
716 	if (status & 0x01) {
717 		if (dma_a_interrupt(card)) {
718 			handled = B_INVOKE_SCHEDULER;
719 		}
720 		else {
721 			handled = B_HANDLED_INTERRUPT;
722 		}
723 		/* acknowledge interrupt */
724 		set_direct(card, 0x0e, 0x00, 0x01);
725 		set_direct(card, 0x0e, 0x01, 0x01);
726 	}
727 #endif
728 #if DO_MIDI
729 	status = get_direct(card, 0x12);
730 	if (status & 0x01) {
731 		if (midi_interrupt(card)) {
732 			handled = B_INVOKE_SCHEDULER;
733 		} else {
734 			handled = B_HANDLED_INTERRUPT;
735 		}
736 	}
737 #endif
738 
739 	/*  Sometimes, the Sonic Vibes will receive a byte of Midi data...
740 	**  And duly note it in the MPU401 status register...
741 	**  And generate an interrupt...
742 	**  But not bother setting the midi interrupt bit in the ISR.
743 	**  Thanks a lot, S3.
744 	*/
745 	if(handled == B_UNHANDLED_INTERRUPT){
746 		if (midi_interrupt(card)) {
747 			handled = B_INVOKE_SCHEDULER;
748 		}
749 	}
750 
751 /*	KTRACE(); / * */
752 	release_spinlock(&card->hardware);
753 	restore_interrupts(cp);
754 
755 	return handled;
756 //	return (handled == B_INVOKE_SCHEDULER) ? B_HANDLED_INTERRUPT : handled;
757 }
758 
759 
760 void
761 increment_interrupt_handler(
762 	cmedia_pci_dev * card)
763 {
764 	KPRINTF(("cmedia_pci: increment_interrupt_handler()\n"));
765 	if (atomic_add(&card->inth_count, 1) == 0) {
766 	// !!!
767 		KPRINTF(("cmedia_pci: intline %d int %p\n", card->info.u.h0.interrupt_line, cmedia_pci_interrupt));
768 		install_io_interrupt_handler(card->info.u.h0.interrupt_line,
769 			cmedia_pci_interrupt, card, 0);
770 	}
771 }
772 
773 
774 void
775 decrement_interrupt_handler(
776 	cmedia_pci_dev * card)
777 {
778 	KPRINTF(("cmedia_pci: decrement_interrupt_handler()\n"));
779 	if (atomic_add(&card->inth_count, -1) == 1) {
780 		KPRINTF(("cmedia_pci: remove_io_interrupt_handler()\n"));
781 		remove_io_interrupt_handler(card->info.u.h0.interrupt_line, cmedia_pci_interrupt, card);
782 	}
783 }
784 
785 
786