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
21EXPORT status_t init_hardware(void);
22EXPORT status_t init_driver(void);
23EXPORT void uninit_driver(void);
24EXPORT const char ** publish_devices(void);
25EXPORT device_hooks * find_device(const char *);
26
27
28static char pci_name[] = B_PCI_MODULE_NAME;
29static pci_module_info	*pci;
30static char gameport_name[] = "generic/gameport/v1";
31generic_gameport_module * gameport;
32static char mpu401_name[] = B_MPU_401_MODULE_NAME;
33generic_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
42extern device_hooks midi_hooks;
43#endif /* DO_MIDI */
44#if DO_JOY
45extern device_hooks joy_hooks;
46#endif /* DO_JOY */
47#if DO_PCM
48extern device_hooks pcm_hooks;
49#endif /* DO_PCM */
50#if DO_MUX
51extern device_hooks mux_hooks;
52#endif /* DO_MUX */
53#if DO_MIXER
54extern device_hooks mixer_hooks;
55#endif /* DO_MIXER */
56
57
58int32 num_cards;
59cmedia_pci_dev cards[NUM_CARDS];
60int num_names;
61char * 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
69uint8
70PCI_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
80uint32
81PCI_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
89void
90PCI_IO_WR (int offset, uint8 val)
91{
92	(*pci->write_io_8) (offset, val);
93}
94
95
96/* detect presence of our hardware */
97status_t
98init_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
140void 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
154uchar 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
162void 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
180uchar 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
190void dump_card(cmedia_pci_dev* card);
191#if 0
192void 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
211void dump_card(cmedia_pci_dev* card)
212{
213}
214#endif
215
216
217static void
218disable_card_interrupts(cmedia_pci_dev * card)
219{
220	set_direct(card, 0x0e, 0x00, 0x03);
221}
222
223
224static status_t
225setup_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
238static void
239set_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
272static void
273make_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
312static status_t
313find_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		}
356dprintf("cmedia_pci: physical %#" B_PRIxPHYSADDR "  logical %p\n",
357where.address, ainfo.address);
358		goto a_o_k;
359	}
360
361allocate:
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
396oops:
397	if (curarea < 0) {
398		dprintf("cmedia_pci: failed to create low_mem area\n");
399		return curarea;
400	}
401a_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
411static status_t
412setup_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
464bail6:
465	//	deallocate low memory
466bail5:
467	(*gameport->delete_device)(card->joy.driver);
468bail4:
469	(*mpu401->delete_device)(card->midi.driver);
470bail3:
471	delete_sem(card->pcm.init_sem);
472bail:
473	return err < B_OK ? err : B_ERROR;
474}
475
476
477static int
478debug_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
502status_t
503init_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
579static void
580teardown_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
618void
619uninit_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
637const char **
638publish_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
650device_hooks *
651find_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
692int32	api_version = B_CUR_DRIVER_API_VERSION;
693
694static int32
695cmedia_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
766void
767increment_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
779void
780decrement_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