Ejemplo n.º 1
0
int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode)
{
	int fd, ver;
	char filename[sizeof(SNDRV_FILE_CONTROL) + 10];
	int fmode;
	snd_ctl_t *ctl;
	snd_ctl_hw_t *hw;
	int err;

	*handle = NULL;	

	assert(card >= 0 && card < 32);
	sprintf(filename, SNDRV_FILE_CONTROL, card);
	if (mode & SND_CTL_READONLY)
		fmode = O_RDONLY;
	else
		fmode = O_RDWR;
	if (mode & SND_CTL_NONBLOCK)
		fmode |= O_NONBLOCK;
	if (mode & SND_CTL_ASYNC)
		fmode |= O_ASYNC;
	fd = snd_open_device(filename, fmode);
	if (fd < 0) {
		snd_card_load(card);
		fd = snd_open_device(filename, fmode);
		if (fd < 0)
			return -errno;
	}
#if 0
	/*
	 * this is bogus, an application have to care about open filedescriptors
	 */
	if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
		SYSERR("fcntl FD_CLOEXEC failed");
		err = -errno;
		close(fd);
		return err;
	}
#endif
	if (ioctl(fd, SNDRV_CTL_IOCTL_PVERSION, &ver) < 0) {
		err = -errno;
		close(fd);
		return err;
	}
	if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_CTL_VERSION_MAX)) {
		close(fd);
		return -SND_ERROR_INCOMPATIBLE_VERSION;
	}
	hw = calloc(1, sizeof(snd_ctl_hw_t));
	if (hw == NULL) {
		close(fd);
		return -ENOMEM;
	}
	hw->card = card;
	hw->fd = fd;

	err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name);
	if (err < 0) {
		close(fd);
		free(hw);
	}
	ctl->ops = &snd_ctl_hw_ops;
	ctl->private_data = hw;
	ctl->poll_fd = fd;
	*handle = ctl;
	return 0;
}
int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
{
	unsigned int idx, num_emphs;
	struct snd_kcontrol *ctl;
	int err;

	ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
	if (! ctl)
		return -ENOMEM;

	for (idx = 0; idx < ak->num_dacs; ++idx) {
		memset(ctl, 0, sizeof(*ctl));
		strcpy(ctl->id.name, "DAC Volume");
		ctl->id.index = idx + ak->idx_offset * 2;
		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
		ctl->count = 1;
		ctl->info = snd_akm4xxx_volume_info;
		ctl->get = snd_akm4xxx_volume_get;
		ctl->put = snd_akm4xxx_volume_put;
		switch (ak->type) {
		case SND_AK4524:
			ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
			break;
		case SND_AK4528:
			ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
			break;
		case SND_AK4529: {
			int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
			ctl->private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
			break;
		}
		case SND_AK4355:
			ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
			break;
		case SND_AK4358:
			if (idx >= 6)
				ctl->private_value = AK_COMPOSE(0, idx + 5, 0, 255); /* register 4-9, chip #0 only */
			else
				ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
			break;
		case SND_AK4381:
			ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
			break;
		default:
			err = -EINVAL;
			goto __error;
		}
		ctl->private_data = ak;
		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
			goto __error;
	}
	for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
		memset(ctl, 0, sizeof(*ctl));
		strcpy(ctl->id.name, "ADC Volume");
		ctl->id.index = idx + ak->idx_offset * 2;
		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
		ctl->count = 1;
		ctl->info = snd_akm4xxx_volume_info;
		ctl->get = snd_akm4xxx_volume_get;
		ctl->put = snd_akm4xxx_volume_put;
		ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
		ctl->private_data = ak;
		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
			goto __error;

		memset(ctl, 0, sizeof(*ctl));
		strcpy(ctl->id.name, "IPGA Analog Capture Volume");
		ctl->id.index = idx + ak->idx_offset * 2;
		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
		ctl->count = 1;
		ctl->info = snd_akm4xxx_ipga_gain_info;
		ctl->get = snd_akm4xxx_ipga_gain_get;
		ctl->put = snd_akm4xxx_ipga_gain_put;
		ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
		ctl->private_data = ak;
		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
			goto __error;
	}
	if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
		num_emphs = 1;
	else
		num_emphs = ak->num_dacs / 2;
	for (idx = 0; idx < num_emphs; idx++) {
		memset(ctl, 0, sizeof(*ctl));
		strcpy(ctl->id.name, "Deemphasis");
		ctl->id.index = idx + ak->idx_offset;
		ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
		ctl->count = 1;
		ctl->info = snd_akm4xxx_deemphasis_info;
		ctl->get = snd_akm4xxx_deemphasis_get;
		ctl->put = snd_akm4xxx_deemphasis_put;
		switch (ak->type) {
		case SND_AK4524:
		case SND_AK4528:
			ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
			break;
		case SND_AK4529: {
			int shift = idx == 3 ? 6 : (2 - idx) * 2;
			ctl->private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
			break;
		}
		case SND_AK4355:
		case SND_AK4358:
			ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
			break;
		case SND_AK4381:
			ctl->private_value = AK_COMPOSE(idx, 1, 1, 0);
			break;
		}
		ctl->private_data = ak;
		if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
			goto __error;
	}
	err = 0;

 __error:
	kfree(ctl);
	return err;
}
int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode)
{
	int fd, ver;
	char filename[sizeof(SNDRV_FILE_CONTROL) + 10];
	int fmode;
	snd_ctl_t *ctl;
	snd_ctl_hw_t *hw;
	int err;

	*handle = NULL;	

	if (CHECK_SANITY(card < 0 || card >= 32)) {
		SNDMSG("Invalid card index %d", card);
		return -EINVAL;
	}
	sprintf(filename, SNDRV_FILE_CONTROL, card);
	if (mode & SND_CTL_READONLY)
		fmode = O_RDONLY;
	else
		fmode = O_RDWR;
	if (mode & SND_CTL_NONBLOCK)
		fmode |= O_NONBLOCK;
	if (mode & SND_CTL_ASYNC)
		fmode |= O_ASYNC;
	fd = snd_open_device(filename, fmode);
	if (fd < 0) {
		snd_card_load(card);
		fd = snd_open_device(filename, fmode);
		if (fd < 0)
			return -errno;
	}
	if (ioctl(fd, SNDRV_CTL_IOCTL_PVERSION, &ver) < 0) {
		err = -errno;
		close(fd);
		return err;
	}
	if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_CTL_VERSION_MAX)) {
		close(fd);
		return -SND_ERROR_INCOMPATIBLE_VERSION;
	}
	hw = calloc(1, sizeof(snd_ctl_hw_t));
	if (hw == NULL) {
		close(fd);
		return -ENOMEM;
	}
	hw->card = card;
	hw->fd = fd;
	hw->protocol = ver;

	err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name);
	if (err < 0) {
		close(fd);
		free(hw);
		return err;
	}
	ctl->ops = &snd_ctl_hw_ops;
	ctl->private_data = hw;
	ctl->poll_fd = fd;
	*handle = ctl;
	return 0;
}