static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip,
				    int aes_idx, unsigned char aes_bits)
{
	int i, err, cmd;
	unsigned char new_bits = aes_bits;
	unsigned char old_bits = chip->aes_bits[aes_idx];
	struct pcxhr_rmh rmh;

	for (i = 0; i < 8; i++) {
		if ((old_bits & 0x01) != (new_bits & 0x01)) {
			cmd = chip->chip_idx & 0x03;      
			if (chip->chip_idx > 3)
				
				cmd |= 1 << 22;
			cmd |= ((aes_idx << 3) + i) << 2; 
			cmd |= (new_bits & 0x01) << 23;   
			pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
			rmh.cmd[0] |= IO_NUM_REG_CUER;
			rmh.cmd[1] = cmd;
			rmh.cmd_len = 2;
			snd_printdd("write iec958 AES %d byte %d bit %d (cmd %x)\n",
				    chip->chip_idx, aes_idx, i, cmd);
			err = pcxhr_send_msg(chip->mgr, &rmh);
			if (err)
				return err;
		}
		old_bits >>= 1;
		new_bits >>= 1;
	}
	chip->aes_bits[aes_idx] = aes_bits;
	return 0;
}
static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
{
	struct pcxhr_rmh rmh;
	int capture_mask = 0;
	int playback_mask = 0;
	int err = 0;

	if (pipe->is_capture)
		capture_mask  = (1 << pipe->first_audio);
	else
		playback_mask = (1 << pipe->first_audio);

	/* stop one pipe */
	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
	if (err < 0)
		snd_printk(KERN_ERR "error stopping pipe!\n");
	/* release the pipe */
	pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
	pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0);
	err = pcxhr_send_msg(mgr, &rmh);
	if (err < 0)
		snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err);
	pipe->status = PCXHR_PIPE_UNDEFINED;
	return err;
}
static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip,
					   int is_capture, int channel)
{
	int err, vol;
	struct pcxhr_rmh rmh;

	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
	if (is_capture) {
		rmh.cmd[0] |= IO_NUM_REG_IN_ANA_LEVEL;
		rmh.cmd[2] = chip->analog_capture_volume[channel];
	} else {
		rmh.cmd[0] |= IO_NUM_REG_OUT_ANA_LEVEL;
		if (chip->analog_playback_active[channel])
			vol = chip->analog_playback_volume[channel];
		else
			vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN;
		
		rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol;
	}
	rmh.cmd[1]  = 1 << ((2 * chip->chip_idx) + channel);	
	rmh.cmd_len = 3;
	err = pcxhr_send_msg(chip->mgr, &rmh);
	if (err < 0) {
		snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)"
			   " is_capture(%d) err(%x)\n",
			   chip->chip_idx, is_capture, err);
		return -EINVAL;
	}
	return 0;
}
static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx)
{
	int err;
	struct pcxhr_rmh rmh;
	struct pcxhr_pipe *pipe = &chip->playback_pipe;
	int left, right;

	if (chip->digital_playback_active[idx][0])
		left = chip->digital_playback_volume[idx][0];
	else
		left = PCXHR_DIGITAL_LEVEL_MIN;
	if (chip->digital_playback_active[idx][1])
		right = chip->digital_playback_volume[idx][1];
	else
		right = PCXHR_DIGITAL_LEVEL_MIN;

	pcxhr_init_rmh(&rmh, CMD_STREAM_OUT_LEVEL_ADJUST);
	
	pcxhr_set_pipe_cmd_params(&rmh, 0, pipe->first_audio, 0, 1<<idx);
	
	rmh.cmd[0] |= MORE_THAN_ONE_STREAM_LEVEL;
	rmh.cmd[2]  = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_1_MASK;
	rmh.cmd[2] |= (left << 10);
	rmh.cmd[3]  = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_2_MASK;
	rmh.cmd[3] |= right;
	rmh.cmd_len = 4;

	err = pcxhr_send_msg(chip->mgr, &rmh);
	if (err < 0) {
		snd_printk(KERN_DEBUG "error update_playback_stream_level "
			   "card(%d) err(%x)\n", chip->chip_idx, err);
		return -EINVAL;
	}
	return 0;
}
/*
 *  allocate a playback/capture pipe (pcmp0/pcmc0)
 */
