Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c94fa4c9 authored by James Courtier-Dutton's avatar James Courtier-Dutton Committed by Jaroslav Kysela
Browse files

[ALSA] emu10k1: General cleanup, add new locks, fix alsa bug#3501, kernel bug#9304.

parent 3839e4f1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1742,6 +1742,8 @@ struct snd_emu10k1 {
	spinlock_t reg_lock;
	spinlock_t emu_lock;
	spinlock_t voice_lock;
	spinlock_t spi_lock; /* serialises access to spi port */
	spinlock_t i2c_lock; /* serialises access to i2c port */

	struct snd_emu10k1_voice voices[NUM_G];
	struct snd_emu10k1_voice p16v_voices[4];
+9 −6
Original line number Diff line number Diff line
@@ -35,9 +35,9 @@ struct best_voice {
/*
 * prototypes
 */
static void lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw,
static void lookup_voices(struct snd_emux *emux, struct snd_emu10k1 *hw,
			  struct best_voice *best, int active_only);
static struct snd_emux_voice *get_voice(struct snd_emux *emu,
static struct snd_emux_voice *get_voice(struct snd_emux *emux,
					struct snd_emux_port *port);
static int start_voice(struct snd_emux_voice *vp);
static void trigger_voice(struct snd_emux_voice *vp);
@@ -45,7 +45,6 @@ static void release_voice(struct snd_emux_voice *vp);
static void update_voice(struct snd_emux_voice *vp, int update);
static void terminate_voice(struct snd_emux_voice *vp);
static void free_voice(struct snd_emux_voice *vp);

static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
@@ -75,9 +74,9 @@ static struct snd_emux_operators emu10k1_ops = {
};

void
snd_emu10k1_ops_setup(struct snd_emux *emu)
snd_emu10k1_ops_setup(struct snd_emux *emux)
{
	emu->ops = emu10k1_ops;
	emux->ops = emu10k1_ops;
}


@@ -166,7 +165,11 @@ free_voice(struct snd_emux_voice *vp)
	struct snd_emu10k1 *hw;
	
	hw = vp->hw;
	if (vp->ch >= 0) {
	/* FIXME: emu10k1_synth is broken. */
	/* This can get called with hw == 0 */
	/* Problem apparent on plug, unplug then plug */
	/* on the Audigy 2 ZS Notebook. */
	if (hw && (vp->ch >= 0)) {
		snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00);
		snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK);
		// snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0);
+4 −2
Original line number Diff line number Diff line
@@ -259,7 +259,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
		 * GPIO7: Unknown
		 */
		outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */

	}
	if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */
		int size, n;
@@ -275,7 +274,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
			emu->i2c_capture_volume[n][0]= 0xcf;
			emu->i2c_capture_volume[n][1]= 0xcf;
		}

	}

	
@@ -653,6 +651,8 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
	value = inl(special_port);

	snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */
	/* Delay to give time for ADC chip to switch on. It needs 113ms */
	msleep(200);
	return 0;
}

@@ -1717,6 +1717,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
	emu->card = card;
	spin_lock_init(&emu->reg_lock);
	spin_lock_init(&emu->emu_lock);
	spin_lock_init(&emu->spi_lock);
	spin_lock_init(&emu->i2c_lock);
	spin_lock_init(&emu->voice_lock);
	spin_lock_init(&emu->synth_lock);
	spin_lock_init(&emu->memblk_lock);
+24 −21
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL");
 */
static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
{
	struct snd_emux *emu;
	struct snd_emux *emux;
	struct snd_emu10k1 *hw;
	struct snd_emu10k1_synth_arg *arg;
	unsigned long flags;
@@ -46,53 +46,56 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
	else if (arg->max_voices > 64)
		arg->max_voices = 64;

	if (snd_emux_new(&emu) < 0)
	if (snd_emux_new(&emux) < 0)
		return -ENOMEM;

	snd_emu10k1_ops_setup(emu);
	emu->hw = hw = arg->hwptr;
	emu->max_voices = arg->max_voices;
	emu->num_ports = arg->seq_ports;
	emu->pitch_shift = -501;
	emu->memhdr = hw->memhdr;
	emu->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; /* maximum two ports */
	emu->midi_devidx = hw->audigy ? 2 : 1; /* audigy has two external midis */
	emu->linear_panning = 0;
	emu->hwdep_idx = 2; /* FIXED */

	if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) {
		snd_emux_free(emu);
	snd_emu10k1_ops_setup(emux);
	hw = arg->hwptr;
	emux->hw = hw;
	emux->max_voices = arg->max_voices;
	emux->num_ports = arg->seq_ports;
	emux->pitch_shift = -501;
	emux->memhdr = hw->memhdr;
	/* maximum two ports */
	emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2;
	/* audigy has two external midis */
	emux->midi_devidx = hw->audigy ? 2 : 1;
	emux->linear_panning = 0;
	emux->hwdep_idx = 2; /* FIXED */

	if (snd_emux_register(emux, dev->card, arg->index, "Emu10k1") < 0) {
		snd_emux_free(emux);
		return -ENOMEM;
	}

	spin_lock_irqsave(&hw->voice_lock, flags);
	hw->synth = emu;
	hw->synth = emux;
	hw->get_synth_voice = snd_emu10k1_synth_get_voice;
	spin_unlock_irqrestore(&hw->voice_lock, flags);

	dev->driver_data = emu;
	dev->driver_data = emux;

	return 0;
}

