sound/drivers/opl3/opl3_midi.c

Source file repositories/reference/linux-study-clean/sound/drivers/opl3/opl3_midi.c

File Facts

System
Linux kernel
Corpus path
sound/drivers/opl3/opl3_midi.c
Extension
.c
Size
21074 bytes
Lines
824
Domain
Driver Families
Bucket
sound/drivers
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct best {
		unsigned int time;
		int voice;
	} best[END];
	struct best *bp;

	for (i = 0; i < END; i++) {
		best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */
		best[i].voice = -1;
	}

	/* Look through all the channels for the most suitable. */
	for (i = 0; i < opl3->max_voices; i++) {
		vp = &opl3->voices[i];

		if (vp->state == SNDRV_OPL3_ST_NOT_AVAIL)
		  /* skip unavailable channels, allocated by
		     drum voices or by bounded 4op voices) */
			continue;

		voice_time = vp->time;
		bp = best;

		chan_4op_1 = ((i < 3) || (i > 8 && i < 12));
		chan_4op_2 = ((i > 2 && i < 6) || (i > 11 && i < 15));
		if (instr_4op) {
			/* allocate 4op voice */
			/* skip channels unavailable to 4op instrument */
			if (!chan_4op_1)
				continue;

			if (vp->state)
				/* kill one voice, CHEAP */
				bp++;
			/* get state of bounded 2op channel
			   to be allocated for 4op instrument */
			vp2 = &opl3->voices[i + 3];
			if (vp2->state == SNDRV_OPL3_ST_ON_2OP) {
				/* kill two voices, EXPENSIVE */
				bp++;
				voice_time = max(voice_time, vp2->time);
			}
		} else {
			/* allocate 2op voice */
			if ((chan_4op_1) || (chan_4op_2))
				/* use bounded channels for 2op, CHEAP */
				bp++;
			else if (vp->state)
				/* kill one voice on 2op channel, CHEAP */
				bp++;
			/* raise kill cost to EXPENSIVE for all channels */
			if (vp->state)
				bp++;
		}
		if (voice_time < bp->time) {
			bp->time = voice_time;
			bp->voice = i;
		}
	}

	for (i = 0; i < END; i++) {
		if (best[i].voice >= 0) {
#ifdef DEBUG_ALLOC
			dev_dbg(opl3->card->dev,
				"%s %iop allocation on voice %i\n",
				alloc_type[i], instr_4op ? 4 : 2,
				best[i].voice);
#endif
			return best[i].voice;
		}
	}
	/* not found */
	return -1;
}

/* ------------------------------ */

/*
 * System timer interrupt function
 */
void snd_opl3_timer_func(struct timer_list *t)
{

	struct snd_opl3 *opl3 = timer_container_of(opl3, t, tlist);
	int again = 0;
	int i;

	scoped_guard(spinlock_irqsave, &opl3->voice_lock) {
		for (i = 0; i < opl3->max_voices; i++) {
			struct snd_opl3_voice *vp = &opl3->voices[i];

Annotation

Implementation Notes