static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe,
				    int is_capture, int pin)
{
	int stream_count, audio_count;
	int err;
	struct pcxhr_rmh rmh;

	if (is_capture) {
		stream_count = 1;
		if (mgr->mono_capture)
			audio_count = 1;
		else
			audio_count = 2;
	} else {
		stream_count = PCXHR_PLAYBACK_STREAMS;
		audio_count = 2;	/* always stereo */
	}
	snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p');
	pipe->is_capture = is_capture;
	pipe->first_audio = pin;
	/* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */
	pcxhr_init_rmh(&rmh, CMD_RES_PIPE);
	pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count); 
	err = pcxhr_send_msg(mgr, &rmh);
	if (err < 0) {
		snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err );
		return err;
	}
	pipe->status = PCXHR_PIPE_DEFINED;

	return 0;
}
Exemple #6
0
static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip,
				    int aes_idx, unsigned char aes_bits)
{
	int i, err, cmd;
	unsigned char new_bits = aes_bits;
	unsigned char old_bits = chip->aes_bits[aes_idx];
	struct pcxhr_rmh rmh;

	for (i = 0; i < 8; i++) {
		if ((old_bits & 0x01) != (new_bits & 0x01)) {
			cmd = chip->chip_idx & 0x03;      /* chip index 0..3 */
			if (chip->chip_idx > 3)
				/* new bit used if chip_idx>3 (PCX1222HR) */
				cmd |= 1 << 22;
			cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */
			cmd |= (new_bits & 0x01) << 23;   /* add bit value */
			pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
			rmh.cmd[0] |= IO_NUM_REG_CUER;
			rmh.cmd[1] = cmd;
			rmh.cmd_len = 2;
			dev_dbg(chip->card->dev,
				"write iec958 AES %d byte %d bit %d (cmd %x)\n",
				    chip->chip_idx, aes_idx, i, cmd);
			err = pcxhr_send_msg(chip->mgr, &rmh);
			if (err)
				return err;
		}
		old_bits >>= 1;
		new_bits >>= 1;
	}
	chip->aes_bits[aes_idx] = aes_bits;
	return 0;
}
Exemple #7
0
static int pcxhr_set_audio_source(struct snd_pcxhr* chip)
{
    struct pcxhr_rmh rmh;
    unsigned int mask, reg;
    unsigned int codec;
    int err, use_src, changed;

    switch (chip->chip_idx) {
    case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break;
    case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break;
    case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break;
    case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break;
    default: return -EINVAL;
    }
    reg = 0;    /* audio source from analog plug */
    use_src = 0;    /* do not activate codec SRC */

    if (chip->audio_capture_source != 0) {
        reg = mask;    /* audio source from digital plug */
        if (chip->audio_capture_source == 2)
            use_src = 1;
    }
    /* set the input source */
    pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed);
    /* resync them (otherwise channel inversion possible) */
    if (changed) {
        pcxhr_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS);
        rmh.cmd[0] |= (1 << chip->chip_idx);
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err)
            return err;
    }
    pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);    /* set codec SRC on off */
    rmh.cmd_len = 3;
    rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
    rmh.cmd[1] = codec;
    rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54);
    err = pcxhr_send_msg(chip->mgr, &rmh);
    if(err)
        return err;
    rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49);
    err = pcxhr_send_msg(chip->mgr, &rmh);
    return err;
}
Exemple #8
0
static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip,
					 int capture, int channel)
{
	int err;
	struct pcxhr_rmh rmh;
	struct pcxhr_pipe *pipe;

	if (capture)
		pipe = &chip->capture_pipe[0];
	else
		pipe = &chip->playback_pipe;

	pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST);
	/* add channel mask */
	pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0,
				  1 << (channel + pipe->first_audio));
	/* TODO : if mask (3 << pipe->first_audio) is used, left and right
	 * channel will be programmed to the same params */
	if (capture) {
		rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL;
		/* VALID_AUDIO_IO_MUTE_LEVEL not yet handled
		 * (capture pipe level) */
		rmh.cmd[2] = chip->digital_capture_volume[channel];
	} else {
		rmh.cmd[0] |=	VALID_AUDIO_IO_MONITOR_LEVEL |
				VALID_AUDIO_IO_MUTE_MONITOR_1;
		/* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL
		 * not yet handled (playback pipe level)
		 */
		rmh.cmd[2] = chip->monitoring_volume[channel] << 10;
		if (chip->monitoring_active[channel] == 0)
			rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1;
	}
	rmh.cmd_len = 3;

	err = pcxhr_send_msg(chip->mgr, &rmh);
	if (err < 0) {
		dev_dbg(chip->card->dev,
			"error update_audio_level(%d) err=%x\n",
			   chip->chip_idx, err);
		return -EINVAL;
	}
	return 0;
}
void pcxhr_reset_board(struct pcxhr_mgr *mgr)
{
	struct pcxhr_rmh rmh;

	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
		/* mute outputs */
		/* a read to IO_NUM_REG_MUTE_OUT register unmutes! */
		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
		rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
		pcxhr_send_msg(mgr, &rmh);
		/* mute inputs */
		pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL);
	}
	/* reset pcxhr dsp */
	if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
		pcxhr_reset_dsp(mgr);
	/* reset second xilinx */
	if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX))
		pcxhr_reset_xilinx_com(mgr);
	return;
}
Exemple #10
0
static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits)
{
    int i, err;
    unsigned char temp;
    struct pcxhr_rmh rmh;

    pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
    rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
    switch (chip->chip_idx) {
    case 0:    rmh.cmd[1] = CS8420_01_CS; break;    /* use CS8416_01_CS for AES SYNC plug */
    case 1:    rmh.cmd[1] = CS8420_23_CS; break;
    case 2:    rmh.cmd[1] = CS8420_45_CS; break;
    case 3:    rmh.cmd[1] = CS8420_67_CS; break;
    default: return -EINVAL;
    }
    switch (aes_idx) {
    case 0:    rmh.cmd[2] = CS8420_CSB0; break;    /* use CS8416_CSBx for AES SYNC plug */
    case 1:    rmh.cmd[2] = CS8420_CSB1; break;
    case 2:    rmh.cmd[2] = CS8420_CSB2; break;
    case 3:    rmh.cmd[2] = CS8420_CSB3; break;
    case 4:    rmh.cmd[2] = CS8420_CSB4; break;
    default: return -EINVAL;
    }
    rmh.cmd[1] &= 0x0fffff;            /* size and code the chip id for the fpga */
    rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI;    /* chip signature + map for spi read */
    rmh.cmd_len = 3;
    err = pcxhr_send_msg(chip->mgr, &rmh);
    if (err)
        return err;
    temp = 0;
    for (i = 0; i < 8; i++) {
        /* attention : reversed bit order (not with CS8416_01_CS) */
        temp <<= 1;
        if (rmh.stat[1] & (1 << i))
            temp |= 1;
    }
    snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp);
    *aes_bits = temp;
    return 0;
}
static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip,
					 int capture, int channel)
{
	int err;
	struct pcxhr_rmh rmh;
	struct pcxhr_pipe *pipe;

	if (capture)
		pipe = &chip->capture_pipe[0];
	else
		pipe = &chip->playback_pipe;

	pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST);
	
	pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0,
				  1 << (channel + pipe->first_audio));
	if (capture) {
		rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL;
		rmh.cmd[2] = chip->digital_capture_volume[channel];
	} else {
		rmh.cmd[0] |=	VALID_AUDIO_IO_MONITOR_LEVEL |
				VALID_AUDIO_IO_MUTE_MONITOR_1;
		rmh.cmd[2] = chip->monitoring_volume[channel] << 10;
		if (chip->monitoring_active[channel] == 0)
			rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1;
	}
	rmh.cmd_len = 3;

	err = pcxhr_send_msg(chip->mgr, &rmh);
	if (err < 0) {
		snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n",
			   chip->chip_idx, err);
		return -EINVAL;
	}
	return 0;
}
static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip,
				     int aes_idx, unsigned char *aes_bits)
{
	int i, err;
	unsigned char temp;
	struct pcxhr_rmh rmh;

	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
	rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
	switch (chip->chip_idx) {
	  
	case 0:	rmh.cmd[1] = CS8420_01_CS; break;
	case 1:	rmh.cmd[1] = CS8420_23_CS; break;
	case 2:	rmh.cmd[1] = CS8420_45_CS; break;
	case 3:	rmh.cmd[1] = CS8420_67_CS; break;
	default: return -EINVAL;
	}
	if (chip->mgr->board_aes_in_192k) {
		switch (aes_idx) {
		case 0:	rmh.cmd[2] = CS8416_CSB0; break;
		case 1:	rmh.cmd[2] = CS8416_CSB1; break;
		case 2:	rmh.cmd[2] = CS8416_CSB2; break;
		case 3:	rmh.cmd[2] = CS8416_CSB3; break;
		case 4:	rmh.cmd[2] = CS8416_CSB4; break;
		default: return -EINVAL;
		}
	} else {
		switch (aes_idx) {
		  
		case 0:	rmh.cmd[2] = CS8420_CSB0; break;
		case 1:	rmh.cmd[2] = CS8420_CSB1; break;
		case 2:	rmh.cmd[2] = CS8420_CSB2; break;
		case 3:	rmh.cmd[2] = CS8420_CSB3; break;
		case 4:	rmh.cmd[2] = CS8420_CSB4; break;
		default: return -EINVAL;
		}
	}
	
	rmh.cmd[1] &= 0x0fffff;
	
	rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI;
	rmh.cmd_len = 3;
	err = pcxhr_send_msg(chip->mgr, &rmh);
	if (err)
		return err;

	if (chip->mgr->board_aes_in_192k) {
		temp = (unsigned char)rmh.stat[1];
	} else {
		temp = 0;
		
		for (i = 0; i < 8; i++) {
			temp <<= 1;
			if (rmh.stat[1] & (1 << i))
				temp |= 1;
		}
	}
	snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
		    chip->chip_idx, aes_idx, temp);
	*aes_bits = temp;
	return 0;
}
static int pcxhr_set_audio_source(struct snd_pcxhr* chip)
{
	struct pcxhr_rmh rmh;
	unsigned int mask, reg;
	unsigned int codec;
	int err, changed;

	switch (chip->chip_idx) {
	case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break;
	case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break;
	case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break;
	case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break;
	default: return -EINVAL;
	}
	if (chip->audio_capture_source != 0) {
		reg = mask;	
	} else {
		reg = 0;	
	}
	
	pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed);
	
	if (changed) {
		pcxhr_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS);
		rmh.cmd[0] |= (1 << chip->chip_idx);
		err = pcxhr_send_msg(chip->mgr, &rmh);
		if (err)
			return err;
	}
	if (chip->mgr->board_aes_in_192k) {
		int i;
		unsigned int src_config = 0xC0;
		
		for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) {
			if (chip->mgr->chip[i]->audio_capture_source == 2)
				src_config |= (1 << (3 - i));
		}
		
		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
		rmh.cmd_len = 2;
		rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC;
		rmh.cmd[1] = src_config;
		err = pcxhr_send_msg(chip->mgr, &rmh);
	} else {
		int use_src = 0;
		if (chip->audio_capture_source == 2)
			use_src = 1;
		
		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
		rmh.cmd_len = 3;
		rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
		rmh.cmd[1] = codec;
		rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) |
			      (use_src ? 0x41 : 0x54));
		err = pcxhr_send_msg(chip->mgr, &rmh);
		if (err)
			return err;
		rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) |
			      (use_src ? 0x41 : 0x49));
		err = pcxhr_send_msg(chip->mgr, &rmh);
	}
	return err;
}
static int pcxhr_init_board(struct pcxhr_mgr *mgr)
{
	int err;
	struct pcxhr_rmh rmh;
	int card_streams;

	/* calc the number of all streams used */
	if (mgr->mono_capture)
		card_streams = mgr->capture_chips * 2;
	else
		card_streams = mgr->capture_chips;
	card_streams += mgr->playback_chips * PCXHR_PLAYBACK_STREAMS;

	/* enable interrupts */
	pcxhr_enable_dsp(mgr);

	pcxhr_init_rmh(&rmh, CMD_SUPPORTED);
	err = pcxhr_send_msg(mgr, &rmh);
	if (err)
		return err;
	/* test 8 or 12 phys out */
	snd_assert((rmh.stat[0] & MASK_FIRST_FIELD) == mgr->playback_chips*2,
		   return -EINVAL);
	/* test 8 or 2 phys in */
	snd_assert(((rmh.stat[0] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD) ==
		   mgr->capture_chips * 2, return -EINVAL);
	/* test max nb substream per board */
	snd_assert((rmh.stat[1] & 0x5F) >= card_streams, return -EINVAL);
	/* test max nb substream per pipe */
	snd_assert(((rmh.stat[1]>>7)&0x5F) >= PCXHR_PLAYBACK_STREAMS, return -EINVAL);

	pcxhr_init_rmh(&rmh, CMD_VERSION);
	/* firmware num for DSP */
	rmh.cmd[0] |= mgr->firmware_num;
	/* transfer granularity in samples (should be multiple of 48) */
	rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY;
	rmh.cmd_len = 2;
	err = pcxhr_send_msg(mgr, &rmh);
	if (err)
		return err;
	snd_printdd("PCXHR DSP version is %d.%d.%d\n",
		    (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
	mgr->dsp_version = rmh.stat[0];

	/* get options */
	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
	rmh.cmd[0] |= IO_NUM_REG_STATUS;
	rmh.cmd[1]  = REG_STATUS_OPTIONS;
	rmh.cmd_len = 2;
	err = pcxhr_send_msg(mgr, &rmh);
	if (err)
		return err;

	if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD)
		mgr->board_has_analog = 1;	/* analog addon board available */
	else
		/* analog addon board not available -> no support for instance */
		return -EINVAL;	

	/* unmute inputs */
	err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
					  REG_CONT_UNMUTE_INPUTS, NULL);
	if (err)
		return err;
	/* unmute outputs */
	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */
	rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
	err = pcxhr_send_msg(mgr, &rmh);
	return err;
}