sound/drivers/opl3/opl3_lib.c

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

File Facts

System
Linux kernel
Corpus path
sound/drivers/opl3/opl3_lib.c
Extension
.c
Size
12651 bytes
Lines
523
Domain
Driver Families
Bucket
sound/drivers
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (!opl3->res_l_port) {
			dev_err(card->dev, "opl3: can't grab left port 0x%lx\n", l_port);
			snd_device_free(card, opl3);
			return -EBUSY;
		}
		if (r_port != 0) {
			opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)");
			if (!opl3->res_r_port) {
				dev_err(card->dev, "opl3: can't grab right port 0x%lx\n", r_port);
				snd_device_free(card, opl3);
				return -EBUSY;
			}
		}
	}
	opl3->l_port = l_port;
	opl3->r_port = r_port;

	switch (opl3->hardware) {
	/* some hardware doesn't support timers */
	case OPL3_HW_OPL3_SV:
	case OPL3_HW_OPL3_CS:
	case OPL3_HW_OPL3_FM801:
		opl3->command = &snd_opl3_command;
		break;
	default:
		opl3->command = &snd_opl2_command;
		err = snd_opl3_detect(opl3);
		if (err < 0) {
			dev_dbg(card->dev, "OPL2/3 chip not detected at 0x%lx/0x%lx\n",
				opl3->l_port, opl3->r_port);
			snd_device_free(card, opl3);
			return err;
		}
		/* detect routine returns correct hardware type */
		switch (opl3->hardware & OPL3_HW_MASK) {
		case OPL3_HW_OPL3:
		case OPL3_HW_OPL4:
			opl3->command = &snd_opl3_command;
		}
	}

	snd_opl3_init(opl3);

	*ropl3 = opl3;
	return 0;
}

EXPORT_SYMBOL(snd_opl3_create);

int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
{
	int err;

	if (timer1_dev >= 0) {
		err = snd_opl3_timer1_init(opl3, timer1_dev);
		if (err < 0)
			return err;
	}
	if (timer2_dev >= 0) {
		err = snd_opl3_timer2_init(opl3, timer2_dev);
		if (err < 0) {
			snd_device_free(opl3->card, opl3->timer1);
			opl3->timer1 = NULL;
			return err;
		}
	}
	return 0;
}

EXPORT_SYMBOL(snd_opl3_timer_new);

int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
		       int device, int seq_device,
		       struct snd_hwdep ** rhwdep)
{
	struct snd_hwdep *hw;
	struct snd_card *card = opl3->card;
	int err;

	if (rhwdep)
		*rhwdep = NULL;

	/* create hardware dependent device (direct FM) */

	err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw);
	if (err < 0) {
		snd_device_free(card, opl3);
		return err;
	}
	hw->private_data = opl3;

Annotation

Implementation Notes