static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev)
{
	struct snd_emux *emu;
	struct snd_emux *emux;
	struct snd_emu10k1 *hw;
	unsigned long flags;

	if (dev->driver_data == NULL)
		return 0; /* not registered actually */

	emu = dev->driver_data;
	emux = dev->driver_data;

	hw = emu->hw;
	hw = emux->hw;
	spin_lock_irqsave(&hw->voice_lock, flags);
	hw->synth = NULL;
	hw->get_synth_voice = NULL;
	spin_unlock_irqrestore(&hw->voice_lock, flags);

	snd_emux_free(emu);
	snd_emux_free(emux);
	return 0;
}

+37 −15
Original line number Diff line number Diff line
@@ -70,6 +70,11 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
	unsigned long flags;
	unsigned int mask;

	if (!emu) {
		snd_printk(KERN_ERR "ptr_write: emu is null!\n");
		dump_stack();
		return;
	}
	mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
	regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);

@@ -134,15 +139,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
	unsigned int reset, set;
	unsigned int reg, tmp;
	int n, result;
	int err = 0;

	/* This function is not re-entrant, so protect against it. */
	spin_lock(&emu->spi_lock);
	if (emu->card_capabilities->ca0108_chip)
		reg = 0x3c; /* PTR20, reg 0x3c */
	else {
		/* For other chip types the SPI register
		 * is currently unknown. */
		return 1;
		err = 1;
		goto spi_write_exit;
	}
	if (data > 0xffff) {
		/* Only 16bit values allowed */
		err = 1;
		goto spi_write_exit;
	}
	if (data > 0xffff) /* Only 16bit values allowed */
		return 1;

	tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
	reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
@@ -160,11 +173,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
			break;
		}
	}
	if (result) /* Timed out */
		return 1;
	if (result) {
		/* Timed out */
		err = 1;
		goto spi_write_exit;
	}
	snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
	tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
	return 0;
	err = 0;
spi_write_exit:
	spin_unlock(&emu->spi_lock);
	return err;
}

/* The ADC does not support i2c read, so only write is implemented */
@@ -176,15 +195,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
	int timeout = 0;
	int status;
	int retry;
	int err = 0;

	if ((reg > 0x7f) || (value > 0x1ff)) {
		snd_printk(KERN_ERR "i2c_write: invalid values.\n");
		return -EINVAL;
	}

	/* This function is not re-entrant, so protect against it. */
	spin_lock(&emu->i2c_lock);

	tmp = reg << 25 | value << 16;
	// snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
	/* Not sure what this I2C channel controls. */
	/* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */

	/* This controls the I2C connected to the WM8775 ADC Codec */
	snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
@@ -192,17 +213,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,

	for (retry = 0; retry < 10; retry++) {
		/* Send the data to i2c */
		//tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
		//tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
		tmp = 0;
		tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
		snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);

		/* Wait till the transaction ends */
		while (1) {
			udelay(10);
			mdelay(1);
			status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
                	// snd_printk("I2C:status=0x%x\n", status);
			timeout++;
			if ((status & I2C_A_ADC_START) == 0)
				break;
@@ -219,10 +237,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,

	if (retry == 10) {
		snd_printk(KERN_ERR "Writing to ADC failed!\n");
		return -EINVAL;
		snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
			status, reg, value);
		/* dump_stack(); */
		err = -EINVAL;
	}
    
    	return 0;
	spin_unlock(&emu->i2c_lock);
	return err;
}

int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
Loading