sound/pci/oxygen/oxygen_lib.c

Source file repositories/reference/linux-study-clean/sound/pci/oxygen/oxygen_lib.c

File Facts

System
Linux kernel
Corpus path
sound/pci/oxygen/oxygen_lib.c
Extension
.c
Size
24833 bytes
Lines
798
Domain
Driver Families
Bucket
sound/pci
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 (clear) {
			if (clear & OXYGEN_INT_SPDIF_IN_DETECT)
				chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT;
			oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
				       chip->interrupt_mask & ~clear);
			oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
				       chip->interrupt_mask);
		}

		elapsed_streams = status & chip->pcm_running;
	}

	for (i = 0; i < PCM_COUNT; ++i)
		if ((elapsed_streams & (1 << i)) && chip->streams[i])
			snd_pcm_period_elapsed(chip->streams[i]);

	if (status & OXYGEN_INT_SPDIF_IN_DETECT) {
		guard(spinlock)(&chip->reg_lock);
		i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
		if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT |
			 OXYGEN_SPDIF_RATE_INT)) {
			/* write the interrupt bit(s) to clear */
			oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i);
			schedule_work(&chip->spdif_input_bits_work);
		}
	}

	if (status & OXYGEN_INT_GPIO)
		schedule_work(&chip->gpio_work);

	if (status & OXYGEN_INT_MIDI) {
		if (chip->midi)
			snd_mpu401_uart_interrupt(0, chip->midi->private_data);
		else
			oxygen_read_uart(chip);
	}

	if (status & OXYGEN_INT_AC97)
		wake_up(&chip->ac97_waitqueue);

	return IRQ_HANDLED;
}

static void oxygen_spdif_input_bits_changed(struct work_struct *work)
{
	struct oxygen *chip = container_of(work, struct oxygen,
					   spdif_input_bits_work);
	u32 reg;

	/*
	 * This function gets called when there is new activity on the SPDIF
	 * input, or when we lose lock on the input signal, or when the rate
	 * changes.
	 */
	msleep(1);
	scoped_guard(spinlock_irq, &chip->reg_lock) {
		reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
		if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
			    OXYGEN_SPDIF_LOCK_STATUS))
		    == OXYGEN_SPDIF_SENSE_STATUS) {
			/*
			 * If we detect activity on the SPDIF input but cannot lock to
			 * a signal, the clock bit is likely to be wrong.
			 */
			reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK;
			oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
			spin_unlock_irq(&chip->reg_lock);
			msleep(1);
			spin_lock_irq(&chip->reg_lock);
			reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
			if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
				    OXYGEN_SPDIF_LOCK_STATUS))
			    == OXYGEN_SPDIF_SENSE_STATUS) {
				/* nothing detected with either clock; give up */
				if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK)
				    == OXYGEN_SPDIF_IN_CLOCK_192) {
					/*
					 * Reset clock to <= 96 kHz because this is
					 * more likely to be received next time.
					 */
					reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK;
					reg |= OXYGEN_SPDIF_IN_CLOCK_96;
					oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
				}
			}
		}
	}

	if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) {
		scoped_guard(spinlock_irq, &chip->reg_lock) {

Annotation

Implementation Notes