From 4c0c0df1365f75cb00eee32162ec538ad279f739 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 20 Jan 2005 22:13:15 +0100 Subject: [ALSA] AK4117 code - fixed cosmetic typos AK4117 receiver Signed-off-by: Jaroslav Kysela --- include/sound/ak4117.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/sound/ak4117.h b/include/sound/ak4117.h index 3137755e6672..9e1dab17c33e 100644 --- a/include/sound/ak4117.h +++ b/include/sound/ak4117.h @@ -106,7 +106,7 @@ #define AK4117_DIF_24L (AK4117_DIF2) /* STDO: 24-bit, left justified */ #define AK4117_DIF_24I2S (AK4117_DIF2|AK4117_DIF0) /* STDO: I2S */ -/* AK4117_REG_INT0_MASK & AK4117_INT1_MASK */ +/* AK4117_REG_INT0_MASK & AK4117_REG_INT1_MASK */ #define AK4117_MULK (1<<7) /* mask enable for UNLOCK bit */ #define AK4117_MPAR (1<<6) /* mask enable for PAR bit */ #define AK4117_MAUTO (1<<5) /* mask enable for AUTO bit */ @@ -181,8 +181,8 @@ struct ak4117 { int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write, unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117); -void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val); -void snd_ak4117_reinit(ak4117_t *chip); +void snd_ak4117_reg_write(ak4117_t *ak4117, unsigned char reg, unsigned char mask, unsigned char val); +void snd_ak4117_reinit(ak4117_t *ak4117); int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *capture_substream); int snd_ak4117_external_rate(ak4117_t *ak4117); int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags); -- cgit v1.2.3 From 9f25159b8b8c3edc8c8348dd12ffce187866c06b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 20 Jan 2005 22:25:19 +0100 Subject: [ALSA] unlocked/compat_ioctl rewrite for control API Control Midlevel ioctl handler for control API is rewritten using unlocked/compat_ioctl. The 32bit wrapper is merged to the core module. Added a new register/unregister function for compat control ioctls. Signed-off-by: Takashi Iwai --- include/sound/control.h | 7 + sound/core/control.c | 176 ++++++++++--------- sound/core/control_compat.c | 412 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 514 insertions(+), 81 deletions(-) create mode 100644 sound/core/control_compat.c (limited to 'include') diff --git a/include/sound/control.h b/include/sound/control.h index 678bcb275d88..7b9444cd02f4 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -119,6 +119,13 @@ int snd_ctl_create(snd_card_t *card); int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn); int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn); +#ifdef CONFIG_COMPAT +int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn); +int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn); +#else +#define snd_ctl_register_ioctl_compat(fcn) +#define snd_ctl_unregister_ioctl_compat(fcn) +#endif int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control); int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_value_t *control); diff --git a/sound/core/control.c b/sound/core/control.c index 91ecc3fbd357..1080098512c7 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -43,6 +43,9 @@ typedef struct _snd_kctl_ioctl { static DECLARE_RWSEM(snd_ioctl_rwsem); static LIST_HEAD(snd_control_ioctls); +#ifdef CONFIG_COMPAT +static LIST_HEAD(snd_control_compat_ioctls); +#endif static int snd_ctl_open(struct inode *inode, struct file *file) { @@ -595,43 +598,51 @@ static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list return 0; } -static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info) +static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info) { snd_card_t *card = ctl->card; - snd_ctl_elem_info_t info; snd_kcontrol_t *kctl; snd_kcontrol_volatile_t *vd; unsigned int index_offset; int result; - if (copy_from_user(&info, _info, sizeof(info))) - return -EFAULT; down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &info.id); + kctl = snd_ctl_find_id(card, &info->id); if (kctl == NULL) { up_read(&card->controls_rwsem); return -ENOENT; } #ifdef CONFIG_SND_DEBUG - info.access = 0; + info->access = 0; #endif - result = kctl->info(kctl, &info); + result = kctl->info(kctl, info); if (result >= 0) { - snd_assert(info.access == 0, ); - index_offset = snd_ctl_get_ioff(kctl, &info.id); + snd_assert(info->access == 0, ); + index_offset = snd_ctl_get_ioff(kctl, &info->id); vd = &kctl->vd[index_offset]; - snd_ctl_build_ioff(&info.id, kctl, index_offset); - info.access = vd->access; + snd_ctl_build_ioff(&info->id, kctl, index_offset); + info->access = vd->access; if (vd->owner) { - info.access |= SNDRV_CTL_ELEM_ACCESS_LOCK; + info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK; if (vd->owner == ctl) - info.access |= SNDRV_CTL_ELEM_ACCESS_OWNER; - info.owner = vd->owner_pid; + info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER; + info->owner = vd->owner_pid; } else { - info.owner = -1; + info->owner = -1; } } up_read(&card->controls_rwsem); + return result; +} + +static int snd_ctl_elem_info_user(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info) +{ + snd_ctl_elem_info_t info; + int result; + + if (copy_from_user(&info, _info, sizeof(info))) + return -EFAULT; + result = snd_ctl_elem_info(ctl, &info); if (result >= 0) if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -816,14 +827,6 @@ static int snd_ctl_elem_user_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t struct user_element *ue = kcontrol->private_data; *uinfo = ue->info; - if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { - uinfo->value.enumerated.items = ue->info.value.enumerated.items; - if (uinfo->value.enumerated.item >= ue->info.value.enumerated.items) - uinfo->value.enumerated.item = 0; - strlcpy(uinfo->value.enumerated.name, - (char *)ue->priv_data + uinfo->value.enumerated.item * 64, - 64); - } return 0; } @@ -851,28 +854,25 @@ static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol) kfree(kcontrol->private_data); } -static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace) +static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int replace) { snd_card_t *card = file->card; - snd_ctl_elem_info_t info; snd_kcontrol_t kctl, *_kctl; unsigned int access; - long private_size, extra_size; + long private_size; struct user_element *ue; int idx, err; if (card->user_ctl_count >= MAX_USER_CONTROLS) return -ENOMEM; - if (copy_from_user(&info, _info, sizeof(info))) - return -EFAULT; - if (info.count > 1024) + if (info->count > 1024) return -EINVAL; - access = info.access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : - (info.access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE)); - info.id.numid = 0; + access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : + (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE)); + info->id.numid = 0; memset(&kctl, 0, sizeof(kctl)); down_write(&card->controls_rwsem); - _kctl = snd_ctl_find_id(card, &info.id); + _kctl = snd_ctl_find_id(card, &info->id); err = 0; if (_kctl) { if (replace) @@ -886,67 +886,50 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_i up_write(&card->controls_rwsem); if (err < 0) return err; - memcpy(&kctl.id, &info.id, sizeof(info.id)); - kctl.count = info.owner ? info.owner : 1; + memcpy(&kctl.id, &info->id, sizeof(info->id)); + kctl.count = info->owner ? info->owner : 1; access |= SNDRV_CTL_ELEM_ACCESS_USER; kctl.info = snd_ctl_elem_user_info; if (access & SNDRV_CTL_ELEM_ACCESS_READ) kctl.get = snd_ctl_elem_user_get; if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) kctl.put = snd_ctl_elem_user_put; - extra_size = 0; - switch (info.type) { + switch (info->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: private_size = sizeof(char); - if (info.count > 128) + if (info->count > 128) return -EINVAL; break; case SNDRV_CTL_ELEM_TYPE_INTEGER: private_size = sizeof(long); - if (info.count > 128) + if (info->count > 128) return -EINVAL; break; case SNDRV_CTL_ELEM_TYPE_INTEGER64: private_size = sizeof(long long); - if (info.count > 64) + if (info->count > 64) return -EINVAL; break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - private_size = sizeof(unsigned int); - if (info.count > 128) - return -EINVAL; - if (info.value.enumerated.items > 128) - return -EINVAL; - extra_size = info.value.enumerated.items * 64; - break; case SNDRV_CTL_ELEM_TYPE_BYTES: private_size = sizeof(unsigned char); - if (info.count > 512) + if (info->count > 512) return -EINVAL; break; case SNDRV_CTL_ELEM_TYPE_IEC958: private_size = sizeof(struct sndrv_aes_iec958); - if (info.count != 1) + if (info->count != 1) return -EINVAL; break; default: return -EINVAL; } - private_size *= info.count; - ue = kcalloc(1, sizeof(struct user_element) + private_size + extra_size, GFP_KERNEL); + private_size *= info->count; + ue = kcalloc(1, sizeof(struct user_element) + private_size, GFP_KERNEL); if (ue == NULL) return -ENOMEM; - ue->info = info; + ue->info = *info; ue->elem_data = (char *)ue + sizeof(ue); ue->elem_data_size = private_size; - if (extra_size) { - ue->priv_data = (char *)ue + sizeof(ue) + private_size; - ue->priv_data_size = extra_size; - if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { - if (copy_from_user(ue->priv_data, *(char __user **)info.value.enumerated.name, extra_size)) - return -EFAULT; - } - } kctl.private_free = snd_ctl_elem_user_free; _kctl = snd_ctl_new(&kctl, access); if (_kctl == NULL) { @@ -969,6 +952,14 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_i return 0; } +static int snd_ctl_elem_add_user(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace) +{ + snd_ctl_elem_info_t info; + if (copy_from_user(&info, _info, sizeof(info))) + return -EFAULT; + return snd_ctl_elem_add(file, &info, replace); +} + static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id) { snd_ctl_elem_id_t id; @@ -1039,8 +1030,7 @@ static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state) } #endif -static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_ctl_file_t *ctl; snd_card_t *card; @@ -1061,7 +1051,7 @@ static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file, case SNDRV_CTL_IOCTL_ELEM_LIST: return snd_ctl_elem_list(ctl->card, argp); case SNDRV_CTL_IOCTL_ELEM_INFO: - return snd_ctl_elem_info(ctl, argp); + return snd_ctl_elem_info_user(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_READ: return snd_ctl_elem_read_user(ctl->card, argp); case SNDRV_CTL_IOCTL_ELEM_WRITE: @@ -1071,7 +1061,7 @@ static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file, case SNDRV_CTL_IOCTL_ELEM_UNLOCK: return snd_ctl_elem_unlock(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_ADD: - return snd_ctl_elem_add(ctl, argp, 0); + return snd_ctl_elem_add_user(ctl, argp, 0); case SNDRV_CTL_IOCTL_ELEM_REPLACE: return snd_ctl_elem_add(ctl, argp, 1); case SNDRV_CTL_IOCTL_ELEM_REMOVE: @@ -1113,17 +1103,6 @@ static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file, return -ENOTTY; } -/* FIXME: need to unlock BKL to allow preemption */ -static int snd_ctl_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int err; - unlock_kernel(); - err = _snd_ctl_ioctl(inode, file, cmd, arg); - lock_kernel(); - return err; -} - static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset) { snd_ctl_file_t *ctl; @@ -1199,7 +1178,7 @@ static unsigned int snd_ctl_poll(struct file *file, poll_table * wait) * register the device-specific control-ioctls. * called from each device manager like pcm.c, hwdep.c, etc. */ -int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn) +static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists) { snd_kctl_ioctl_t *pn; @@ -1208,22 +1187,34 @@ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn) return -ENOMEM; pn->fioctl = fcn; down_write(&snd_ioctl_rwsem); - list_add_tail(&pn->list, &snd_control_ioctls); + list_add_tail(&pn->list, lists); up_write(&snd_ioctl_rwsem); return 0; } +int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn) +{ + return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls); +} + +#ifdef CONFIG_COMPAT +int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn) +{ + return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls); +} +#endif + /* * de-register the device-specific control-ioctls. */ -int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn) +static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists) { struct list_head *list; snd_kctl_ioctl_t *p; snd_runtime_check(fcn != NULL, return -EINVAL); down_write(&snd_ioctl_rwsem); - list_for_each(list, &snd_control_ioctls) { + list_for_each(list, lists) { p = list_entry(list, snd_kctl_ioctl_t, list); if (p->fioctl == fcn) { list_del(&p->list); @@ -1237,6 +1228,19 @@ int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn) return -EINVAL; } +int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn) +{ + return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls); +} + +#ifdef CONFIG_COMPAT +int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn) +{ + return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls); +} + +#endif + static int snd_ctl_fasync(int fd, struct file * file, int on) { snd_ctl_file_t *ctl; @@ -1248,6 +1252,15 @@ static int snd_ctl_fasync(int fd, struct file * file, int on) return 0; } +/* + * ioctl32 compat + */ +#ifdef CONFIG_COMPAT +#include "control_compat.c" +#else +#define snd_ctl_ioctl_compat NULL +#endif + /* * INIT PART */ @@ -1259,7 +1272,8 @@ static struct file_operations snd_ctl_f_ops = .open = snd_ctl_open, .release = snd_ctl_release, .poll = snd_ctl_poll, - .ioctl = snd_ctl_ioctl, + .unlocked_ioctl = snd_ctl_ioctl, + .compat_ioctl = snd_ctl_ioctl_compat, .fasync = snd_ctl_fasync, }; diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c new file mode 100644 index 000000000000..7fdabea4bfc8 --- /dev/null +++ b/sound/core/control_compat.c @@ -0,0 +1,412 @@ +/* + * compat ioctls for control API + * + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* this file included from control.c */ + +#include + +struct sndrv_ctl_elem_list32 { + u32 offset; + u32 space; + u32 used; + u32 count; + u32 pids; + unsigned char reserved[50]; +} /* don't set packed attribute here */; + +static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list32 __user *data32) +{ + struct sndrv_ctl_elem_list __user *data; + compat_caddr_t ptr; + int err; + + data = compat_alloc_user_space(sizeof(*data)); + + /* offset, space, used, count */ + if (copy_in_user(data, data32, 4 * sizeof(u32))) + return -EFAULT; + /* pids */ + if (get_user(ptr, &data32->pids) || + put_user(compat_ptr(ptr), &data->pids)) + return -EFAULT; + err = snd_ctl_elem_list(card, data); + if (err < 0) + return err; + /* copy the result */ + if (copy_in_user(data32, data, 4 * sizeof(u32))) + return -EFAULT; + return 0; +} + +/* + * control element info + * it uses union, so the things are not easy.. + */ + +struct sndrv_ctl_elem_info32 { + struct sndrv_ctl_elem_id id; // the size of struct is same + s32 type; + u32 access; + u32 count; + s32 owner; + union { + struct { + s32 min; + s32 max; + s32 step; + } integer; + struct { + u64 min; + u64 max; + u64 step; + } integer64; + struct { + u32 items; + u32 item; + char name[64]; + } enumerated; + unsigned char reserved[128]; + } value; + unsigned char reserved[64]; +} __attribute__((packed)); + +static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_info32 __user *data32) +{ + struct sndrv_ctl_elem_info *data; + int err; + + data = kcalloc(1, sizeof(*data), GFP_KERNEL); + if (! data) + return -ENOMEM; + + err = -EFAULT; + /* copy id */ + if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) + goto error; + /* we need to copy the item index. + * hope this doesn't break anything.. + */ + if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) + goto error; + err = snd_ctl_elem_info(ctl, data); + if (err < 0) + goto error; + /* restore info to 32bit */ + err = -EFAULT; + /* id, type, access, count */ + if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) || + copy_to_user(&data32->type, &data->type, 3 * sizeof(u32))) + goto error; + if (put_user(data->owner, &data32->owner)) + goto error; + switch (data->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + if (put_user(data->value.integer.min, &data32->value.integer.min) || + put_user(data->value.integer.max, &data32->value.integer.max) || + put_user(data->value.integer.step, &data32->value.integer.step)) + goto error; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + if (copy_to_user(&data32->value.integer64, + &data->value.integer64, + sizeof(data->value.integer64))) + goto error; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + if (copy_to_user(&data32->value.enumerated, + &data->value.enumerated, + sizeof(data->value.enumerated))) + goto error; + break; + default: + break; + } + err = 0; + error: + kfree(data); + return err; +} + +/* read / write */ +struct sndrv_ctl_elem_value32 { + struct sndrv_ctl_elem_id id; + unsigned int indirect; /* bit-field causes misalignment */ + union { + s32 integer[128]; + unsigned char data[512]; +#ifndef CONFIG_X86_64 + s64 integer64[64]; +#endif + } value; + unsigned char reserved[128]; +}; + + +/* get the value type and count of the control */ +static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp) +{ + snd_kcontrol_t *kctl; + snd_ctl_elem_info_t info; + int err; + + down_read(&card->controls_rwsem); + kctl = snd_ctl_find_id(card, id); + if (! kctl) { + up_read(&card->controls_rwsem); + return -ENXIO; + } + info.id = *id; + err = kctl->info(kctl, &info); + up_read(&card->controls_rwsem); + if (err >= 0) { + err = info.type; + *countp = info.count; + } + return err; +} + +static int get_elem_size(int type, int count) +{ + switch (type) { + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + return sizeof(s64) * count; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + return sizeof(int) * count; + case SNDRV_CTL_ELEM_TYPE_BYTES: + return 512; + case SNDRV_CTL_ELEM_TYPE_IEC958: + return sizeof(struct sndrv_aes_iec958); + default: + return -1; + } +} + +static int copy_ctl_value_from_user(snd_card_t *card, + struct sndrv_ctl_elem_value *data, + struct sndrv_ctl_elem_value32 __user *data32, + int *typep, int *countp) +{ + int i, type, count, size; + unsigned int indirect; + + if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) + return -EFAULT; + if (get_user(indirect, &data32->indirect)) + return -EFAULT; + if (indirect) + return -EINVAL; + type = get_ctl_type(card, &data->id, &count); + if (type < 0) + return type; + + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + for (i = 0; i < count; i++) { + int val; + if (get_user(val, &data32->value.integer[i])) + return -EFAULT; + data->value.integer.value[i] = val; + } + } else { + size = get_elem_size(type, count); + if (size < 0) { + printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); + return -EINVAL; + } + if (copy_from_user(data->value.bytes.data, + data32->value.data, size)) + return -EFAULT; + } + + *typep = type; + *countp = count; + return 0; +} + +/* restore the value to 32bit */ +static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32, + struct sndrv_ctl_elem_value *data, + int type, int count) +{ + int i, size; + + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + for (i = 0; i < count; i++) { + int val; + val = data->value.integer.value[i]; + if (put_user(val, &data32->value.integer[i])) + return -EFAULT; + } + } else { + size = get_elem_size(type, count); + if (copy_to_user(data32->value.data, + data->value.bytes.data, size)) + return -EFAULT; + } + return 0; +} + +static int snd_ctl_elem_read_user_compat(snd_card_t *card, + struct sndrv_ctl_elem_value32 __user *data32) +{ + struct sndrv_ctl_elem_value *data; + int err, type, count; + + data = kcalloc(1, sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) + goto error; + if ((err = snd_ctl_elem_read(card, data)) < 0) + goto error; + err = copy_ctl_value_to_user(data32, data, type, count); + error: + kfree(data); + return err; +} + +static int snd_ctl_elem_write_user_compat(snd_ctl_file_t *file, + struct sndrv_ctl_elem_value32 __user *data32) +{ + struct sndrv_ctl_elem_value *data; + int err, type, count; + + data = kcalloc(1, sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + if ((err = copy_ctl_value_from_user(file->card, data, data32, &type, &count)) < 0) + goto error; + if ((err = snd_ctl_elem_write(file->card, file, data)) < 0) + goto error; + err = copy_ctl_value_to_user(data32, data, type, count); + error: + kfree(data); + return err; +} + +/* add or replace a user control */ +static int snd_ctl_elem_add_compat(snd_ctl_file_t *file, + struct sndrv_ctl_elem_info32 __user *data32, + int replace) +{ + struct sndrv_ctl_elem_info *data; + int err; + + data = kcalloc(1, sizeof(*data), GFP_KERNEL); + if (! data) + return -ENOMEM; + + err = -EFAULT; + /* id, type, access, count */ \ + if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || + copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) + goto error; + if (get_user(data->owner, &data32->owner) || + get_user(data->type, &data32->type)) + goto error; + switch (data->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + if (get_user(data->value.integer.min, &data32->value.integer.min) || + get_user(data->value.integer.max, &data32->value.integer.max) || + get_user(data->value.integer.step, &data32->value.integer.step)) + goto error; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + if (copy_from_user(&data->value.integer64, + &data32->value.integer64, + sizeof(data->value.integer64))) + goto error; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + if (copy_from_user(&data->value.enumerated, + &data32->value.enumerated, + sizeof(data->value.enumerated))) + goto error; + break; + default: + break; + } + err = snd_ctl_elem_add(file, data, replace); + error: + kfree(data); + return err; +} + +enum { + SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32), + SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32), + SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32), + SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32), + SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct sndrv_ctl_elem_info32), + SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct sndrv_ctl_elem_info32), +}; + +static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + snd_ctl_file_t *ctl; + struct list_head *list; + void __user *argp = compat_ptr(arg); + int err; + + ctl = file->private_data; + snd_assert(ctl && ctl->card, return -ENXIO); + + switch (cmd) { + case SNDRV_CTL_IOCTL_PVERSION: + case SNDRV_CTL_IOCTL_CARD_INFO: + case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: + case SNDRV_CTL_IOCTL_POWER: + case SNDRV_CTL_IOCTL_POWER_STATE: + case SNDRV_CTL_IOCTL_ELEM_LOCK: + case SNDRV_CTL_IOCTL_ELEM_UNLOCK: + return snd_ctl_ioctl(file, cmd, (unsigned long)argp); + case SNDRV_CTL_IOCTL_ELEM_LIST32: + return snd_ctl_elem_list_compat(ctl->card, argp); + case SNDRV_CTL_IOCTL_ELEM_INFO32: + return snd_ctl_elem_info_compat(ctl, argp); + case SNDRV_CTL_IOCTL_ELEM_READ32: + return snd_ctl_elem_read_user_compat(ctl->card, argp); + case SNDRV_CTL_IOCTL_ELEM_WRITE32: + return snd_ctl_elem_write_user_compat(ctl, argp); + case SNDRV_CTL_IOCTL_ELEM_ADD32: + return snd_ctl_elem_add_compat(ctl, argp, 0); + case SNDRV_CTL_IOCTL_ELEM_REPLACE32: + return snd_ctl_elem_add_compat(ctl, argp, 1); + } + + down_read(&snd_ioctl_rwsem); + list_for_each(list, &snd_control_compat_ioctls) { + snd_kctl_ioctl_t *p = list_entry(list, snd_kctl_ioctl_t, list); + if (p->fioctl) { + err = p->fioctl(ctl->card, ctl, cmd, arg); + if (err != -ENOIOCTLCMD) { + up_read(&snd_ioctl_rwsem); + return err; + } + } + } + up_read(&snd_ioctl_rwsem); + return -ENOIOCTLCMD; +} -- cgit v1.2.3 From 90efff421cb0dbaef98e6b014bae38eaed0f0a40 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 20 Jan 2005 22:28:06 +0100 Subject: [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten using unlocked/compat_ioctl. The 32bit wrapper is merged to the core module. Signed-off-by: Takashi Iwai --- include/sound/hwdep.h | 1 + sound/core/hwdep.c | 25 ++++---- sound/core/hwdep_compat.c | 77 +++++++++++++++++++++++ sound/core/rawmidi.c | 27 ++++---- sound/core/rawmidi_compat.c | 120 ++++++++++++++++++++++++++++++++++++ sound/core/seq/seq_clientmgr.c | 18 +++--- sound/core/seq/seq_compat.c | 137 +++++++++++++++++++++++++++++++++++++++++ sound/core/timer.c | 23 +++---- sound/core/timer_compat.c | 119 +++++++++++++++++++++++++++++++++++ 9 files changed, 496 insertions(+), 51 deletions(-) create mode 100644 sound/core/hwdep_compat.c create mode 100644 sound/core/rawmidi_compat.c create mode 100644 sound/core/seq/seq_compat.c create mode 100644 sound/core/timer_compat.c (limited to 'include') diff --git a/include/sound/hwdep.h b/include/sound/hwdep.h index 4a4cc0167fac..043876348fa1 100644 --- a/include/sound/hwdep.h +++ b/include/sound/hwdep.h @@ -38,6 +38,7 @@ typedef struct _snd_hwdep_ops { int (*release) (snd_hwdep_t * hw, struct file * file); unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait); int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg); + int (*ioctl_compat) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg); int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma); int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status); int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image); diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index cbd8eba6a35a..cb19695c2062 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -232,8 +232,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t __user *_in return 0; } -static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file, - unsigned int cmd, unsigned long arg) +static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg) { snd_hwdep_t *hw = file->private_data; void __user *argp = (void __user *)arg; @@ -252,17 +251,6 @@ static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file, return -ENOTTY; } -/* FIXME: need to unlock BKL to allow preemption */ -static int snd_hwdep_ioctl(struct inode *inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int err; - unlock_kernel(); - err = _snd_hwdep_ioctl(inode, file, cmd, arg); - lock_kernel(); - return err; -} - static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma) { snd_hwdep_t *hw = file->private_data; @@ -315,6 +303,12 @@ static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, return -ENOIOCTLCMD; } +#ifdef CONFIG_COMPAT +#include "hwdep_compat.c" +#else +#define snd_hwdep_ioctl_compat NULL +#endif + /* */ @@ -328,7 +322,8 @@ static struct file_operations snd_hwdep_f_ops = .open = snd_hwdep_open, .release = snd_hwdep_release, .poll = snd_hwdep_poll, - .ioctl = snd_hwdep_ioctl, + .unlocked_ioctl = snd_hwdep_ioctl, + .compat_ioctl = snd_hwdep_ioctl_compat, .mmap = snd_hwdep_mmap, }; @@ -509,12 +504,14 @@ static int __init alsa_hwdep_init(void) } snd_hwdep_proc_entry = entry; snd_ctl_register_ioctl(snd_hwdep_control_ioctl); + snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl); return 0; } static void __exit alsa_hwdep_exit(void) { snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl); + snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl); if (snd_hwdep_proc_entry) { snd_info_unregister(snd_hwdep_proc_entry); snd_hwdep_proc_entry = NULL; diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c new file mode 100644 index 000000000000..6866f423d4b9 --- /dev/null +++ b/sound/core/hwdep_compat.c @@ -0,0 +1,77 @@ +/* + * 32bit -> 64bit ioctl wrapper for hwdep API + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file is included from hwdep.c */ + +#include + +struct sndrv_hwdep_dsp_image32 { + u32 index; + unsigned char name[64]; + u32 image; /* pointer */ + u32 length; + u32 driver_data; +} /* don't set packed attribute here */; + +static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw, + struct sndrv_hwdep_dsp_image32 __user *src) +{ + struct sndrv_hwdep_dsp_image *dst; + compat_caddr_t ptr; + u32 val; + + dst = compat_alloc_user_space(sizeof(*dst)); + + /* index and name */ + if (copy_in_user(dst, src, 4 + 64)) + return -EFAULT; + if (get_user(ptr, &src->image) || + put_user(compat_ptr(ptr), &dst->image)) + return -EFAULT; + if (get_user(val, &src->length) || + put_user(val, &dst->length)) + return -EFAULT; + if (get_user(val, &src->driver_data) || + put_user(val, &dst->driver_data)) + return -EFAULT; + + return snd_hwdep_dsp_load(hw, dst); +} + +enum { + SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32) +}; + +static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg) +{ + snd_hwdep_t *hw = file->private_data; + void __user *argp = compat_ptr(arg); + switch (cmd) { + case SNDRV_HWDEP_IOCTL_PVERSION: + case SNDRV_HWDEP_IOCTL_INFO: + case SNDRV_HWDEP_IOCTL_DSP_STATUS: + return snd_hwdep_ioctl(file, cmd, (unsigned long)argp); + case SNDRV_HWDEP_IOCTL_DSP_LOAD32: + return snd_hwdep_dsp_load_compat(hw, argp); + } + if (hw->ops.ioctl_compat) + return hw->ops.ioctl_compat(hw, file, cmd, arg); + return -ENOIOCTLCMD; +} diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0624ff970cb8..91a4cde430e2 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -673,8 +673,7 @@ static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream, return 0; } -static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_rawmidi_file_t *rfile; void __user *argp = (void __user *)arg; @@ -784,17 +783,6 @@ static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file, return -ENOTTY; } -/* FIXME: need to unlock BKL to allow preemption */ -static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int err; - unlock_kernel(); - err = _snd_rawmidi_ioctl(inode, file, cmd, arg); - lock_kernel(); - return err; -} - static int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, unsigned int cmd, @@ -1277,6 +1265,14 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait) return mask; } +/* + */ +#ifdef CONFIG_COMPAT +#include "rawmidi_compat.c" +#else +#define snd_rawmidi_ioctl_compat NULL +#endif + /* */ @@ -1347,7 +1343,8 @@ static struct file_operations snd_rawmidi_f_ops = .open = snd_rawmidi_open, .release = snd_rawmidi_release, .poll = snd_rawmidi_poll, - .ioctl = snd_rawmidi_ioctl, + .unlocked_ioctl = snd_rawmidi_ioctl, + .compat_ioctl = snd_rawmidi_ioctl_compat, }; static snd_minor_t snd_rawmidi_reg = @@ -1628,6 +1625,7 @@ static int __init alsa_rawmidi_init(void) { snd_ctl_register_ioctl(snd_rawmidi_control_ioctl); + snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl); #ifdef CONFIG_SND_OSSEMUL { int i; /* check device map table */ @@ -1649,6 +1647,7 @@ static int __init alsa_rawmidi_init(void) static void __exit alsa_rawmidi_exit(void) { snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl); + snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl); } module_init(alsa_rawmidi_init) diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c new file mode 100644 index 000000000000..d97631c3f3ad --- /dev/null +++ b/sound/core/rawmidi_compat.c @@ -0,0 +1,120 @@ +/* + * 32bit -> 64bit ioctl wrapper for raw MIDI API + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file included from rawmidi.c */ + +#include + +struct sndrv_rawmidi_params32 { + s32 stream; + u32 buffer_size; + u32 avail_min; + unsigned int no_active_sensing; /* avoid bit-field */ + unsigned char reserved[16]; +} __attribute__((packed)); + +static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile, + struct sndrv_rawmidi_params32 __user *src) +{ + snd_rawmidi_params_t params; + unsigned int val; + + if (rfile->output == NULL) + return -EINVAL; + if (get_user(params.stream, &src->stream) || + get_user(params.buffer_size, &src->buffer_size) || + get_user(params.avail_min, &src->avail_min) || + get_user(val, &src->no_active_sensing)) + return -EFAULT; + params.no_active_sensing = val; + switch (params.stream) { + case SNDRV_RAWMIDI_STREAM_OUTPUT: + return snd_rawmidi_output_params(rfile->output, ¶ms); + case SNDRV_RAWMIDI_STREAM_INPUT: + return snd_rawmidi_input_params(rfile->input, ¶ms); + } + return -EINVAL; +} + +struct sndrv_rawmidi_status32 { + s32 stream; + struct compat_timespec tstamp; + u32 avail; + u32 xruns; + unsigned char reserved[16]; +} __attribute__((packed)); + +static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile, + struct sndrv_rawmidi_status32 __user *src) +{ + int err; + snd_rawmidi_status_t status; + + if (rfile->output == NULL) + return -EINVAL; + if (get_user(status.stream, &src->stream)) + return -EFAULT; + + switch (status.stream) { + case SNDRV_RAWMIDI_STREAM_OUTPUT: + err = snd_rawmidi_output_status(rfile->output, &status); + break; + case SNDRV_RAWMIDI_STREAM_INPUT: + err = snd_rawmidi_input_status(rfile->input, &status); + break; + default: + return -EINVAL; + } + if (err < 0) + return err; + + if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) || + put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) || + put_user(status.avail, &src->avail) || + put_user(status.xruns, &src->xruns)) + return -EFAULT; + + return 0; +} + +enum { + SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32), + SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32), +}; + +static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + snd_rawmidi_file_t *rfile; + void __user *argp = compat_ptr(arg); + + rfile = file->private_data; + switch (cmd) { + case SNDRV_RAWMIDI_IOCTL_PVERSION: + case SNDRV_RAWMIDI_IOCTL_INFO: + case SNDRV_RAWMIDI_IOCTL_DROP: + case SNDRV_RAWMIDI_IOCTL_DRAIN: + return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); + case SNDRV_RAWMIDI_IOCTL_PARAMS32: + return snd_rawmidi_ioctl_params_compat(rfile, argp); + case SNDRV_RAWMIDI_IOCTL_STATUS32: + return snd_rawmidi_ioctl_status_compat(rfile, argp); + } + return -ENOIOCTLCMD; +} diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 4b24a1fbc989..3719d7f98ec8 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2131,21 +2131,20 @@ static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg } -static int snd_seq_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { client_t *client = (client_t *) file->private_data; - int err; snd_assert(client != NULL, return -ENXIO); - /* FIXME: need to unlock BKL to allow preemption */ - unlock_kernel(); - err = snd_seq_do_ioctl(client, cmd, (void __user *) arg); - lock_kernel(); - return err; + return snd_seq_do_ioctl(client, cmd, (void __user *) arg); } +#ifdef CONFIG_COMPAT +#include "seq_compat.c" +#else +#define snd_seq_ioctl_compat NULL +#endif /* -------------------------------------------------------- */ @@ -2462,7 +2461,8 @@ static struct file_operations snd_seq_f_ops = .open = snd_seq_open, .release = snd_seq_release, .poll = snd_seq_poll, - .ioctl = snd_seq_ioctl, + .unlocked_ioctl = snd_seq_ioctl, + .compat_ioctl = snd_seq_ioctl_compat, }; static snd_minor_t snd_seq_reg = diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c new file mode 100644 index 000000000000..902ad8b0c355 --- /dev/null +++ b/sound/core/seq/seq_compat.c @@ -0,0 +1,137 @@ +/* + * 32bit -> 64bit ioctl wrapper for sequencer API + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file included from seq.c */ + +#include + +struct sndrv_seq_port_info32 { + struct sndrv_seq_addr addr; /* client/port numbers */ + char name[64]; /* port name */ + + u32 capability; /* port capability bits */ + u32 type; /* port type bits */ + s32 midi_channels; /* channels per MIDI port */ + s32 midi_voices; /* voices per MIDI port */ + s32 synth_voices; /* voices per SYNTH port */ + + s32 read_use; /* R/O: subscribers for output (from this port) */ + s32 write_use; /* R/O: subscribers for input (to this port) */ + + u32 kernel; /* reserved for kernel use (must be NULL) */ + u32 flags; /* misc. conditioning */ + unsigned char time_queue; /* queue # for timestamping */ + char reserved[59]; /* for future use */ +}; + +static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd, + struct sndrv_seq_port_info32 __user *data32) +{ + int err = -EFAULT; + snd_seq_port_info_t *data; + mm_segment_t fs; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (! data) + return -ENOMEM; + + if (copy_from_user(data, data32, sizeof(*data32)) || + get_user(data->flags, &data32->flags) || + get_user(data->time_queue, &data32->time_queue)) + goto error; + data->kernel = NULL; + + fs = snd_enter_user(); + err = snd_seq_do_ioctl(client, cmd, data); + snd_leave_user(fs); + if (err < 0) + goto error; + + if (copy_to_user(data32, data, sizeof(*data32)) || + put_user(data->flags, &data32->flags) || + put_user(data->time_queue, &data32->time_queue)) + err = -EFAULT; + + error: + kfree(data); + return err; +} + + + +/* + */ + +enum { + SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32), +}; + +static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + client_t *client = (client_t *) file->private_data; + void __user *argp = compat_ptr(arg); + + snd_assert(client != NULL, return -ENXIO); + + switch (cmd) { + case SNDRV_SEQ_IOCTL_PVERSION: + case SNDRV_SEQ_IOCTL_CLIENT_ID: + case SNDRV_SEQ_IOCTL_SYSTEM_INFO: + case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO: + case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO: + case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT: + case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT: + case SNDRV_SEQ_IOCTL_CREATE_QUEUE: + case SNDRV_SEQ_IOCTL_DELETE_QUEUE: + case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO: + case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO: + case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE: + case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS: + case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO: + case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO: + case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER: + case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER: + case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT: + case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT: + case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL: + case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL: + case SNDRV_SEQ_IOCTL_REMOVE_EVENTS: + case SNDRV_SEQ_IOCTL_QUERY_SUBS: + case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION: + case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT: + case SNDRV_SEQ_IOCTL_RUNNING_MODE: + return snd_seq_do_ioctl(client, cmd, argp); + case SNDRV_SEQ_IOCTL_CREATE_PORT32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp); + case SNDRV_SEQ_IOCTL_DELETE_PORT32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp); + case SNDRV_SEQ_IOCTL_GET_PORT_INFO32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp); + case SNDRV_SEQ_IOCTL_SET_PORT_INFO32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp); + case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp); + } + return -ENOIOCTLCMD; +} diff --git a/sound/core/timer.c b/sound/core/timer.c index f5ef7f5be53a..3d8a8a96e0c3 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1653,8 +1653,7 @@ static int snd_timer_user_continue(struct file *file) return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; } -static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_timer_user_t *tu; void __user *argp = (void __user *)arg; @@ -1701,17 +1700,6 @@ static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file, return -ENOTTY; } -/* FIXME: need to unlock BKL to allow preemption */ -static int snd_timer_user_ioctl(struct inode *inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int err; - unlock_kernel(); - err = _snd_timer_user_ioctl(inode, file, cmd, arg); - lock_kernel(); - return err; -} - static int snd_timer_user_fasync(int fd, struct file * file, int on) { snd_timer_user_t *tu; @@ -1803,6 +1791,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) return mask; } +#ifdef CONFIG_COMPAT +#include "timer_compat.c" +#else +#define snd_timer_user_ioctl_compat NULL +#endif + static struct file_operations snd_timer_f_ops = { .owner = THIS_MODULE, @@ -1810,7 +1804,8 @@ static struct file_operations snd_timer_f_ops = .open = snd_timer_user_open, .release = snd_timer_user_release, .poll = snd_timer_user_poll, - .ioctl = snd_timer_user_ioctl, + .unlocked_ioctl = snd_timer_user_ioctl, + .compat_ioctl = snd_timer_user_ioctl_compat, .fasync = snd_timer_user_fasync, }; diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c new file mode 100644 index 000000000000..9fbc3957a22d --- /dev/null +++ b/sound/core/timer_compat.c @@ -0,0 +1,119 @@ +/* + * 32bit -> 64bit ioctl wrapper for timer API + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file included from timer.c */ + +#include + +struct sndrv_timer_info32 { + u32 flags; + s32 card; + unsigned char id[64]; + unsigned char name[80]; + u32 reserved0; + u32 resolution; + unsigned char reserved[64]; +}; + +static int snd_timer_user_info_compat(struct file *file, + struct sndrv_timer_info32 __user *_info) +{ + snd_timer_user_t *tu; + struct sndrv_timer_info32 info; + snd_timer_t *t; + + tu = file->private_data; + snd_assert(tu->timeri != NULL, return -ENXIO); + t = tu->timeri->timer; + snd_assert(t != NULL, return -ENXIO); + memset(&info, 0, sizeof(info)); + info.card = t->card ? t->card->number : -1; + if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) + info.flags |= SNDRV_TIMER_FLG_SLAVE; + strlcpy(info.id, t->id, sizeof(info.id)); + strlcpy(info.name, t->name, sizeof(info.name)); + info.resolution = t->hw.resolution; + if (copy_to_user(_info, &info, sizeof(*_info))) + return -EFAULT; + return 0; +} + +struct sndrv_timer_status32 { + struct compat_timespec tstamp; + u32 resolution; + u32 lost; + u32 overrun; + u32 queue; + unsigned char reserved[64]; +}; + +static int snd_timer_user_status_compat(struct file *file, + struct sndrv_timer_status32 __user *_status) +{ + snd_timer_user_t *tu; + snd_timer_status_t status; + + tu = file->private_data; + snd_assert(tu->timeri != NULL, return -ENXIO); + memset(&status, 0, sizeof(status)); + status.tstamp = tu->tstamp; + status.resolution = snd_timer_resolution(tu->timeri); + status.lost = tu->timeri->lost; + status.overrun = tu->overrun; + spin_lock_irq(&tu->qlock); + status.queue = tu->qused; + spin_unlock_irq(&tu->qlock); + if (copy_to_user(_status, &status, sizeof(status))) + return -EFAULT; + return 0; +} + +/* + */ + +enum { + SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32), + SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32), +}; + +static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = compat_ptr(arg); + + switch (cmd) { + case SNDRV_TIMER_IOCTL_PVERSION: + case SNDRV_TIMER_IOCTL_TREAD: + case SNDRV_TIMER_IOCTL_GINFO: + case SNDRV_TIMER_IOCTL_GPARAMS: + case SNDRV_TIMER_IOCTL_GSTATUS: + case SNDRV_TIMER_IOCTL_SELECT: + case SNDRV_TIMER_IOCTL_PARAMS: + case SNDRV_TIMER_IOCTL_START: + case SNDRV_TIMER_IOCTL_STOP: + case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_NEXT_DEVICE: + return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); + case SNDRV_TIMER_IOCTL_INFO32: + return snd_timer_user_info_compat(file, argp); + case SNDRV_TIMER_IOCTL_STATUS32: + return snd_timer_user_status_compat(file, argp); + } + return -ENOIOCTLCMD; +} -- cgit v1.2.3 From 5c9b7198845983bb068286d089254a8420d185e3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 21 Jan 2005 00:29:20 +0100 Subject: [ALSA] remove obsolete sound/core/ioctl32 directory The compatibility layer is integrated to ALSA midlevel code now. --- include/sound/version.h~ | 3 + sound/core/ioctl32/Makefile | 11 - sound/core/ioctl32/hwdep32.c | 73 ------- sound/core/ioctl32/ioctl32.c | 433 -------------------------------------- sound/core/ioctl32/ioctl32.h | 102 --------- sound/core/ioctl32/pcm32.c | 464 ----------------------------------------- sound/core/ioctl32/rawmidi32.c | 91 -------- sound/core/ioctl32/seq32.c | 116 ----------- sound/core/ioctl32/timer32.c | 105 ---------- 9 files changed, 3 insertions(+), 1395 deletions(-) create mode 100644 include/sound/version.h~ delete mode 100644 sound/core/ioctl32/Makefile delete mode 100644 sound/core/ioctl32/hwdep32.c delete mode 100644 sound/core/ioctl32/ioctl32.c delete mode 100644 sound/core/ioctl32/ioctl32.h delete mode 100644 sound/core/ioctl32/pcm32.c delete mode 100644 sound/core/ioctl32/rawmidi32.c delete mode 100644 sound/core/ioctl32/seq32.c delete mode 100644 sound/core/ioctl32/timer32.c (limited to 'include') diff --git a/include/sound/version.h~ b/include/sound/version.h~ new file mode 100644 index 000000000000..37d587f79e6b --- /dev/null +++ b/include/sound/version.h~ @@ -0,0 +1,3 @@ +/* include/version.h. Generated by configure. */ +#define CONFIG_SND_VERSION "1.0.8rc2" +#define CONFIG_SND_DATE " (Wed Jan 05 06:44:40 2005 UTC)" diff --git a/sound/core/ioctl32/Makefile b/sound/core/ioctl32/Makefile deleted file mode 100644 index 0d0eacd42380..000000000000 --- a/sound/core/ioctl32/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for ALSA -# Copyright (c) 1999 by Jaroslav Kysela -# - -snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o -ifneq ($(CONFIG_SND_SEQUENCER),n) - snd-ioctl32-objs += seq32.o -endif - -obj-$(CONFIG_SND_BIT32_EMUL) += snd-ioctl32.o diff --git a/sound/core/ioctl32/hwdep32.c b/sound/core/ioctl32/hwdep32.c deleted file mode 100644 index d3fd14c6a43f..000000000000 --- a/sound/core/ioctl32/hwdep32.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for hwdep API - * Copyright (c) by Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include "ioctl32.h" - -struct sndrv_hwdep_dsp_image32 { - u32 index; - unsigned char name[64]; - u32 image; /* pointer */ - u32 length; - u32 driver_data; -} /* don't set packed attribute here */; - -static inline int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - struct sndrv_hwdep_dsp_image __user *data, *dst; - struct sndrv_hwdep_dsp_image32 __user *data32, *src; - compat_caddr_t ptr; - - data32 = compat_ptr(arg); - data = compat_alloc_user_space(sizeof(*data)); - - /* index and name */ - if (copy_in_user(data, data32, 4 + 64)) - return -EFAULT; - if (__get_user(ptr, &data32->image) || - __put_user(compat_ptr(ptr), &data->image)) - return -EFAULT; - src = data32; - dst = data; - COPY_CVT(length); - COPY_CVT(driver_data); - return file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); -} - -DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD); - -#define AP(x) snd_ioctl32_##x - -enum { - SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32) -}; - -struct ioctl32_mapper hwdep_mappers[] = { - MAP_COMPAT(SNDRV_HWDEP_IOCTL_PVERSION), - MAP_COMPAT(SNDRV_HWDEP_IOCTL_INFO), - MAP_COMPAT(SNDRV_HWDEP_IOCTL_DSP_STATUS), - { SNDRV_HWDEP_IOCTL_DSP_LOAD32, AP(hwdep_dsp_image) }, - { 0 }, -}; diff --git a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c deleted file mode 100644 index bf48c51080a5..000000000000 --- a/sound/core/ioctl32/ioctl32.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for control API - * Copyright (c) by Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ioctl32.h" - - -/* - * register/unregister mappers - * exported for other modules - */ - -MODULE_AUTHOR("Takashi Iwai "); -MODULE_DESCRIPTION("ioctl32 wrapper for ALSA"); -MODULE_LICENSE("GPL"); - -int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)); -int unregister_ioctl32_conversion(unsigned int cmd); - - -int snd_ioctl32_register(struct ioctl32_mapper *mappers) -{ - int err; - struct ioctl32_mapper *m; - - for (m = mappers; m->cmd; m++) { - err = register_ioctl32_conversion(m->cmd, m->handler); - if (err >= 0) - m->registered++; - } - return 0; -} - -void snd_ioctl32_unregister(struct ioctl32_mapper *mappers) -{ - struct ioctl32_mapper *m; - - for (m = mappers; m->cmd; m++) { - if (m->registered) { - unregister_ioctl32_conversion(m->cmd); - m->registered = 0; - } - } -} - - -/* - * compatible wrapper - */ -int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp) -{ - if (! filp->f_op || ! filp->f_op->ioctl) - return -ENOTTY; - return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); -} - - -/* - * Controls - */ - -struct sndrv_ctl_elem_list32 { - u32 offset; - u32 space; - u32 used; - u32 count; - u32 pids; - unsigned char reserved[50]; -} /* don't set packed attribute here */; - -static inline int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - struct sndrv_ctl_elem_list32 __user *data32; - struct sndrv_ctl_elem_list __user *data; - compat_caddr_t ptr; - int err; - - data32 = compat_ptr(arg); - data = compat_alloc_user_space(sizeof(*data)); - - /* offset, space, used, count */ - if (copy_in_user(data, data32, 4 * sizeof(u32))) - return -EFAULT; - /* pids */ - if (__get_user(ptr, &data32->pids) || - __put_user(compat_ptr(ptr), &data->pids)) - return -EFAULT; - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); - if (err < 0) - return err; - /* copy the result */ - if (copy_in_user(data32, data, 4 * sizeof(u32))) - return -EFAULT; - return 0; -} - -DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST); - -/* - * control element info - * it uses union, so the things are not easy.. - */ - -struct sndrv_ctl_elem_info32 { - struct sndrv_ctl_elem_id id; // the size of struct is same - s32 type; - u32 access; - u32 count; - s32 owner; - union { - struct { - s32 min; - s32 max; - s32 step; - } integer; - struct { - u64 min; - u64 max; - u64 step; - } integer64; - struct { - u32 items; - u32 item; - char name[64]; - } enumerated; - unsigned char reserved[128]; - } value; - unsigned char reserved[64]; -} __attribute__((packed)); - -static inline int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - struct sndrv_ctl_elem_info __user *data, *src; - struct sndrv_ctl_elem_info32 __user *data32, *dst; - unsigned int type; - int err; - - data32 = compat_ptr(arg); - data = compat_alloc_user_space(sizeof(*data)); - - /* copy id */ - if (copy_in_user(&data->id, &data32->id, sizeof(data->id))) - return -EFAULT; - /* we need to copy the item index. - * hope this doesn't break anything.. - */ - if (copy_in_user(&data->value.enumerated.item, - &data32->value.enumerated.item, - sizeof(data->value.enumerated.item))) - return -EFAULT; - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); - if (err < 0) - return err; - /* restore info to 32bit */ - /* for COPY_CVT macro */ - src = data; - dst = data32; - /* id, type, access, count */ - if (copy_in_user(&data32->id, &data->id, sizeof(data->id)) || - copy_in_user(&data32->type, &data->type, 3 * sizeof(u32))) - return -EFAULT; - COPY_CVT(owner); - __get_user(type, &data->type); - switch (type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - COPY_CVT(value.integer.min); - COPY_CVT(value.integer.max); - COPY_CVT(value.integer.step); - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - if (copy_in_user(&data32->value.integer64, - &data->value.integer64, - sizeof(data->value.integer64))) - return -EFAULT; - break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - if (copy_in_user(&data32->value.enumerated, - &data->value.enumerated, - sizeof(data->value.enumerated))) - return -EFAULT; - break; - default: - break; - } - return 0; -} - -DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO); - -struct sndrv_ctl_elem_value32 { - struct sndrv_ctl_elem_id id; - unsigned int indirect; /* bit-field causes misalignment */ - union { - s32 integer[128]; /* integer and boolean need conversion */ -#ifndef CONFIG_X86_64 - s64 integer64[64]; /* for alignment */ -#endif - unsigned char data[512]; /* others should be compatible */ - } value; - unsigned char reserved[128]; /* not used */ -}; - - -/* hmm, it's so hard to retrieve the value type from the control id.. */ -static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id) -{ - snd_kcontrol_t *kctl; - snd_ctl_elem_info_t info; - int err; - - down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); - if (! kctl) { - up_read(&card->controls_rwsem); - return -ENXIO; - } - info.id = *id; - err = kctl->info(kctl, &info); - up_read(&card->controls_rwsem); - if (err >= 0) - err = info.type; - return err; -} - -extern int snd_major; - -static inline int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - struct sndrv_ctl_elem_value *data; - struct sndrv_ctl_elem_value32 __user *data32; - snd_ctl_file_t *ctl; - int err, i, indirect; - int type; - - /* sanity check */ - if (imajor(file->f_dentry->d_inode) != snd_major || - SNDRV_MINOR_DEVICE(iminor(file->f_dentry->d_inode)) != SNDRV_MINOR_CONTROL) - return -ENOTTY; - - if ((ctl = file->private_data) == NULL) - return -ENOTTY; - - data32 = compat_ptr(arg); - data = kcalloc(1, sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) { - err = -EFAULT; - goto __end; - } - if (__get_user(indirect, &data32->indirect)) { - err = -EFAULT; - goto __end; - } - /* FIXME: indirect access is not supported */ - if (indirect) { - err = -EINVAL; - goto __end; - } - type = get_ctl_type(ctl->card, &data->id); - if (type < 0) { - err = type; - goto __end; - } - - switch (type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - for (i = 0; i < 128; i++) { - int val; - if (__get_user(val, &data32->value.integer[i])) { - err = -EFAULT; - goto __end; - } - data->value.integer.value[i] = val; - } - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - case SNDRV_CTL_ELEM_TYPE_BYTES: - case SNDRV_CTL_ELEM_TYPE_IEC958: - if (__copy_from_user(data->value.bytes.data, - data32->value.data, - sizeof(data32->value.data))) { - err = -EFAULT; - goto __end; - } - break; - default: - printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); - err = -EINVAL; - goto __end; - } - - if (native_ctl == SNDRV_CTL_IOCTL_ELEM_READ) - err = snd_ctl_elem_read(ctl->card, data); - else - err = snd_ctl_elem_write(ctl->card, ctl, data); - if (err < 0) - goto __end; - /* restore info to 32bit */ - switch (type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - for (i = 0; i < 128; i++) { - int val; - val = data->value.integer.value[i]; - if (__put_user(val, &data32->value.integer[i])) { - err = -EFAULT; - goto __end; - } - } - break; - default: - if (__copy_to_user(data32->value.data, - data->value.bytes.data, - sizeof(data32->value.data))) { - err = -EFAULT; - goto __end; - } - break; - break; - } - err = 0; - __end: - kfree(data); - return err; -} - -DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ); -DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_write, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_WRITE); - -/* - */ - -#define AP(x) snd_ioctl32_##x - -enum { - SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32), - SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32), - SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32), - SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32), -}; - -static struct ioctl32_mapper control_mappers[] = { - /* controls (without rawmidi, hwdep, timer releated ones) */ - MAP_COMPAT(SNDRV_CTL_IOCTL_PVERSION), - MAP_COMPAT(SNDRV_CTL_IOCTL_CARD_INFO), - { SNDRV_CTL_IOCTL_ELEM_LIST32, AP(ctl_elem_list) }, - { SNDRV_CTL_IOCTL_ELEM_INFO32, AP(ctl_elem_info) }, - { SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_read) }, - { SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_write) }, - MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_LOCK), - MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_UNLOCK), - MAP_COMPAT(SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS), - MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_INFO), - MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE), - MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE), - MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_INFO), - MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE), - MAP_COMPAT(SNDRV_CTL_IOCTL_POWER), - MAP_COMPAT(SNDRV_CTL_IOCTL_POWER_STATE), - { 0 } -}; - - -/* - */ - -extern struct ioctl32_mapper pcm_mappers[]; -extern struct ioctl32_mapper rawmidi_mappers[]; -extern struct ioctl32_mapper timer_mappers[]; -extern struct ioctl32_mapper hwdep_mappers[]; -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) -extern struct ioctl32_mapper seq_mappers[]; -#endif - -static void snd_ioctl32_done(void) -{ -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) - snd_ioctl32_unregister(seq_mappers); -#endif - snd_ioctl32_unregister(hwdep_mappers); - snd_ioctl32_unregister(timer_mappers); - snd_ioctl32_unregister(rawmidi_mappers); - snd_ioctl32_unregister(pcm_mappers); - snd_ioctl32_unregister(control_mappers); -} - -static int __init snd_ioctl32_init(void) -{ - snd_ioctl32_register(control_mappers); - snd_ioctl32_register(pcm_mappers); - snd_ioctl32_register(rawmidi_mappers); - snd_ioctl32_register(timer_mappers); - snd_ioctl32_register(hwdep_mappers); -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) - snd_ioctl32_register(seq_mappers); -#endif - return 0; -} - -module_init(snd_ioctl32_init) -module_exit(snd_ioctl32_done) diff --git a/sound/core/ioctl32/ioctl32.h b/sound/core/ioctl32/ioctl32.h deleted file mode 100644 index a8825a87a976..000000000000 --- a/sound/core/ioctl32/ioctl32.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 32bit -> 64bit ioctl helpers - * Copyright (c) by Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * This file registers the converters from 32-bit ioctls to 64-bit ones. - * The converter assumes that a 32-bit user-pointer can be casted by compat_ptr(x) - * macro to a valid 64-bit pointer which is accessible via copy_from/to_user. - * - */ - -#ifndef __ALSA_IOCTL32_H -#define __ALSA_IOCTL32_H - -#include - -#define COPY(x) \ - do { \ - if (copy_in_user(&dst->x, &src->x, sizeof(dst->x))) \ - return -EFAULT; \ - } while (0) - -#define COPY_ARRAY(x) \ - do { \ - if (copy_in_user(dst->x, src->x, sizeof(dst->x))) \ - return -EFAULT; \ - } while (0) - -#define COPY_CVT(x) \ - do { \ - __typeof__(src->x) __val_tmp; \ - if (get_user(__val_tmp, &src->x) || \ - put_user(__val_tmp, &dst->x))\ - return -EFAULT; \ - } while (0) - -#define convert_from_32(type, dstp, srcp)\ -{\ - struct sndrv_##type __user *dst = dstp;\ - struct sndrv_##type##32 __user *src = srcp;\ - CVT_##sndrv_##type();\ -} - -#define convert_to_32(type, dstp, srcp)\ -{\ - struct sndrv_##type __user *src = srcp;\ - struct sndrv_##type##32 __user *dst = dstp;\ - CVT_##sndrv_##type();\ -} - - -#define DEFINE_ALSA_IOCTL(type) \ -static inline int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\ -{\ - struct sndrv_##type##32 __user *data32;\ - struct sndrv_##type __user *data;\ - int err;\ - data32 = compat_ptr(arg);\ - data = compat_alloc_user_space(sizeof(*data));\ - convert_from_32(type, data, data32);\ - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);\ - if (err < 0) \ - return err;\ - if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\ - convert_to_32(type, data32, data);\ - }\ - return 0;\ -} - -#define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \ -static int snd_ioctl32_##name(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) {\ - return _snd_ioctl32_##type(fd, cmd, arg, file, native_ctl);\ -} - -#define MAP_COMPAT(ctl) { ctl, snd_ioctl32_compat } - -struct ioctl32_mapper { - unsigned int cmd; - int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp); - int registered; -}; - -int snd_ioctl32_compat(unsigned int, unsigned int, unsigned long, struct file *); - -int snd_ioctl32_register(struct ioctl32_mapper *mappers); -void snd_ioctl32_unregister(struct ioctl32_mapper *mappers); - -#endif /* __ALSA_IOCTL32_H */ diff --git a/sound/core/ioctl32/pcm32.c b/sound/core/ioctl32/pcm32.c deleted file mode 100644 index 1e37cda343d2..000000000000 --- a/sound/core/ioctl32/pcm32.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for PCM API - * Copyright (c) by Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ioctl32.h" - - -/* wrapper for sndrv_pcm_[us]frames */ -struct sndrv_pcm_sframes_str { - sndrv_pcm_sframes_t val; -}; -struct sndrv_pcm_sframes_str32 { - s32 val; -}; -struct sndrv_pcm_uframes_str { - sndrv_pcm_uframes_t val; -}; -struct sndrv_pcm_uframes_str32 { - u32 val; -}; - -#define CVT_sndrv_pcm_sframes_str() { COPY_CVT(val); } -#define CVT_sndrv_pcm_uframes_str() { COPY_CVT(val); } - - -struct sndrv_pcm_hw_params32 { - u32 flags; - struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */ - struct sndrv_mask mres[5]; /* reserved masks */ - struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; - struct sndrv_interval ires[9]; /* reserved intervals */ - u32 rmask; - u32 cmask; - u32 info; - u32 msbits; - u32 rate_num; - u32 rate_den; - u32 fifo_size; - unsigned char reserved[64]; -} __attribute__((packed)); - -struct sndrv_pcm_sw_params32 { - s32 tstamp_mode; - u32 period_step; - u32 sleep_min; - u32 avail_min; - u32 xfer_align; - u32 start_threshold; - u32 stop_threshold; - u32 silence_threshold; - u32 silence_size; - u32 boundary; - unsigned char reserved[64]; -} __attribute__((packed)); - -#define CVT_sndrv_pcm_sw_params()\ -{\ - COPY(tstamp_mode);\ - COPY(period_step);\ - COPY(sleep_min);\ - COPY_CVT(avail_min);\ - COPY_CVT(xfer_align);\ - COPY_CVT(start_threshold);\ - COPY_CVT(stop_threshold);\ - COPY_CVT(silence_threshold);\ - COPY_CVT(silence_size);\ - COPY_CVT(boundary);\ -} - -struct sndrv_pcm_channel_info32 { - u32 channel; - u32 offset; - u32 first; - u32 step; -} __attribute__((packed)); - -#define CVT_sndrv_pcm_channel_info()\ -{\ - COPY(channel);\ - COPY_CVT(offset);\ - COPY(first);\ - COPY(step);\ -} - -struct sndrv_pcm_status32 { - s32 state; - struct compat_timespec trigger_tstamp; - struct compat_timespec tstamp; - u32 appl_ptr; - u32 hw_ptr; - s32 delay; - u32 avail; - u32 avail_max; - u32 overrange; - s32 suspended_state; - unsigned char reserved[60]; -} __attribute__((packed)); - -#define CVT_sndrv_pcm_status()\ -{\ - COPY(state);\ - COPY_CVT(trigger_tstamp.tv_sec);\ - COPY_CVT(trigger_tstamp.tv_nsec);\ - COPY_CVT(tstamp.tv_sec);\ - COPY_CVT(tstamp.tv_nsec);\ - COPY_CVT(appl_ptr);\ - COPY_CVT(hw_ptr);\ - COPY_CVT(delay);\ - COPY_CVT(avail);\ - COPY_CVT(avail_max);\ - COPY_CVT(overrange);\ - COPY(suspended_state);\ -} - -DEFINE_ALSA_IOCTL(pcm_uframes_str); -DEFINE_ALSA_IOCTL(pcm_sframes_str); -DEFINE_ALSA_IOCTL(pcm_sw_params); -DEFINE_ALSA_IOCTL(pcm_channel_info); -DEFINE_ALSA_IOCTL(pcm_status); - -/* sanity device check */ -extern int snd_major; -static int sanity_check_pcm(struct file *file) -{ - unsigned short minor; - if (imajor(file->f_dentry->d_inode) != snd_major) - return -ENOTTY; - minor = iminor(file->f_dentry->d_inode); - if (minor >= 256 || - minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK) - return -ENOTTY; - return 0; -} - -/* recalcuate the boundary within 32bit */ -static void recalculate_boundary(snd_pcm_runtime_t *runtime) -{ - if (! runtime->buffer_size) - return; - runtime->boundary = runtime->buffer_size; - while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) - runtime->boundary *= 2; -} - -/* both for HW_PARAMS and HW_REFINE */ -static int _snd_ioctl32_pcm_hw_params(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - struct sndrv_pcm_hw_params32 __user *data32; - struct sndrv_pcm_hw_params *data; - snd_pcm_file_t *pcm_file; - snd_pcm_substream_t *substream; - snd_pcm_runtime_t *runtime; - int err; - - if (sanity_check_pcm(file)) - return -ENOTTY; - if (! (pcm_file = file->private_data)) - return -ENOTTY; - if (! (substream = pcm_file->substream)) - return -ENOTTY; - if (! (runtime = substream->runtime)) - return -ENOTTY; - - data32 = compat_ptr(arg); - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - if (copy_from_user(data, data32, sizeof(*data32))) { - err = -EFAULT; - goto error; - } - if (native_ctl == SNDRV_PCM_IOCTL_HW_REFINE) - err = snd_pcm_hw_refine(substream, data); - else - err = snd_pcm_hw_params(substream, data); - if (err < 0) - goto error; - if (copy_to_user(data32, data, sizeof(*data32)) || - __put_user((u32)data->fifo_size, &data32->fifo_size)) { - err = -EFAULT; - goto error; - } - - if (native_ctl == SNDRV_PCM_IOCTL_HW_PARAMS) - recalculate_boundary(runtime); - error: - kfree(data); - return err; -} - - -/* - */ -struct sndrv_xferi32 { - s32 result; - u32 buf; - u32 frames; -} __attribute__((packed)); - -static int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - struct sndrv_xferi32 data32; - struct sndrv_xferi __user *data; - snd_pcm_sframes_t result; - int err; - - if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) - return -EFAULT; - data = compat_alloc_user_space(sizeof(*data)); - if (put_user((snd_pcm_sframes_t)data32.result, &data->result) || - __put_user(compat_ptr(data32.buf), &data->buf) || - __put_user((snd_pcm_uframes_t)data32.frames, &data->frames)) - return -EFAULT; - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); - if (err < 0) - return err; - /* copy the result */ - if (__get_user(result, &data->result)) - return -EFAULT; - data32.result = result; - if (copy_to_user((void __user *)arg, &data32, sizeof(data32))) - return -EFAULT; - return 0; -} - - -/* snd_xfern needs remapping of bufs */ -struct sndrv_xfern32 { - s32 result; - u32 bufs; /* this is void **; */ - u32 frames; -} __attribute__((packed)); - -/* - * xfern ioctl nees to copy (up to) 128 pointers on stack. - * although we may pass the copied pointers through f_op->ioctl, but the ioctl - * handler there expands again the same 128 pointers on stack, so it is better - * to handle the function (calling pcm_readv/writev) directly in this handler. - */ -static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - snd_pcm_file_t *pcm_file; - snd_pcm_substream_t *substream; - struct sndrv_xfern32 __user *srcptr = compat_ptr(arg); - struct sndrv_xfern32 data32; - void __user **bufs; - int err = 0, ch, i; - u32 __user *bufptr; - - if (sanity_check_pcm(file)) - return -ENOTTY; - if (! (pcm_file = file->private_data)) - return -ENOTTY; - if (! (substream = pcm_file->substream)) - return -ENOTTY; - if (! substream->runtime) - return -ENOTTY; - - /* check validty of the command */ - switch (native_ctl) { - case SNDRV_PCM_IOCTL_WRITEN_FRAMES: - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return -EINVAL; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - break; - case SNDRV_PCM_IOCTL_READN_FRAMES: - if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) - return -EINVAL; - break; - } - if ((ch = substream->runtime->channels) > 128) - return -EINVAL; - if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) - return -EFAULT; - bufptr = compat_ptr(data32.bufs); - bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL); - if (bufs == NULL) - return -ENOMEM; - for (i = 0; i < ch; i++) { - u32 ptr; - if (get_user(ptr, bufptr)) { - kfree(bufs); - return -EFAULT; - } - bufs[ch] = compat_ptr(ptr); - bufptr++; - } - switch (native_ctl) { - case SNDRV_PCM_IOCTL_WRITEN_FRAMES: - err = snd_pcm_lib_writev(substream, bufs, data32.frames); - break; - case SNDRV_PCM_IOCTL_READN_FRAMES: - err = snd_pcm_lib_readv(substream, bufs, data32.frames); - break; - } - if (err >= 0) { - if (put_user(err, &srcptr->result)) - err = -EFAULT; - } - kfree(bufs); - return err; -} - - -struct sndrv_pcm_mmap_status32 { - s32 state; - s32 pad1; - u32 hw_ptr; - struct compat_timespec tstamp; - s32 suspended_state; -} __attribute__((packed)); - -struct sndrv_pcm_mmap_control32 { - u32 appl_ptr; - u32 avail_min; -} __attribute__((packed)); - -struct sndrv_pcm_sync_ptr32 { - u32 flags; - union { - struct sndrv_pcm_mmap_status32 status; - unsigned char reserved[64]; - } s; - union { - struct sndrv_pcm_mmap_control32 control; - unsigned char reserved[64]; - } c; -} __attribute__((packed)); - -#define CVT_sndrv_pcm_sync_ptr()\ -{\ - COPY(flags);\ - COPY(s.status.state);\ - COPY(s.status.pad1);\ - COPY_CVT(s.status.hw_ptr);\ - COPY_CVT(s.status.tstamp.tv_sec);\ - COPY_CVT(s.status.tstamp.tv_nsec);\ - COPY(s.status.suspended_state);\ - COPY_CVT(c.control.appl_ptr);\ - COPY_CVT(c.control.avail_min);\ -} - -DEFINE_ALSA_IOCTL(pcm_sync_ptr); - -/* - */ - -DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine, pcm_hw_params, SNDRV_PCM_IOCTL_HW_REFINE); -DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params, pcm_hw_params, SNDRV_PCM_IOCTL_HW_PARAMS); -DEFINE_ALSA_IOCTL_ENTRY(pcm_sw_params, pcm_sw_params, SNDRV_PCM_IOCTL_SW_PARAMS); -DEFINE_ALSA_IOCTL_ENTRY(pcm_status, pcm_status, SNDRV_PCM_IOCTL_STATUS); -DEFINE_ALSA_IOCTL_ENTRY(pcm_delay, pcm_sframes_str, SNDRV_PCM_IOCTL_DELAY); -DEFINE_ALSA_IOCTL_ENTRY(pcm_channel_info, pcm_channel_info, SNDRV_PCM_IOCTL_CHANNEL_INFO); -DEFINE_ALSA_IOCTL_ENTRY(pcm_rewind, pcm_uframes_str, SNDRV_PCM_IOCTL_REWIND); -DEFINE_ALSA_IOCTL_ENTRY(pcm_forward, pcm_uframes_str, SNDRV_PCM_IOCTL_FORWARD); -DEFINE_ALSA_IOCTL_ENTRY(pcm_readi, xferi, SNDRV_PCM_IOCTL_READI_FRAMES); -DEFINE_ALSA_IOCTL_ENTRY(pcm_writei, xferi, SNDRV_PCM_IOCTL_WRITEI_FRAMES); -DEFINE_ALSA_IOCTL_ENTRY(pcm_readn, xfern, SNDRV_PCM_IOCTL_READN_FRAMES); -DEFINE_ALSA_IOCTL_ENTRY(pcm_writen, xfern, SNDRV_PCM_IOCTL_WRITEN_FRAMES); -DEFINE_ALSA_IOCTL_ENTRY(pcm_sync_ptr, pcm_sync_ptr, SNDRV_PCM_IOCTL_SYNC_PTR); - - -/* - * When PCM is used on 32bit mode, we need to disable - * mmap of PCM status/control records because of the size - * incompatibility. - * - * Since INFO ioctl is always called at first, we mark the - * mmap-disabling in this ioctl wrapper. - */ -static int snd_pcm_info_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp) -{ - snd_pcm_file_t *pcm_file; - snd_pcm_substream_t *substream; - if (! filp->f_op || ! filp->f_op->ioctl) - return -ENOTTY; - pcm_file = filp->private_data; - if (! pcm_file) - return -ENOTTY; - substream = pcm_file->substream; - if (! substream) - return -ENOTTY; - substream->no_mmap_ctrl = 1; - return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); -} - -/* - */ -#define AP(x) snd_ioctl32_##x - -enum { - SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32), - SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32), - SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32), - SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32), - SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32), - SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32), - SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32), - SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32), - SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32), - SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32), - SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32), - SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32), - SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32), - -}; - -struct ioctl32_mapper pcm_mappers[] = { - MAP_COMPAT(SNDRV_PCM_IOCTL_PVERSION), - /* MAP_COMPAT(SNDRV_PCM_IOCTL_INFO), */ - { SNDRV_PCM_IOCTL_INFO, snd_pcm_info_ioctl32 }, - MAP_COMPAT(SNDRV_PCM_IOCTL_TSTAMP), - { SNDRV_PCM_IOCTL_HW_REFINE32, AP(pcm_hw_refine) }, - { SNDRV_PCM_IOCTL_HW_PARAMS32, AP(pcm_hw_params) }, - MAP_COMPAT(SNDRV_PCM_IOCTL_HW_FREE), - { SNDRV_PCM_IOCTL_SW_PARAMS32, AP(pcm_sw_params) }, - { SNDRV_PCM_IOCTL_STATUS32, AP(pcm_status) }, - { SNDRV_PCM_IOCTL_DELAY32, AP(pcm_delay) }, - MAP_COMPAT(SNDRV_PCM_IOCTL_HWSYNC), - { SNDRV_PCM_IOCTL_SYNC_PTR32, AP(pcm_sync_ptr) }, - { SNDRV_PCM_IOCTL_CHANNEL_INFO32, AP(pcm_channel_info) }, - MAP_COMPAT(SNDRV_PCM_IOCTL_PREPARE), - MAP_COMPAT(SNDRV_PCM_IOCTL_RESET), - MAP_COMPAT(SNDRV_PCM_IOCTL_START), - MAP_COMPAT(SNDRV_PCM_IOCTL_DROP), - MAP_COMPAT(SNDRV_PCM_IOCTL_DRAIN), - MAP_COMPAT(SNDRV_PCM_IOCTL_PAUSE), - { SNDRV_PCM_IOCTL_REWIND32, AP(pcm_rewind) }, - MAP_COMPAT(SNDRV_PCM_IOCTL_RESUME), - MAP_COMPAT(SNDRV_PCM_IOCTL_XRUN), - { SNDRV_PCM_IOCTL_FORWARD32, AP(pcm_forward) }, - { SNDRV_PCM_IOCTL_WRITEI_FRAMES32, AP(pcm_writei) }, - { SNDRV_PCM_IOCTL_READI_FRAMES32, AP(pcm_readi) }, - { SNDRV_PCM_IOCTL_WRITEN_FRAMES32, AP(pcm_writen) }, - { SNDRV_PCM_IOCTL_READN_FRAMES32, AP(pcm_readn) }, - MAP_COMPAT(SNDRV_PCM_IOCTL_LINK), - MAP_COMPAT(SNDRV_PCM_IOCTL_UNLINK), - - { 0 }, -}; diff --git a/sound/core/ioctl32/rawmidi32.c b/sound/core/ioctl32/rawmidi32.c deleted file mode 100644 index c1d89488618c..000000000000 --- a/sound/core/ioctl32/rawmidi32.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for raw MIDI API - * Copyright (c) by Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ioctl32.h" - -struct sndrv_rawmidi_params32 { - s32 stream; - u32 buffer_size; - u32 avail_min; - unsigned int no_active_sensing; /* avoid bit-field */ - unsigned char reserved[16]; -} __attribute__((packed)); - -#define CVT_sndrv_rawmidi_params()\ -{\ - COPY(stream);\ - COPY_CVT(buffer_size);\ - COPY_CVT(avail_min);\ - if (copy_in_user(((size_t __user *)&dst->avail_min + 1),\ - ((size_t __user *)&src->avail_min + 1), 4)) \ - return -EFAULT;\ -} - -struct sndrv_rawmidi_status32 { - s32 stream; - struct compat_timespec tstamp; - u32 avail; - u32 xruns; - unsigned char reserved[16]; -} __attribute__((packed)); - -#define CVT_sndrv_rawmidi_status()\ -{\ - COPY(stream);\ - COPY_CVT(tstamp.tv_sec);\ - COPY_CVT(tstamp.tv_nsec);\ - COPY_CVT(avail);\ - COPY_CVT(xruns);\ -} - -DEFINE_ALSA_IOCTL(rawmidi_params); -DEFINE_ALSA_IOCTL(rawmidi_status); - -DEFINE_ALSA_IOCTL_ENTRY(rawmidi_params, rawmidi_params, SNDRV_RAWMIDI_IOCTL_PARAMS); -DEFINE_ALSA_IOCTL_ENTRY(rawmidi_status, rawmidi_status, SNDRV_RAWMIDI_IOCTL_STATUS); - -#define AP(x) snd_ioctl32_##x - -enum { - SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32), - SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32), -}; - -struct ioctl32_mapper rawmidi_mappers[] = { - MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_PVERSION), - MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_INFO), - { SNDRV_RAWMIDI_IOCTL_PARAMS32, AP(rawmidi_params) }, - { SNDRV_RAWMIDI_IOCTL_STATUS32, AP(rawmidi_status) }, - MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DROP), - MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DRAIN), - - MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE), - MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_INFO), - MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE), - - { 0 }, -}; diff --git a/sound/core/ioctl32/seq32.c b/sound/core/ioctl32/seq32.c deleted file mode 100644 index c349feaf3add..000000000000 --- a/sound/core/ioctl32/seq32.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for sequencer API - * Copyright (c) by Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ioctl32.h" - -struct sndrv_seq_port_info32 { - struct sndrv_seq_addr addr; /* client/port numbers */ - char name[64]; /* port name */ - - u32 capability; /* port capability bits */ - u32 type; /* port type bits */ - s32 midi_channels; /* channels per MIDI port */ - s32 midi_voices; /* voices per MIDI port */ - s32 synth_voices; /* voices per SYNTH port */ - - s32 read_use; /* R/O: subscribers for output (from this port) */ - s32 write_use; /* R/O: subscribers for input (to this port) */ - - u32 kernel; /* reserved for kernel use (must be NULL) */ - u32 flags; /* misc. conditioning */ - unsigned char time_queue; /* queue # for timestamping */ - char reserved[59]; /* for future use */ -}; - -#define CVT_sndrv_seq_port_info()\ -{\ - COPY(addr);\ - COPY_ARRAY(name);\ - COPY(capability);\ - COPY(type);\ - COPY(midi_channels);\ - COPY(midi_voices);\ - COPY(synth_voices);\ - COPY(read_use);\ - COPY(write_use);\ - COPY(flags);\ - COPY(time_queue);\ -} - -DEFINE_ALSA_IOCTL(seq_port_info); -DEFINE_ALSA_IOCTL_ENTRY(create_port, seq_port_info, SNDRV_SEQ_IOCTL_CREATE_PORT); -DEFINE_ALSA_IOCTL_ENTRY(delete_port, seq_port_info, SNDRV_SEQ_IOCTL_DELETE_PORT); -DEFINE_ALSA_IOCTL_ENTRY(get_port_info, seq_port_info, SNDRV_SEQ_IOCTL_GET_PORT_INFO); -DEFINE_ALSA_IOCTL_ENTRY(set_port_info, seq_port_info, SNDRV_SEQ_IOCTL_SET_PORT_INFO); -DEFINE_ALSA_IOCTL_ENTRY(query_next_port, seq_port_info, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT); - -/* - */ -#define AP(x) snd_ioctl32_##x - -enum { - SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32), - SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32), - SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32), - SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32), - SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32), -}; - -struct ioctl32_mapper seq_mappers[] = { - MAP_COMPAT(SNDRV_SEQ_IOCTL_PVERSION), - MAP_COMPAT(SNDRV_SEQ_IOCTL_CLIENT_ID), - MAP_COMPAT(SNDRV_SEQ_IOCTL_SYSTEM_INFO), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_INFO), - MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO), - { SNDRV_SEQ_IOCTL_CREATE_PORT32, AP(create_port) }, - { SNDRV_SEQ_IOCTL_DELETE_PORT32, AP(delete_port) }, - { SNDRV_SEQ_IOCTL_GET_PORT_INFO32, AP(get_port_info) }, - { SNDRV_SEQ_IOCTL_SET_PORT_INFO32, AP(set_port_info) }, - MAP_COMPAT(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT), - MAP_COMPAT(SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT), - MAP_COMPAT(SNDRV_SEQ_IOCTL_CREATE_QUEUE), - MAP_COMPAT(SNDRV_SEQ_IOCTL_DELETE_QUEUE), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_INFO), - MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_INFO), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO), - MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER), - MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT), - MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_POOL), - MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_POOL), - MAP_COMPAT(SNDRV_SEQ_IOCTL_REMOVE_EVENTS), - MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_SUBS), - MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION), - MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT), - { SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32, AP(query_next_port) }, - MAP_COMPAT(SNDRV_SEQ_IOCTL_RUNNING_MODE), - { 0 }, -}; diff --git a/sound/core/ioctl32/timer32.c b/sound/core/ioctl32/timer32.c deleted file mode 100644 index 5f1a2d97a873..000000000000 --- a/sound/core/ioctl32/timer32.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for timer API - * Copyright (c) by Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ioctl32.h" - -struct sndrv_timer_info32 { - u32 flags; - s32 card; - unsigned char id[64]; - unsigned char name[80]; - u32 reserved0; - u32 resolution; - unsigned char reserved[64]; -}; - -#define CVT_sndrv_timer_info()\ -{\ - COPY(flags);\ - COPY(card);\ - COPY_ARRAY(id);\ - COPY_ARRAY(name);\ - COPY_CVT(resolution);\ -} - -struct sndrv_timer_status32 { - struct compat_timespec tstamp; - u32 resolution; - u32 lost; - u32 overrun; - u32 queue; - unsigned char reserved[64]; -}; - -#define CVT_sndrv_timer_status()\ -{\ - COPY_CVT(tstamp.tv_sec);\ - COPY_CVT(tstamp.tv_nsec);\ - COPY(resolution);\ - COPY(lost);\ - COPY(overrun);\ - COPY(queue);\ -} - -DEFINE_ALSA_IOCTL(timer_info); -DEFINE_ALSA_IOCTL(timer_status); - -DEFINE_ALSA_IOCTL_ENTRY(timer_info, timer_info, SNDRV_TIMER_IOCTL_INFO); -DEFINE_ALSA_IOCTL_ENTRY(timer_status, timer_status, SNDRV_TIMER_IOCTL_STATUS); - -/* - */ - -#define AP(x) snd_ioctl32_##x - -enum { - SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32), - SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32), -}; - -struct ioctl32_mapper timer_mappers[] = { - MAP_COMPAT(SNDRV_TIMER_IOCTL_PVERSION), - MAP_COMPAT(SNDRV_TIMER_IOCTL_NEXT_DEVICE), - MAP_COMPAT(SNDRV_TIMER_IOCTL_SELECT), - { SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) }, - MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS), - { SNDRV_TIMER_IOCTL_STATUS32, AP(timer_status) }, -#if 0 - /* ** FIXME ** - * The following four entries are disabled because they conflict - * with the TCOC* definitions. - * Unfortunately, the current ioctl32 wrapper uses a single - * hash table for all devices. Once when the wrapper is fixed - * with the table based on devices, they'll be back again. - */ - MAP_COMPAT(SNDRV_TIMER_IOCTL_START), - MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP), - MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE), - MAP_COMPAT(SNDRV_TIMER_IOCTL_PAUSE), -#endif - { 0 }, -}; -- cgit v1.2.3 From dc1c3c59a9c8bbc15f7ccb26faec1739b580089e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 27 Jan 2005 10:20:45 +0100 Subject: [ALSA] Removed file added by mistake Removed include/sound/version.h~ --- include/sound/version.h~ | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 include/sound/version.h~ (limited to 'include') diff --git a/include/sound/version.h~ b/include/sound/version.h~ deleted file mode 100644 index 37d587f79e6b..000000000000 --- a/include/sound/version.h~ +++ /dev/null @@ -1,3 +0,0 @@ -/* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.8rc2" -#define CONFIG_SND_DATE " (Wed Jan 05 06:44:40 2005 UTC)" -- cgit v1.2.3 From efac16caa86e5d6fb3c7972edb28d1614b32ece4 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 14 Feb 2005 16:34:58 +0100 Subject: [ALSA] Remove pm_register/pm_unregister SA11xx UDA1341 driver,ALSA Core,ISA Removed pm_register() and pm_unregister(). Use platform_device for suspend/resume, instead. The current implemention is still a hack. The whole ISA drivers should be rewritten with a proper bus definition. Signed-off-by: Takashi Iwai --- include/sound/core.h | 30 +++++----- sound/arm/sa11xx-uda1341.c | 4 +- sound/core/Kconfig | 2 + sound/core/init.c | 134 ++++++++++++++++++++++++++++++++++++--------- sound/core/sound.c | 4 +- sound/isa/Kconfig | 6 ++ 6 files changed, 136 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/include/sound/core.h b/include/sound/core.h index c1e64ce10830..b1691ad419b0 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -169,11 +169,13 @@ struct _snd_card { #ifdef CONFIG_PM int (*pm_suspend)(snd_card_t *card, unsigned int state); int (*pm_resume)(snd_card_t *card, unsigned int state); - struct pm_dev *pm_dev; /* for ISA */ void *pm_private_data; unsigned int power_state; /* power state */ struct semaphore power_lock; /* power lock */ wait_queue_head_t power_sleep; +#ifdef CONFIG_SND_GENERIC_PM + struct snd_generic_device *pm_dev; /* for ISA */ +#endif #endif #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) @@ -209,33 +211,31 @@ int snd_card_set_pm_callback(snd_card_t *card, int (*suspend)(snd_card_t *, unsigned int), int (*resume)(snd_card_t *, unsigned int), void *private_data); -int snd_card_set_dev_pm_callback(snd_card_t *card, int type, - int (*suspend)(snd_card_t *, unsigned int), - int (*resume)(snd_card_t *, unsigned int), - void *private_data); +int snd_card_set_generic_pm_callback(snd_card_t *card, + int (*suspend)(snd_card_t *, unsigned int), + int (*resume)(snd_card_t *, unsigned int), + void *private_data); #define snd_card_set_isa_pm_callback(card,suspend,resume,data) \ - snd_card_set_dev_pm_callback(card, PM_ISA_DEV, suspend, resume, data) -#ifdef CONFIG_PCI -#ifndef SND_PCI_PM_CALLBACKS + snd_card_set_generic_pm_callback(card, suspend, resume, data) +struct pci_dev; int snd_card_pci_suspend(struct pci_dev *dev, u32 state); int snd_card_pci_resume(struct pci_dev *dev); #define SND_PCI_PM_CALLBACKS \ .suspend = snd_card_pci_suspend, .resume = snd_card_pci_resume -#endif -#endif -#else + +#else /* ! CONFIG_PM */ + #define snd_power_lock(card) do { (void)(card); } while (0) #define snd_power_unlock(card) do { (void)(card); } while (0) static inline int snd_power_wait(snd_card_t *card, unsigned int state, struct file *file) { return 0; } #define snd_power_get_state(card) SNDRV_CTL_POWER_D0 #define snd_power_change_state(card, state) do { (void)(card); } while (0) #define snd_card_set_pm_callback(card,suspend,resume,data) -#define snd_card_set_dev_pm_callback(card,suspend,resume,data) +#define snd_card_set_generic_pm_callback(card,suspend,resume,data) #define snd_card_set_isa_pm_callback(card,suspend,resume,data) -#ifdef CONFIG_PCI #define SND_PCI_PM_CALLBACKS -#endif -#endif + +#endif /* CONFIG_PM */ /* device.c */ diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index 21103c7aed5a..9a1e0e6270a1 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c @@ -21,7 +21,7 @@ * merged HAL layer (patches from Brian) */ -/* $Id: sa11xx-uda1341.c,v 1.19 2004/12/15 15:26:10 tiwai Exp $ */ +/* $Id: sa11xx-uda1341.c,v 1.20 2005/01/28 14:49:59 tiwai Exp $ */ /*************************************************************************************************** * @@ -938,7 +938,7 @@ static int __init sa11xx_uda1341_init(void) if ((err = snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341, 0)) < 0) goto nodev; - snd_card_set_dev_pm_callback(card, PM_SYS_DEV, + snd_card_set_generic_pm_callback(card, snd_sa11xx_uda1341_suspend, snd_sa11_uda1341_resume, sa11xx_uda1341); diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 48dd6b797e5d..46399b87ce08 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -123,3 +123,5 @@ config SND_DEBUG_DETECT Say Y here to enable extra-verbose log messages printed when detecting devices. +config SND_GENERIC_PM + bool diff --git a/sound/core/init.c b/sound/core/init.c index 729a9937db51..22c44327467f 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -229,6 +229,10 @@ int snd_card_disconnect(snd_card_t * card) return 0; } +#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM) +static void snd_generic_device_unregister(struct snd_generic_device *dev); +#endif + /** * snd_card_free - frees given soundcard structure * @card: soundcard structure @@ -252,9 +256,9 @@ int snd_card_free(snd_card_t * card) #ifdef CONFIG_PM wake_up(&card->power_sleep); -#ifdef CONFIG_ISA +#ifdef CONFIG_SND_GENERIC_PM if (card->pm_dev) { - pm_unregister(card->pm_dev); + snd_generic_device_unregister(card->pm_dev); card->pm_dev = NULL; } #endif @@ -729,53 +733,131 @@ int snd_card_set_pm_callback(snd_card_t *card, return 0; } -static int snd_generic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +#ifdef CONFIG_SND_GENERIC_PM +/* + * use platform_device for generic power-management without a proper bus + * (e.g. ISA) + */ +struct snd_generic_device { + struct platform_device pdev; + snd_card_t *card; +}; + +#define get_snd_generic_card(dev) container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card + +#define SND_GENERIC_NAME "snd_generic_pm" + +static int snd_generic_suspend(struct device *dev, u32 state, u32 level); +static int snd_generic_resume(struct device *dev, u32 level); + +static struct device_driver snd_generic_driver = { + .name = SND_GENERIC_NAME, + .bus = &platform_bus_type, + .suspend = snd_generic_suspend, + .resume = snd_generic_resume, +}; + +static int generic_driver_registered; + +static void generic_driver_unregister(void) +{ + if (generic_driver_registered) { + generic_driver_registered--; + if (! generic_driver_registered) + driver_unregister(&snd_generic_driver); + } +} + +static struct snd_generic_device *snd_generic_device_register(snd_card_t *card) { - snd_card_t *card = dev->data; + struct snd_generic_device *dev; - switch (rqst) { - case PM_SUSPEND: - if (card->power_state == SNDRV_CTL_POWER_D3hot) - break; - /* FIXME: the correct state value? */ - card->pm_suspend(card, 0); - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - break; - case PM_RESUME: - if (card->power_state == SNDRV_CTL_POWER_D0) - break; - /* FIXME: the correct state value? */ - card->pm_resume(card, 0); - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - break; + if (! generic_driver_registered) { + if (driver_register(&snd_generic_driver) < 0) + return NULL; + } + generic_driver_registered++; + + dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); + if (! dev) { + generic_driver_unregister(); + return NULL; + } + + dev->pdev.name = SND_GENERIC_NAME; + dev->pdev.id = card->number; + dev->card = card; + if (platform_device_register(&dev->pdev) < 0) { + kfree(dev); + generic_driver_unregister(); + return NULL; } + return dev; +} + +static void snd_generic_device_unregister(struct snd_generic_device *dev) +{ + platform_device_unregister(&dev->pdev); + kfree(dev); + generic_driver_unregister(); +} + +/* suspend/resume callbacks for snd_generic platform device */ +static int snd_generic_suspend(struct device *dev, u32 state, u32 level) +{ + snd_card_t *card; + + if (level != SUSPEND_DISABLE) + return 0; + + card = get_snd_generic_card(dev); + if (card->power_state == SNDRV_CTL_POWER_D3hot) + return 0; + /* FIXME: the correct state value? */ + card->pm_suspend(card, 0); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + return 0; +} + +static int snd_generic_resume(struct device *dev, u32 level) +{ + snd_card_t *card; + + if (level != RESUME_ENABLE) + return 0; + + card = get_snd_generic_card(dev); + if (card->power_state == SNDRV_CTL_POWER_D0) + return 0; + /* FIXME: the correct state value? */ + card->pm_resume(card, 0); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } /** - * snd_card_set_dev_pm_callback - set the generic power-management callbacks + * snd_card_set_generic_pm_callback - set the generic power-management callbacks * @card: soundcard structure - * @type: PM device type (PM_XXX) * @suspend: suspend callback function * @resume: resume callback function * @private_data: private data to pass to the callback functions * * Registers the power-management and sets the lowlevel callbacks for - * the given card with the given PM type. These callbacks are called - * from the ALSA's common PM handler and from the control API. + * the given card. These callbacks are called from the ALSA's common + * PM handler and from the control API. */ -int snd_card_set_dev_pm_callback(snd_card_t *card, int type, +int snd_card_set_generic_pm_callback(snd_card_t *card, int (*suspend)(snd_card_t *, unsigned int), int (*resume)(snd_card_t *, unsigned int), void *private_data) { - card->pm_dev = pm_register(type, 0, snd_generic_pm_callback); + card->pm_dev = snd_generic_device_register(card); if (! card->pm_dev) return -ENOMEM; - card->pm_dev->data = card; snd_card_set_pm_callback(card, suspend, resume, private_data); return 0; } +#endif /* CONFIG_SND_GENERIC_PM */ #ifdef CONFIG_PCI int snd_card_pci_suspend(struct pci_dev *dev, u32 state) diff --git a/sound/core/sound.c b/sound/core/sound.c index 8068c8a3fc24..641950ca754a 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -420,7 +420,9 @@ EXPORT_SYMBOL(snd_card_file_remove); #ifdef CONFIG_PM EXPORT_SYMBOL(snd_power_wait); EXPORT_SYMBOL(snd_card_set_pm_callback); -EXPORT_SYMBOL(snd_card_set_dev_pm_callback); +#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM) +EXPORT_SYMBOL(snd_card_set_generic_pm_callback); +#endif #ifdef CONFIG_PCI EXPORT_SYMBOL(snd_card_pci_suspend); EXPORT_SYMBOL(snd_card_pci_resume); diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 7e6cedb413f9..ffbe4bf4aa12 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -20,6 +20,7 @@ config SND_AD1848 tristate "Generic AD1848/CS4248 driver" depends on SND select SND_PCM + select SND_GENERIC_PM help Say Y here to include support for AD1848 (Analog Devices) or CS4248 (Cirrus Logic - Crystal Semiconductors) chips. @@ -35,6 +36,7 @@ config SND_CS4231 depends on SND select SND_MPU401_UART select SND_PCM + select SND_GENERIC_PM help Say Y here to include support for CS4231 chips from Cirrus Logic - Crystal Semiconductors. @@ -48,6 +50,7 @@ config SND_CS4232 select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_PM help Say Y here to include support for CS4232 chips from Cirrus Logic - Crystal Semiconductors. @@ -61,6 +64,7 @@ config SND_CS4236 select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_PM help Say Y to include support for CS4235,CS4236,CS4237B,CS4238B, CS4239 chips from Cirrus Logic - Crystal Semiconductors. @@ -98,6 +102,7 @@ config SND_ES18XX select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_PM help Say Y here to include support for ESS AudioDrive ES18xx chips. @@ -332,6 +337,7 @@ config SND_OPL3SA2 select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_PM help Say Y here to include support for Yamaha OPL3-SA2 and OPL3-SA3 chips. -- cgit v1.2.3 From f285aed4a9eb8e100993587b67ef3064b27031f8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 14 Feb 2005 16:42:16 +0100 Subject: [ALSA] driver model type fixes for ALSA SA11xx UDA1341 driver,Control Midlevel,ALSA Core,Digigram VX core ES18xx driver,OPL3SA2 driver,AD1848 driver,CS4231 driver,ATIIXP driver ATIIXP-modem driver,CS4281 driver,ES1938 driver,ES1968 driver Intel8x0 driver,Intel8x0-modem driver,Maestro3 driver,VIA82xx driver VIA82xx-modem driver,ALI5451 driver,CS46xx driver,HDA Codec driver HDA Intel driver,NM256 driver,Trident driver,YMFPCI driver PDAudioCF driver,Digigram VX Pocket driver,PPC PMAC driver Fixes by Pavel Machek : suspend() routines no longer get u32 as their parameter (they get pm_message_t, which is u32 for now, but will change in 2.6.12 or so). This fixes ALSA to notice this, and uses constants with right types where appropriate. It results in no code changes. [Best results will be when patching against latest -mm, you may get some warnings if you patch it into older kernel, but it should still do the right thing.] Please apply, Pavel [In addition, suspend callback type is changed to follow to the standard style taking no state argument -- Takashi] Signed-off-by: Takashi Iwai --- include/sound/core.h | 14 +++++++------- sound/arm/sa11xx-uda1341.c | 6 +++--- sound/core/control.c | 6 ++---- sound/core/init.c | 18 +++++++----------- sound/drivers/vx/vx_core.c | 4 ++-- sound/isa/ad1848/ad1848_lib.c | 4 ++-- sound/isa/cs423x/cs4231_lib.c | 4 ++-- sound/isa/es18xx.c | 4 ++-- sound/isa/opl3sa2.c | 4 ++-- sound/pci/ali5451/ali5451.c | 4 ++-- sound/pci/atiixp.c | 4 ++-- sound/pci/atiixp_modem.c | 4 ++-- sound/pci/cs4281.c | 8 ++++---- sound/pci/cs46xx/cs46xx_lib.c | 4 ++-- sound/pci/es1938.c | 4 ++-- sound/pci/es1968.c | 4 ++-- sound/pci/hda/hda_codec.c | 6 +++--- sound/pci/hda/hda_codec.h | 8 ++++---- sound/pci/hda/hda_intel.c | 6 +++--- sound/pci/intel8x0.c | 4 ++-- sound/pci/intel8x0m.c | 4 ++-- sound/pci/maestro3.c | 4 ++-- sound/pci/nm256/nm256.c | 4 ++-- sound/pci/trident/trident_main.c | 8 ++++---- sound/pci/via82xx.c | 4 ++-- sound/pci/via82xx_modem.c | 4 ++-- sound/pci/ymfpci/ymfpci_main.c | 4 ++-- sound/pcmcia/pdaudiocf/pdaudiocf.c | 4 ++-- sound/pcmcia/pdaudiocf/pdaudiocf.h | 4 ++-- sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 4 ++-- sound/pcmcia/vx/vx_entry.c | 4 ++-- sound/ppc/pmac.c | 8 ++++---- 32 files changed, 85 insertions(+), 91 deletions(-) (limited to 'include') diff --git a/include/sound/core.h b/include/sound/core.h index b1691ad419b0..df47c383daeb 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -167,8 +167,8 @@ struct _snd_card { struct device *dev; #ifdef CONFIG_PM - int (*pm_suspend)(snd_card_t *card, unsigned int state); - int (*pm_resume)(snd_card_t *card, unsigned int state); + int (*pm_suspend)(snd_card_t *card, pm_message_t state); + int (*pm_resume)(snd_card_t *card); void *pm_private_data; unsigned int power_state; /* power state */ struct semaphore power_lock; /* power lock */ @@ -208,17 +208,17 @@ static inline void snd_power_change_state(snd_card_t *card, unsigned int state) wake_up(&card->power_sleep); } int snd_card_set_pm_callback(snd_card_t *card, - int (*suspend)(snd_card_t *, unsigned int), - int (*resume)(snd_card_t *, unsigned int), + int (*suspend)(snd_card_t *, pm_message_t), + int (*resume)(snd_card_t *), void *private_data); int snd_card_set_generic_pm_callback(snd_card_t *card, - int (*suspend)(snd_card_t *, unsigned int), - int (*resume)(snd_card_t *, unsigned int), + int (*suspend)(snd_card_t *, pm_message_t), + int (*resume)(snd_card_t *), void *private_data); #define snd_card_set_isa_pm_callback(card,suspend,resume,data) \ snd_card_set_generic_pm_callback(card, suspend, resume, data) struct pci_dev; -int snd_card_pci_suspend(struct pci_dev *dev, u32 state); +int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state); int snd_card_pci_resume(struct pci_dev *dev); #define SND_PCI_PM_CALLBACKS \ .suspend = snd_card_pci_suspend, .resume = snd_card_pci_resume diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index 9a1e0e6270a1..174bc032d1ad 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c @@ -21,7 +21,7 @@ * merged HAL layer (patches from Brian) */ -/* $Id: sa11xx-uda1341.c,v 1.20 2005/01/28 14:49:59 tiwai Exp $ */ +/* $Id: sa11xx-uda1341.c,v 1.21 2005/01/28 19:34:04 tiwai Exp $ */ /*************************************************************************************************** * @@ -862,7 +862,7 @@ static int __init snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341_t *sa11xx_uda1341, #ifdef CONFIG_PM -static int snd_sa11xx_uda1341_suspend(snd_card_t *card, unsigned int state) +static int snd_sa11xx_uda1341_suspend(snd_card_t *card, pm_message_t state) { sa11xx_uda1341_t *chip = card->pm_private_data; @@ -878,7 +878,7 @@ static int snd_sa11xx_uda1341_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_sa11xx_uda1341_resume(snd_card_t *card, unsigned int state) +static int snd_sa11xx_uda1341_resume(snd_card_t *card) { sa11xx_uda1341_t *chip = card->pm_private_data; diff --git a/sound/core/control.c b/sound/core/control.c index 1080098512c7..56b095c1a23b 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1007,15 +1007,13 @@ static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state) switch (power_state) { case SNDRV_CTL_POWER_D0: if (card->power_state != power_state) { - /* FIXME: pass the correct state value */ - card->pm_resume(card, 0); + card->pm_resume(card); snd_power_change_state(card, power_state); } break; case SNDRV_CTL_POWER_D3hot: if (card->power_state != power_state) { - /* FIXME: pass the correct state value */ - card->pm_suspend(card, 0); + card->pm_suspend(card, PMSG_SUSPEND); snd_power_change_state(card, power_state); } break; diff --git a/sound/core/init.c b/sound/core/init.c index 7ed1081b0fad..aa0a263ede25 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -720,8 +720,8 @@ int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file * handler and from the control API. */ int snd_card_set_pm_callback(snd_card_t *card, - int (*suspend)(snd_card_t *, unsigned int), - int (*resume)(snd_card_t *, unsigned int), + int (*suspend)(snd_card_t *, pm_message_t), + int (*resume)(snd_card_t *), void *private_data) { card->pm_suspend = suspend; @@ -810,8 +810,7 @@ static int snd_generic_suspend(struct device *dev, u32 state, u32 level) card = get_snd_generic_card(dev); if (card->power_state == SNDRV_CTL_POWER_D3hot) return 0; - /* FIXME: the correct state value? */ - card->pm_suspend(card, 0); + card->pm_suspend(card, PMSG_SUSPEND); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -826,8 +825,7 @@ static int snd_generic_resume(struct device *dev, u32 level) card = get_snd_generic_card(dev); if (card->power_state == SNDRV_CTL_POWER_D0) return 0; - /* FIXME: the correct state value? */ - card->pm_resume(card, 0); + card->pm_resume(card); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -857,7 +855,7 @@ int snd_card_set_generic_pm_callback(snd_card_t *card, #endif /* CONFIG_SND_GENERIC_PM */ #ifdef CONFIG_PCI -int snd_card_pci_suspend(struct pci_dev *dev, u32 state) +int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state) { snd_card_t *card = pci_get_drvdata(dev); int err; @@ -865,8 +863,7 @@ int snd_card_pci_suspend(struct pci_dev *dev, u32 state) return 0; if (card->power_state == SNDRV_CTL_POWER_D3hot) return 0; - /* FIXME: correct state value? */ - err = card->pm_suspend(card, 0); + err = card->pm_suspend(card, PMSG_SUSPEND); pci_save_state(dev); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return err; @@ -881,8 +878,7 @@ int snd_card_pci_resume(struct pci_dev *dev) return 0; /* restore the PCI config space */ pci_restore_state(dev); - /* FIXME: correct state value? */ - card->pm_resume(card, 0); + card->pm_resume(card); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 20afb96885f9..c6fa5afa3e9a 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -721,7 +721,7 @@ int snd_vx_dsp_load(vx_core_t *chip, const struct firmware *dsp) /* * suspend */ -static int snd_vx_suspend(snd_card_t *card, unsigned int state) +static int snd_vx_suspend(snd_card_t *card, pm_message_t state) { vx_core_t *chip = card->pm_private_data; unsigned int i; @@ -738,7 +738,7 @@ static int snd_vx_suspend(snd_card_t *card, unsigned int state) /* * resume */ -static int snd_vx_resume(snd_card_t *card, unsigned int state) +static int snd_vx_resume(snd_card_t *card) { vx_core_t *chip = card->pm_private_data; int i, err; diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 97b8f8710802..8fb3db103e48 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -644,7 +644,7 @@ static void snd_ad1848_thinkpad_twiddle(ad1848_t *chip, int on) { } #ifdef CONFIG_PM -static int snd_ad1848_suspend(snd_card_t *card, unsigned int state) +static int snd_ad1848_suspend(snd_card_t *card, pm_message_t state) { ad1848_t *chip = card->pm_private_data; @@ -657,7 +657,7 @@ static int snd_ad1848_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_ad1848_resume(snd_card_t *card, unsigned int state) +static int snd_ad1848_resume(snd_card_t *card) { ad1848_t *chip = card->pm_private_data; diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 888e2b00f9d9..3e7a2a33a5ca 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -1394,7 +1394,7 @@ static void snd_cs4231_resume(cs4231_t *chip) #endif } -static int snd_cs4231_pm_suspend(snd_card_t *card, unsigned int state) +static int snd_cs4231_pm_suspend(snd_card_t *card, pm_message_t state) { cs4231_t *chip = card->pm_private_data; if (chip->suspend) @@ -1402,7 +1402,7 @@ static int snd_cs4231_pm_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_cs4231_pm_resume(snd_card_t *card, unsigned int state) +static int snd_cs4231_pm_resume(snd_card_t *card) { cs4231_t *chip = card->pm_private_data; if (chip->resume) diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 4939aad0aebb..1d832b2adb7c 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1612,7 +1612,7 @@ static int __devinit snd_es18xx_pcm(es18xx_t *chip, int device, snd_pcm_t ** rpc /* Power Management support functions */ #ifdef CONFIG_PM -static int snd_es18xx_suspend(snd_card_t *card, unsigned int state) +static int snd_es18xx_suspend(snd_card_t *card, pm_message_t state) { es18xx_t *chip = card->pm_private_data; @@ -1627,7 +1627,7 @@ static int snd_es18xx_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_es18xx_resume(snd_card_t *card, unsigned int state) +static int snd_es18xx_resume(snd_card_t *card) { es18xx_t *chip = card->pm_private_data; diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index ea71f581962b..1e6415640f52 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -529,7 +529,7 @@ static int __init snd_opl3sa2_mixer(opl3sa2_t *chip) /* Power Management support functions */ #ifdef CONFIG_PM -static int snd_opl3sa2_suspend(snd_card_t *card, unsigned int state) +static int snd_opl3sa2_suspend(snd_card_t *card, pm_message_t state) { opl3sa2_t *chip = card->pm_private_data; @@ -542,7 +542,7 @@ static int snd_opl3sa2_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_opl3sa2_resume(snd_card_t *card, unsigned int state) +static int snd_opl3sa2_resume(snd_card_t *card) { opl3sa2_t *chip = card->pm_private_data; int i; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index b58de4440904..6c4deeaaa455 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1894,7 +1894,7 @@ static int __devinit snd_ali_mixer(ali_t * codec) } #ifdef CONFIG_PM -static int ali_suspend(snd_card_t *card, unsigned int state) +static int ali_suspend(snd_card_t *card, pm_message_t state) { ali_t *chip = card->pm_private_data; ali_image_t *im; @@ -1936,7 +1936,7 @@ static int ali_suspend(snd_card_t *card, unsigned int state) return 0; } -static int ali_resume(snd_card_t *card, unsigned int state) +static int ali_resume(snd_card_t *card) { ali_t *chip = card->pm_private_data; ali_image_t *im; diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 758bc99c3490..a566571b255b 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1398,7 +1398,7 @@ static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock, const char /* * power management */ -static int snd_atiixp_suspend(snd_card_t *card, unsigned int state) +static int snd_atiixp_suspend(snd_card_t *card, pm_message_t state) { atiixp_t *chip = card->pm_private_data; int i; @@ -1417,7 +1417,7 @@ static int snd_atiixp_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_atiixp_resume(snd_card_t *card, unsigned int state) +static int snd_atiixp_resume(snd_card_t *card) { atiixp_t *chip = card->pm_private_data; int i; diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index abe32fbb3cbe..5d3e537339f9 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1107,7 +1107,7 @@ static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock) /* * power management */ -static int snd_atiixp_suspend(snd_card_t *card, unsigned int state) +static int snd_atiixp_suspend(snd_card_t *card, pm_message_t state) { atiixp_t *chip = card->pm_private_data; int i; @@ -1126,7 +1126,7 @@ static int snd_atiixp_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_atiixp_resume(snd_card_t *card, unsigned int state) +static int snd_atiixp_resume(snd_card_t *card) { atiixp_t *chip = card->pm_private_data; int i; diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 72831d064e40..3a5fd96d6e87 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1376,8 +1376,8 @@ static int snd_cs4281_dev_free(snd_device_t *device) static int snd_cs4281_chip_init(cs4281_t *chip); /* defined below */ #ifdef CONFIG_PM -static int cs4281_suspend(snd_card_t *card, unsigned int state); -static int cs4281_resume(snd_card_t *card, unsigned int state); +static int cs4281_suspend(snd_card_t *card, pm_message_t state); +static int cs4281_resume(snd_card_t *card); #endif static int __devinit snd_cs4281_create(snd_card_t * card, @@ -2037,7 +2037,7 @@ static int saved_regs[SUSPEND_REGISTERS] = { #define CLKCR1_CKRA 0x00010000L -static int cs4281_suspend(snd_card_t *card, unsigned int state) +static int cs4281_suspend(snd_card_t *card, pm_message_t state) { cs4281_t *chip = card->pm_private_data; u32 ulCLK; @@ -2082,7 +2082,7 @@ static int cs4281_suspend(snd_card_t *card, unsigned int state) return 0; } -static int cs4281_resume(snd_card_t *card, unsigned int state) +static int cs4281_resume(snd_card_t *card) { cs4281_t *chip = card->pm_private_data; unsigned int i; diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 0dcfee801597..2a8e4a0a8172 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3704,7 +3704,7 @@ static struct cs_card_type __devinitdata cards[] = { * APM support */ #ifdef CONFIG_PM -static int snd_cs46xx_suspend(snd_card_t *card, unsigned int state) +static int snd_cs46xx_suspend(snd_card_t *card, pm_message_t state) { cs46xx_t *chip = card->pm_private_data; int amp_saved; @@ -3728,7 +3728,7 @@ static int snd_cs46xx_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_cs46xx_resume(snd_card_t *card, unsigned int state) +static int snd_cs46xx_resume(snd_card_t *card) { cs46xx_t *chip = card->pm_private_data; int amp_saved; diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 6057e544050d..553b24d72462 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1381,7 +1381,7 @@ static unsigned char saved_regs[SAVED_REG_SIZE+1] = { }; -static int es1938_suspend(snd_card_t *card, unsigned int state) +static int es1938_suspend(snd_card_t *card, pm_message_t state) { es1938_t *chip = card->pm_private_data; unsigned char *s, *d; @@ -1398,7 +1398,7 @@ static int es1938_suspend(snd_card_t *card, unsigned int state) return 0; } -static int es1938_resume(snd_card_t *card, unsigned int state) +static int es1938_resume(snd_card_t *card) { es1938_t *chip = card->pm_private_data; unsigned char *s, *d; diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 12ac754801a6..9d461c673498 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2404,7 +2404,7 @@ static void snd_es1968_start_irq(es1968_t *chip) /* * PM support */ -static int es1968_suspend(snd_card_t *card, unsigned int state) +static int es1968_suspend(snd_card_t *card, pm_message_t state) { es1968_t *chip = card->pm_private_data; @@ -2419,7 +2419,7 @@ static int es1968_suspend(snd_card_t *card, unsigned int state) return 0; } -static int es1968_resume(snd_card_t *card, unsigned int state) +static int es1968_resume(snd_card_t *card) { es1968_t *chip = card->pm_private_data; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 99ea5032de2c..f13e69c2b479 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1613,7 +1613,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o * * Returns 0 if successful. */ -int snd_hda_suspend(struct hda_bus *bus, unsigned int state) +int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) { struct list_head *p; @@ -1633,14 +1633,14 @@ int snd_hda_suspend(struct hda_bus *bus, unsigned int state) * * Returns 0 if successful. */ -int snd_hda_resume(struct hda_bus *bus, unsigned int state) +int snd_hda_resume(struct hda_bus *bus) { struct list_head *p; list_for_each(p, &bus->codec_list) { struct hda_codec *codec = list_entry(p, struct hda_codec, list); if (codec->patch_ops.resume) - codec->patch_ops.resume(codec, state); + codec->patch_ops.resume(codec); } return 0; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b4291661fd3b..e40708d5821d 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -447,8 +447,8 @@ struct hda_codec_ops { void (*free)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); #ifdef CONFIG_PM - int (*suspend)(struct hda_codec *codec, unsigned int state); - int (*resume)(struct hda_codec *codec, unsigned int state); + int (*suspend)(struct hda_codec *codec, pm_message_t state); + int (*resume)(struct hda_codec *codec); #endif }; @@ -595,8 +595,8 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); * power management */ #ifdef CONFIG_PM -int snd_hda_suspend(struct hda_bus *bus, unsigned int state); -int snd_hda_resume(struct hda_bus *bus, unsigned int state); +int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); +int snd_hda_resume(struct hda_bus *bus); #endif #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 903060c74ed1..d89647a3d449 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1174,7 +1174,7 @@ static int __devinit azx_init_stream(azx_t *chip) /* * power management */ -static int azx_suspend(snd_card_t *card, unsigned int state) +static int azx_suspend(snd_card_t *card, pm_message_t state) { azx_t *chip = card->pm_private_data; int i; @@ -1188,14 +1188,14 @@ static int azx_suspend(snd_card_t *card, unsigned int state) return 0; } -static int azx_resume(snd_card_t *card, unsigned int state) +static int azx_resume(snd_card_t *card) { azx_t *chip = card->pm_private_data; pci_enable_device(chip->pci); pci_set_master(chip->pci); azx_init_chip(chip); - snd_hda_resume(chip->bus, state); + snd_hda_resume(chip->bus); return 0; } #endif /* CONFIG_PM */ diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index aeaf1651d2f9..31b8415db031 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2320,7 +2320,7 @@ static int snd_intel8x0_free(intel8x0_t *chip) /* * power management */ -static int intel8x0_suspend(snd_card_t *card, unsigned int state) +static int intel8x0_suspend(snd_card_t *card, pm_message_t state) { intel8x0_t *chip = card->pm_private_data; int i; @@ -2345,7 +2345,7 @@ static int intel8x0_suspend(snd_card_t *card, unsigned int state) return 0; } -static int intel8x0_resume(snd_card_t *card, unsigned int state) +static int intel8x0_resume(snd_card_t *card) { intel8x0_t *chip = card->pm_private_data; int i; diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index f65f156b136e..68a7f48025b2 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1078,7 +1078,7 @@ static int snd_intel8x0_free(intel8x0_t *chip) /* * power management */ -static int intel8x0m_suspend(snd_card_t *card, unsigned int state) +static int intel8x0m_suspend(snd_card_t *card, pm_message_t state) { intel8x0_t *chip = card->pm_private_data; int i; @@ -1091,7 +1091,7 @@ static int intel8x0m_suspend(snd_card_t *card, unsigned int state) return 0; } -static int intel8x0m_resume(snd_card_t *card, unsigned int state) +static int intel8x0m_resume(snd_card_t *card) { intel8x0_t *chip = card->pm_private_data; pci_enable_device(chip->pci); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 87fae627b801..713774a4dfd2 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2385,7 +2385,7 @@ static int snd_m3_free(m3_t *chip) * APM support */ #ifdef CONFIG_PM -static int m3_suspend(snd_card_t *card, unsigned int state) +static int m3_suspend(snd_card_t *card, pm_message_t state) { m3_t *chip = card->pm_private_data; int i, index; @@ -2417,7 +2417,7 @@ static int m3_suspend(snd_card_t *card, unsigned int state) return 0; } -static int m3_resume(snd_card_t *card, unsigned int state) +static int m3_resume(snd_card_t *card) { m3_t *chip = card->pm_private_data; int i, index; diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 33e0d6b52ad9..356fbeac6f9e 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1267,7 +1267,7 @@ snd_nm256_peek_for_sig(nm256_t *chip) * APM event handler, so the card is properly reinitialized after a power * event. */ -static int nm256_suspend(snd_card_t *card, unsigned int state) +static int nm256_suspend(snd_card_t *card, pm_message_t state) { nm256_t *chip = card->pm_private_data; @@ -1278,7 +1278,7 @@ static int nm256_suspend(snd_card_t *card, unsigned int state) return 0; } -static int nm256_resume(snd_card_t *card, unsigned int state) +static int nm256_resume(snd_card_t *card) { nm256_t *chip = card->pm_private_data; diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index cafa9abe7e73..c802608e8336 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -48,8 +48,8 @@ static int snd_trident_pcm_mixer_build(trident_t *trident, snd_trident_voice_t * static int snd_trident_pcm_mixer_free(trident_t *trident, snd_trident_voice_t * voice, snd_pcm_substream_t *substream); static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs); #ifdef CONFIG_PM -static int snd_trident_suspend(snd_card_t *card, unsigned int state); -static int snd_trident_resume(snd_card_t *card, unsigned int state); +static int snd_trident_suspend(snd_card_t *card, pm_message_t state); +static int snd_trident_resume(snd_card_t *card); #endif static int snd_trident_sis_reset(trident_t *trident); @@ -3921,7 +3921,7 @@ static void snd_trident_clear_voices(trident_t * trident, unsigned short v_min, } #ifdef CONFIG_PM -static int snd_trident_suspend(snd_card_t *card, unsigned int state) +static int snd_trident_suspend(snd_card_t *card, pm_message_t state) { trident_t *trident = card->pm_private_data; @@ -3947,7 +3947,7 @@ static int snd_trident_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_trident_resume(snd_card_t *card, unsigned int state) +static int snd_trident_resume(snd_card_t *card) { trident_t *trident = card->pm_private_data; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 5b26b52d55e5..201952e9d74e 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1895,7 +1895,7 @@ static int __devinit snd_via82xx_chip_init(via82xx_t *chip) /* * power management */ -static int snd_via82xx_suspend(snd_card_t *card, unsigned int state) +static int snd_via82xx_suspend(snd_card_t *card, pm_message_t state) { via82xx_t *chip = card->pm_private_data; int i; @@ -1920,7 +1920,7 @@ static int snd_via82xx_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_via82xx_resume(snd_card_t *card, unsigned int state) +static int snd_via82xx_resume(snd_card_t *card) { via82xx_t *chip = card->pm_private_data; int idx, i; diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 3e1a8bab66d6..64304bf42ef1 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1034,7 +1034,7 @@ static int __devinit snd_via82xx_chip_init(via82xx_t *chip) /* * power management */ -static int snd_via82xx_suspend(snd_card_t *card, unsigned int state) +static int snd_via82xx_suspend(snd_card_t *card, pm_message_t state) { via82xx_t *chip = card->pm_private_data; int i; @@ -1051,7 +1051,7 @@ static int snd_via82xx_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_via82xx_resume(snd_card_t *card, unsigned int state) +static int snd_via82xx_resume(snd_card_t *card) { via82xx_t *chip = card->pm_private_data; int i; diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 4b560a7357b3..c54f7ed4ea12 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2142,7 +2142,7 @@ static int saved_regs_index[] = { }; #define YDSXGR_NUM_SAVED_REGS ARRAY_SIZE(saved_regs_index) -static int snd_ymfpci_suspend(snd_card_t *card, unsigned int state) +static int snd_ymfpci_suspend(snd_card_t *card, pm_message_t state) { ymfpci_t *chip = card->pm_private_data; unsigned int i; @@ -2161,7 +2161,7 @@ static int snd_ymfpci_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_ymfpci_resume(snd_card_t *card, unsigned int state) +static int snd_ymfpci_resume(snd_card_t *card) { ymfpci_t *chip = card->pm_private_data; unsigned int i; diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index e31a990df275..bae45fe2f2de 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -342,7 +342,7 @@ static int pdacf_event(event_t event, int priority, event_callback_args_t *args) link->state |= DEV_SUSPEND; if (chip) { snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n"); - snd_pdacf_suspend(chip->card, 0); + snd_pdacf_suspend(chip->card, PMSG_SUSPEND); } /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: @@ -361,7 +361,7 @@ static int pdacf_event(event_t event, int priority, event_callback_args_t *args) pcmcia_request_configuration(link->handle, &link->conf); if (chip) { snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n"); - snd_pdacf_resume(chip->card, 0); + snd_pdacf_resume(chip->card); } } snd_printdd(KERN_DEBUG "resume done!\n"); diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h index ddaa69d54236..c7a9628256ee 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.h +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h @@ -134,8 +134,8 @@ pdacf_t *snd_pdacf_create(snd_card_t *card); int snd_pdacf_ak4117_create(pdacf_t *pdacf); void snd_pdacf_powerdown(pdacf_t *chip); #ifdef CONFIG_PM -int snd_pdacf_suspend(snd_card_t *card, unsigned int state); -int snd_pdacf_resume(snd_card_t *card, unsigned int state); +int snd_pdacf_suspend(snd_card_t *card, pm_message_t state); +int snd_pdacf_resume(snd_card_t *card); #endif int snd_pdacf_pcm_new(pdacf_t *chip); irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs); diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index f845503bb449..a2132e3763dd 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -255,7 +255,7 @@ void snd_pdacf_powerdown(pdacf_t *chip) #ifdef CONFIG_PM -int snd_pdacf_suspend(snd_card_t *card, unsigned int state) +int snd_pdacf_suspend(snd_card_t *card, pm_message_t state) { pdacf_t *chip = card->pm_private_data; u16 val; @@ -275,7 +275,7 @@ static inline int check_signal(pdacf_t *chip) return (chip->ak4117->rcs0 & AK4117_UNLCK) == 0; } -int snd_pdacf_resume(snd_card_t *card, unsigned int state) +int snd_pdacf_resume(snd_card_t *card) { pdacf_t *chip = card->pm_private_data; int timeout = 40; diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c index d3c70b02fbbb..53d8172c52ae 100644 --- a/sound/pcmcia/vx/vx_entry.c +++ b/sound/pcmcia/vx/vx_entry.c @@ -346,7 +346,7 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar link->state |= DEV_SUSPEND; if (chip && chip->card->pm_suspend) { snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n"); - chip->card->pm_suspend(chip->card, 0); + chip->card->pm_suspend(chip->card, PMSG_SUSPEND); } /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: @@ -366,7 +366,7 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar pcmcia_request_configuration(link->handle, &link->conf); if (chip && chip->card->pm_resume) { snd_printdd(KERN_DEBUG "calling snd_vx_resume\n"); - chip->card->pm_resume(chip->card, 0); + chip->card->pm_resume(chip->card); } } snd_printdd(KERN_DEBUG "resume done!\n"); diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 2498b75fb6e5..a8921ab763dd 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -40,8 +40,8 @@ #if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK) static int snd_pmac_register_sleep_notifier(pmac_t *chip); static int snd_pmac_unregister_sleep_notifier(pmac_t *chip); -static int snd_pmac_suspend(snd_card_t *card, unsigned int state); -static int snd_pmac_resume(snd_card_t *card, unsigned int state); +static int snd_pmac_suspend(snd_card_t *card, pm_message_t state); +static int snd_pmac_resume(snd_card_t *card); #endif @@ -1233,7 +1233,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return) * Save state when going to sleep, restore it afterwards. */ -static int snd_pmac_suspend(snd_card_t *card, unsigned int state) +static int snd_pmac_suspend(snd_card_t *card, pm_message_t state) { pmac_t *chip = card->pm_private_data; unsigned long flags; @@ -1254,7 +1254,7 @@ static int snd_pmac_suspend(snd_card_t *card, unsigned int state) return 0; } -static int snd_pmac_resume(snd_card_t *card, unsigned int state) +static int snd_pmac_resume(snd_card_t *card) { pmac_t *chip = card->pm_private_data; -- cgit v1.2.3 From 61c7da990676a5e746e30ff19ac1d9e49a26fde3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 14 Feb 2005 16:47:25 +0100 Subject: [ALSA] Fix inclusion of pm.h ALSA Core Added the missing inclusion of linux/pm.h. Signed-off-by: Takashi Iwai --- include/sound/core.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/sound/core.h b/include/sound/core.h index df47c383daeb..da8c781b81e1 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -26,6 +26,7 @@ #include /* struct semaphore */ #include /* struct rw_semaphore */ #include /* struct workqueue_struct */ +#include /* pm_message_t */ /* Typedef's */ typedef struct timespec snd_timestamp_t; -- cgit v1.2.3 From 8fdee9cf1e455610510cdc4a0acc45bc31890111 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 14 Feb 2005 16:59:12 +0100 Subject: [ALSA] capture EXTINs with multichannel device EMU10K1/EMU10K2 driver This patch changes the emu10k1 multichannel capture device (hw:x,2) to capture the 16 external inputs by default. This involves adding DSP code to route the EXTINs to the FXBUS2 (EFX capture) channels and setting the corresponding FXWC bits by default. This allows capturing multiple inputs simultaneously. It completely bypasses the capture controls of the mixer. With my Audigy2 ZS I can capture LineIn, Line2, and Aux2 at the same time (6 channels). Signed-off-by: Lee Revell Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 15 +++++++++++---- sound/pci/emu10k1/emufx.c | 23 +++++++++++++++++++++++ sound/pci/emu10k1/emupcm.c | 14 ++++++++++++-- 3 files changed, 46 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 29a24cbd8f65..943c9e52abc6 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1112,7 +1112,10 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, /* GPRs */ #define FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x0f */ #define EXTIN(x) (0x10 + (x)) /* x = 0x00 - 0x0f */ -#define EXTOUT(x) (0x20 + (x)) /* x = 0x00 - 0x0f */ +#define EXTOUT(x) (0x20 + (x)) /* x = 0x00 - 0x0f physical outs -> FXWC low 16 bits */ +#define FXBUS2(x) (0x30 + (x)) /* x = 0x00 - 0x0f copies of fx buses for capture -> FXWC high 16 bits */ + /* NB: 0x31 and 0x32 are shared with Center/LFE on SB live 5.1 */ + #define C_00000000 0x40 #define C_00000001 0x41 #define C_00000002 0x42 @@ -1154,9 +1157,13 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, #define A_ITRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */ #define A_ETRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */ -#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f? */ -#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x1f? */ -#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f? */ +#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f FX buses */ +#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x0f physical ins */ +#define A_P16VIN(x) (0x50 + (x)) /* x = 0x00 - 0x0f p16v ins (A2 only) "EMU32 inputs" */ +#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f physical outs -> A_FXWC1 0x79-7f unknown */ +#define A_FXBUS2(x) (0x80 + (x)) /* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */ +#define A_EMU32OUTH(x) (0xa0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */ +#define A_EMU32OUTL(x) (0xb0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */ #define A_GPR(x) (A_FXGPREGBASE + (x)) /* cc_reg constants */ diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 5d8d4274978f..842290ba456c 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1358,6 +1358,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); #endif + /* EFX capture - capture the 16 EXTINs */ + for (z = 0; z < 16; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); + } + /* * ok, set up done.. */ @@ -1930,6 +1935,24 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) if (emu->fx8010.extout_mask & (1< tmp) { snd_BUG(); err = -EIO; diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index de78ffe9112d..022493d554f1 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1390,8 +1390,18 @@ int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm if (rpcm) *rpcm = pcm; - emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; - emu->efx_voices_mask[1] = 0; + /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs + * to these + */ + + /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ + if (emu->audigy) { + emu->efx_voices_mask[0] = 0; + emu->efx_voices_mask[1] = 0xffff; + } else { + emu->efx_voices_mask[0] = 0xffff; + emu->efx_voices_mask[1] = 0; + } snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu)); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); -- cgit v1.2.3 From 6d92388b61cca79b3443f5a8a48b0c7e0866c278 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 14 Feb 2005 17:19:12 +0100 Subject: [ALSA] add 96Khz support and setting sample rate for direct SPDIF output EMU10K1/EMU10K2 driver This patch should add support for 96Khz 'direct SPDIF' aka 'SPDIF Bypass' (not P16V) playback mode available on the Audigy1 and 2 and newer SBLives (?). It lets you bypass the 48khz DSP resampling when using the card in digital mode. It also adds 96khz analog playback support, good for testing but less interesting because it's downsampled to 48khz. A new mixer control 'Audigy SPDIF Output Sample Rate' is created, you can choose 44100, 48000, or 96000. Standard SPDIF playback, AC3 passthrough (real 96khz playback), and analog playback (96khz is resampled to 48khz in the DSP) all work with a 16 bit,96khz wav file. Only the last was tested due to lack of any SPDIF hardware. This was derived mostly from the opensource.creative.com driver. All that was needed for 96khz playback to work in analog mode was changing the format to 8000_96000 (looks like the creative driver supports 192khz too). And, of course this sample rate has always been supported (albeit downsampled) because if you have 48khz samples in a soundfont the envelope engine has to be able to pitch shift them in both directions. I still have not been able to figure out how to get 24 bit playback to work. This is possible, independent of the P16V, for spdif and analog 24/48 playback via the DSP. I do know how to access the full 24 bits from the ADC from within the DSP, just not how to get it in there. For one thing I have no idea which 24 bit format it supports. Some of them seemed to work with JACK but produced noise. This was generated with my multichannel patch but it applies against ALSA CVS as well. Signed-off-by: Lee Revell Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 7 ++-- sound/pci/emu10k1/emumixer.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ sound/pci/emu10k1/emupcm.c | 4 +- 3 files changed, 95 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 943c9e52abc6..fd623d13dbcc 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -710,9 +710,10 @@ #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ -#define A_SPDIF_48000 0x00000080 -#define A_SPDIF_44100 0x00000000 -#define A_SPDIF_96000 0x00000040 +#define A_SPDIF_RATE_MASK 0x000000c0 +#define A_SPDIF_48000 0x00000000 +#define A_SPDIF_44100 0x00000040 +#define A_SPDIF_96000 0x00000080 #define A_FXRT2 0x7c #define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 62ecdec603b0..6d7cbaa1747c 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -67,6 +67,91 @@ static int snd_emu10k1_spdif_get_mask(snd_kcontrol_t * kcontrol, return 0; } +static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"44100", "48000", "96000"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_audigy_spdif_output_rate_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int tmp; + unsigned long flags; + + + spin_lock_irqsave(&emu->reg_lock, flags); + tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); + switch (tmp & A_SPDIF_RATE_MASK) { + case A_SPDIF_44100: + ucontrol->value.enumerated.item[0] = 0; + break; + case A_SPDIF_48000: + ucontrol->value.enumerated.item[0] = 1; + break; + case A_SPDIF_96000: + ucontrol->value.enumerated.item[0] = 2; + break; + default: + ucontrol->value.enumerated.item[0] = 1; + } + spin_unlock_irqrestore(&emu->reg_lock, flags); + return 0; +} + +static int snd_audigy_spdif_output_rate_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + int change; + unsigned int reg, val, tmp; + unsigned long flags; + + switch(ucontrol->value.enumerated.item[0]) { + case 0: + val = A_SPDIF_44100; + break; + case 1: + val = A_SPDIF_48000; + break; + case 2: + val = A_SPDIF_96000; + break; + default: + val = A_SPDIF_48000; + break; + } + + + spin_lock_irqsave(&emu->reg_lock, flags); + reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); + tmp = reg & ~A_SPDIF_RATE_MASK; + tmp |= val; + if ((change = (tmp != reg))) + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); + spin_unlock_irqrestore(&emu->reg_lock, flags); + return change; +} + +static snd_kcontrol_new_t snd_audigy_spdif_output_rate = +{ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Audigy SPDIF Output Sample Rate", + .count = 1, + .info = snd_audigy_spdif_output_rate_info, + .get = snd_audigy_spdif_output_rate_get, + .put = snd_audigy_spdif_output_rate_put +}; + static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { @@ -620,6 +705,10 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; } else if (! emu->APS) { /* sb live! */ if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 022493d554f1..c9fa79b496bd 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -707,9 +707,9 @@ static snd_pcm_hardware_t snd_emu10k1_playback = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000, .rate_min = 4000, - .rate_max = 48000, + .rate_max = 96000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), -- cgit v1.2.3 From e81585354771a1862e0013ec9a205810fa5c6558 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 14 Feb 2005 17:25:22 +0100 Subject: [ALSA] Added ICE1724 - ESI Juli@ code (not complete) + AK4114 code + AK4358 Serial BUS drivers,AK4114 receiver,AK4XXX AD/DA converters ICE1712 driver,ICE1724 driver Initial incomplete driver for ESI Juli@ cardcards based on ICE1724, AK4114, AK4358 and AK5385. The ICE1724 and ICE1712 main files plus some drivers are also updated (cleanups and new callbacks). Signed-off-by: Jaroslav Kysela --- include/sound/ak4114.h | 205 +++++++++++++++ include/sound/ak4xxx-adda.h | 3 +- sound/i2c/other/Makefile | 2 + sound/i2c/other/ak4114.c | 581 +++++++++++++++++++++++++++++++++++++++++ sound/i2c/other/ak4xxx-adda.c | 36 ++- sound/pci/ice1712/Makefile | 2 +- sound/pci/ice1712/ak4xxx.c | 12 +- sound/pci/ice1712/envy24ht.h | 2 +- sound/pci/ice1712/ice1712.c | 32 ++- sound/pci/ice1712/ice1712.h | 9 +- sound/pci/ice1712/ice1724.c | 68 +++-- sound/pci/ice1712/juli.c | 230 ++++++++++++++++ sound/pci/ice1712/juli.h | 10 + sound/pci/ice1712/prodigy192.c | 4 +- sound/pci/ice1712/revo.c | 11 + 15 files changed, 1154 insertions(+), 53 deletions(-) create mode 100644 include/sound/ak4114.h create mode 100644 sound/i2c/other/ak4114.c create mode 100644 sound/pci/ice1712/juli.c create mode 100644 sound/pci/ice1712/juli.h (limited to 'include') diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h new file mode 100644 index 000000000000..f3f2c3e5ae51 --- /dev/null +++ b/include/sound/ak4114.h @@ -0,0 +1,205 @@ +#ifndef __SOUND_AK4114_H +#define __SOUND_AK4114_H + +/* + * Routines for Asahi Kasei AK4114 + * Copyright (c) by Jaroslav Kysela , + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* AK4114 registers */ +#define AK4114_REG_PWRDN 0x00 /* power down */ +#define AK4114_REG_FORMAT 0x01 /* format control */ +#define AK4114_REG_IO0 0x02 /* input/output control */ +#define AK4114_REG_IO1 0x03 /* input/output control */ +#define AK4114_REG_INT0_MASK 0x04 /* interrupt0 mask */ +#define AK4114_REG_INT1_MASK 0x05 /* interrupt1 mask */ +#define AK4114_REG_RCS0 0x06 /* receiver status 0 */ +#define AK4114_REG_RCS1 0x07 /* receiver status 1 */ +#define AK4114_REG_RXCSB0 0x08 /* RX channel status byte 0 */ +#define AK4114_REG_RXCSB1 0x09 /* RX channel status byte 1 */ +#define AK4114_REG_RXCSB2 0x0a /* RX channel status byte 2 */ +#define AK4114_REG_RXCSB3 0x0b /* RX channel status byte 3 */ +#define AK4114_REG_RXCSB4 0x0c /* RX channel status byte 4 */ +#define AK4114_REG_TXCSB0 0x0d /* TX channel status byte 0 */ +#define AK4114_REG_TXCSB1 0x0e /* TX channel status byte 1 */ +#define AK4114_REG_TXCSB2 0x0f /* TX channel status byte 2 */ +#define AK4114_REG_TXCSB3 0x10 /* TX channel status byte 3 */ +#define AK4114_REG_TXCSB4 0x11 /* TX channel status byte 4 */ +#define AK4114_REG_Pc0 0x12 /* burst preamble Pc byte 0 */ +#define AK4114_REG_Pc1 0x13 /* burst preamble Pc byte 1 */ +#define AK4114_REG_Pd0 0x14 /* burst preamble Pd byte 0 */ +#define AK4114_REG_Pd1 0x15 /* burst preamble Pd byte 1 */ +#define AK4114_REG_QSUB_ADDR 0x16 /* Q-subcode address + control */ +#define AK4114_REG_QSUB_TRACK 0x17 /* Q-subcode track */ +#define AK4114_REG_QSUB_INDEX 0x18 /* Q-subcode index */ +#define AK4114_REG_QSUB_MINUTE 0x19 /* Q-subcode minute */ +#define AK4114_REG_QSUB_SECOND 0x1a /* Q-subcode second */ +#define AK4114_REG_QSUB_FRAME 0x1b /* Q-subcode frame */ +#define AK4114_REG_QSUB_ZERO 0x1c /* Q-subcode zero */ +#define AK4114_REG_QSUB_ABSMIN 0x1d /* Q-subcode absolute minute */ +#define AK4114_REG_QSUB_ABSSEC 0x1e /* Q-subcode absolute second */ +#define AK4114_REG_QSUB_ABSFRM 0x1f /* Q-subcode absolute frame */ + +/* sizes */ +#define AK4114_REG_RXCSB_SIZE ((AK4114_REG_RXCSB4-AK4114_REG_RXCSB0)+1) +#define AK4114_REG_TXCSB_SIZE ((AK4114_REG_TXCSB4-AK4114_REG_TXCSB0)+1) +#define AK4114_REG_QSUB_SIZE ((AK4114_REG_QSUB_ABSFRM-AK4114_REG_QSUB_ADDR)+1) + +/* AK4117_REG_PWRDN bits */ +#define AK4114_CS12 (1<<7) /* Channel Status Select */ +#define AK4114_BCU (1<<6) /* Block Start & C/U Output Mode */ +#define AK4114_CM1 (1<<5) /* Master Clock Operation Select */ +#define AK4114_CM0 (1<<4) /* Master Clock Operation Select */ +#define AK4114_OCKS1 (1<<3) /* Master Clock Frequency Select */ +#define AK4114_OCKS0 (1<<2) /* Master Clock Frequency Select */ +#define AK4114_PWN (1<<1) /* 0 = power down, 1 = normal operation */ +#define AK4114_RST (1<<0) /* 0 = reset & initialize (except this register), 1 = normal operation */ + +/* AK4114_REQ_FORMAT bits */ +#define AK4114_MONO (1<<7) /* Double Sampling Frequency Mode: 0 = stereo, 1 = mono */ +#define AK4114_DIF2 (1<<5) /* Audio Data Control */ +#define AK4114_DIF1 (1<<5) /* Audio Data Control */ +#define AK4114_DIF0 (1<<4) /* Audio Data Control */ +#define AK4114_DIF_16R (0) /* STDO: 16-bit, right justified */ +#define AK4114_DIF_18R (AK4114_DIF0) /* STDO: 18-bit, right justified */ +#define AK4114_DIF_20R (AK4114_DIF1) /* STDO: 20-bit, right justified */ +#define AK4114_DIF_24R (AK4114_DIF1|AK4114_DIF0) /* STDO: 24-bit, right justified */ +#define AK4114_DIF_24L (AK4114_DIF2) /* STDO: 24-bit, left justified */ +#define AK4114_DIF_24I2S (AK4114_DIF2|AK4114_DIF0) /* STDO: I2S */ +#define AK4114_DIF_I24L (AK4114_DIF2|AK4114_DIF1) /* STDO: 24-bit, left justified; LRCLK, BICK = Input */ +#define AK4114_DIF_I24I2S (AK4114_DIF2|AK4114_DIF1|AK4114_DIF0) /* STDO: I2S; LRCLK, BICK = Input */ +#define AK4114_DEAU (1<<3) /* Deemphasis Autodetect Enable (1 = enable) */ +#define AK4114_DEM1 (1<<2) /* 32kHz-48kHz Deemphasis Control */ +#define AK4114_DEM0 (1<<1) /* 32kHz-48kHz Deemphasis Control */ +#define AK4114_DEM_44KHZ (0) +#define AK4114_DEM_48KHZ (AK4114_DEM1) +#define AK4114_DEM_32KHZ (AK4114_DEM0|AK4114_DEM1) +#define AK4114_DEM_96KHZ (AK4114_DEM1) /* DFS must be set */ +#define AK4114_DFS (1<<0) /* 96kHz Deemphasis Control */ + +/* AK4114_REG_IO0 */ +#define AK4114_TX1E (1<<7) /* TX1 Output Enable (1 = enable) */ +#define AK4114_OPS12 (1<<2) /* Output Though Data Selector for TX1 pin */ +#define AK4114_OPS11 (1<<1) /* Output Though Data Selector for TX1 pin */ +#define AK4114_OPS10 (1<<0) /* Output Though Data Selector for TX1 pin */ +#define AK4114_TX0E (1<<3) /* TX0 Output Enable (1 = enable) */ +#define AK4114_OPS02 (1<<2) /* Output Though Data Selector for TX0 pin */ +#define AK4114_OPS01 (1<<1) /* Output Though Data Selector for TX0 pin */ +#define AK4114_OPS00 (1<<0) /* Output Though Data Selector for TX0 pin */ + +/* AK4114_REG_IO1 */ +#define AK4114_EFH1 (1<<7) /* Interrupt 0 pin Hold */ +#define AK4114_EFH0 (1<<6) /* Interrupt 0 pin Hold */ +#define AK4114_EFH_512 (0) +#define AK4114_EFH_1024 (AK4114_EFH0) +#define AK4114_EFH_2048 (AK4114_EFH1) +#define AK4114_EFH_4096 (AK4114_EFH1|AK4114_EFH0) +#define AK4114_UDIT (1<<5) /* U-bit Control for DIT (0 = fixed '0', 1 = recovered) */ +#define AK4114_TLR (1<<4) /* Double Sampling Frequency Select for DIT (0 = L channel, 1 = R channel) */ +#define AK4114_DIT (1<<3) /* TX1 out: 0 = Through Data (RX data), 1 = Transmit Data (DAUX data) */ +#define AK4114_IPS2 (1<<2) /* Input Recovery Data Select */ +#define AK4114_IPS1 (1<<1) /* Input Recovery Data Select */ +#define AK4114_IPS0 (1<<0) /* Input Recovery Data Select */ +#define AK4114_IPS(x) ((x)&7) + +/* AK4114_REG_INT0_MASK && AK4114_REG_INT1_MASK*/ +#define AK4117_MQI (1<<7) /* mask enable for QINT bit */ +#define AK4117_MAT (1<<6) /* mask enable for AUTO bit */ +#define AK4117_MCI (1<<5) /* mask enable for CINT bit */ +#define AK4117_MUL (1<<4) /* mask enable for UNLOCK bit */ +#define AK4117_MDTS (1<<3) /* mask enable for DTSCD bit */ +#define AK4117_MPE (1<<2) /* mask enable for PEM bit */ +#define AK4117_MAN (1<<1) /* mask enable for AUDN bit */ +#define AK4117_MPR (1<<0) /* mask enable for PAR bit */ + +/* AK4114_REG_RCS0 */ +#define AK4114_QINT (1<<7) /* Q-subcode buffer interrupt, 0 = no change, 1 = changed */ +#define AK4114_AUTO (1<<6) /* Non-PCM or DTS stream auto detection, 0 = no detect, 1 = detect */ +#define AK4114_CINT (1<<5) /* channel status buffer interrupt, 0 = no change, 1 = change */ +#define AK4114_UNLCK (1<<4) /* PLL lock status, 0 = lock, 1 = unlock */ +#define AK4114_DTSCD (1<<3) /* DTS-CD Detect, 0 = No detect, 1 = Detect */ +#define AK4114_PEM (1<<2) /* Pre-emphasis Detect, 0 = OFF, 1 = ON */ +#define AK4114_AUDION (1<<1) /* audio bit output, 0 = audio, 1 = non-audio */ +#define AK4114_PAR (1<<0) /* parity error or biphase error status, 0 = no error, 1 = error */ + +/* AK4114_REG_RCS1 */ +#define AK4114_FS3 (1<<7) /* sampling frequency detection */ +#define AK4114_FS2 (1<<6) +#define AK4114_FS1 (1<<5) +#define AK4114_FS0 (1<<4) +#define AK4114_FS_44100HZ (0) +#define AK4114_FS_48000HZ (AK4114_FS1) +#define AK4114_FS_32000HZ (AK4114_FS1|AK4114_FS0) +#define AK4114_FS_88200HZ (AK4114_FS3) +#define AK4114_FS_96000HZ (AK4114_FS3|AK4114_FS1) +#define AK4114_FS_176400HZ (AK4114_FS3|AK4114_FS2) +#define AK4114_FS_192000HZ (AK4114_FS3|AK4114_FS2|AK4114_FS1) +#define AK4114_V (1<<3) /* Validity of Channel Status, 0 = Valid, 1 = Invalid */ +#define AK4114_QCRC (1<<1) /* CRC for Q-subcode, 0 = no error, 1 = error */ +#define AK4114_CCRC (1<<0) /* CRC for channel status, 0 = no error, 1 = error */ + +/* flags for snd_ak4114_check_rate_and_errors() */ +#define AK4114_CHECK_NO_STAT (1<<0) /* no statistics */ +#define AK4114_CHECK_NO_RATE (1<<1) /* no rate check */ + +#define AK4114_CONTROLS 14 + +typedef void (ak4114_write_t)(void *private_data, unsigned char addr, unsigned char data); +typedef unsigned char (ak4114_read_t)(void *private_data, unsigned char addr); + +typedef struct ak4114 ak4114_t; + +struct ak4114 { + snd_card_t * card; + ak4114_write_t * write; + ak4114_read_t * read; + void * private_data; + unsigned int init: 1; + spinlock_t lock; + unsigned char regmap[7]; + unsigned char txcsb[5]; + snd_kcontrol_t *kctls[AK4114_CONTROLS]; + snd_pcm_substream_t *playback_substream; + snd_pcm_substream_t *capture_substream; + unsigned long parity_errors; + unsigned long v_bit_errors; + unsigned long qcrc_errors; + unsigned long ccrc_errors; + unsigned char rcs0; + unsigned char rcs1; + struct workqueue_struct *workqueue; + struct work_struct work; + void *change_callback_private; + void (*change_callback)(ak4114_t *ak4114, unsigned char c0, unsigned char c1); +}; + +int snd_ak4114_create(snd_card_t *card, + ak4114_read_t *read, ak4114_write_t *write, + unsigned char pgm[7], unsigned char txcsb[5], + void *private_data, ak4114_t **r_ak4114); +void snd_ak4114_reg_write(ak4114_t *ak4114, unsigned char reg, unsigned char mask, unsigned char val); +void snd_ak4114_reinit(ak4114_t *ak4114); +int snd_ak4114_build(ak4114_t *ak4114, + snd_pcm_substream_t *playback_substream, + snd_pcm_substream_t *capture_substream); +int snd_ak4114_external_rate(ak4114_t *ak4114); +int snd_ak4114_check_rate_and_errors(ak4114_t *ak4114, unsigned int flags); + +#endif /* __SOUND_AK4114_H */ + diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h index 63fc8c703808..e94ac0282318 100644 --- a/include/sound/ak4xxx-adda.h +++ b/include/sound/ak4xxx-adda.h @@ -50,7 +50,8 @@ struct snd_akm4xxx { /* template should fill the following fields */ unsigned int idx_offset; /* control index offset */ enum { - SND_AK4524, SND_AK4528, SND_AK4529, SND_AK4355, SND_AK4381 + SND_AK4524, SND_AK4528, SND_AK4529, + SND_AK4355, SND_AK4358, SND_AK4381 } type; struct snd_ak4xxx_ops ops; }; diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index c2377d0e9a68..2fe023ef00a7 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 2003 by Jaroslav Kysela # +snd-ak4114-objs := ak4114.o snd-ak4117-objs := ak4117.o snd-ak4xxx-adda-objs := ak4xxx-adda.o snd-tea575x-tuner-objs := tea575x-tuner.o @@ -11,4 +12,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.o obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o +obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c new file mode 100644 index 000000000000..6ab04e73c3ca --- /dev/null +++ b/sound/i2c/other/ak4114.c @@ -0,0 +1,581 @@ +/* + * Routines for control of the AK4114 via I2C and 4-wire serial interface + * IEC958 (S/PDIF) receiver by Asahi Kasei + * Copyright (c) by Jaroslav Kysela + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_DESCRIPTION("AK4114 IEC958 (S/PDIF) receiver by Asahi Kasei"); +MODULE_LICENSE("GPL"); + +#define AK4114_ADDR 0x00 /* fixed address */ + +static void ak4114_stats(void *); + +static void reg_write(ak4114_t *ak4114, unsigned char reg, unsigned char val) +{ + ak4114->write(ak4114->private_data, reg, val); + if (reg <= AK4114_REG_INT1_MASK) + ak4114->regmap[reg] = val; + else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4) + ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val; +} + +static inline unsigned char reg_read(ak4114_t *ak4114, unsigned char reg) +{ + return ak4114->read(ak4114->private_data, reg); +} + +#if 0 +static void reg_dump(ak4114_t *ak4114) +{ + int i; + + printk("AK4114 REG DUMP:\n"); + for (i = 0; i < 0x20; i++) + printk("reg[%02x] = %02x (%02x)\n", i, reg_read(ak4114, i), i < sizeof(ak4114->regmap) ? ak4114->regmap[i] : 0); +} +#endif + +static void snd_ak4114_free(ak4114_t *chip) +{ + chip->init = 1; /* don't schedule new work */ + mb(); + if (chip->workqueue != NULL) { + flush_workqueue(chip->workqueue); + destroy_workqueue(chip->workqueue); + } + kfree(chip); +} + +static int snd_ak4114_dev_free(snd_device_t *device) +{ + ak4114_t *chip = device->device_data; + snd_ak4114_free(chip); + return 0; +} + +int snd_ak4114_create(snd_card_t *card, + ak4114_read_t *read, ak4114_write_t *write, + unsigned char pgm[7], unsigned char txcsb[5], + void *private_data, ak4114_t **r_ak4114) +{ + ak4114_t *chip; + int err = 0; + unsigned char reg; + static snd_device_ops_t ops = { + .dev_free = snd_ak4114_dev_free, + }; + + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + spin_lock_init(&chip->lock); + chip->card = card; + chip->read = read; + chip->write = write; + chip->private_data = private_data; + + for (reg = 0; reg < 7; reg++) + chip->regmap[reg] = pgm[reg]; + for (reg = 0; reg < 5; reg++) + chip->txcsb[reg] = txcsb[reg]; + snd_ak4114_reinit(chip); + + chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); + chip->rcs1 = reg_read(chip, AK4114_REG_RCS1); + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) + goto __fail; + + chip->workqueue = create_workqueue("snd-ak4114"); + if (chip->workqueue == NULL) { + err = -ENOMEM; + goto __fail; + } + + if (r_ak4114) + *r_ak4114 = chip; + return 0; + + __fail: + snd_ak4114_free(chip); + return err < 0 ? err : -EIO; +} + +void snd_ak4114_reg_write(ak4114_t *chip, unsigned char reg, unsigned char mask, unsigned char val) +{ + if (reg <= AK4114_REG_INT1_MASK) + reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); + else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) + reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val); +} + +void snd_ak4114_reinit(ak4114_t *chip) +{ + unsigned char old = chip->regmap[AK4114_REG_PWRDN], reg; + + chip->init = 1; + mb(); + flush_workqueue(chip->workqueue); + /* bring the chip to reset state and powerdown state */ + reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN)); + udelay(200); + /* release reset, but leave powerdown */ + reg_write(chip, AK4114_REG_PWRDN, (old | AK4114_RST) & ~AK4114_PWN); + udelay(200); + for (reg = 1; reg < 7; reg++) + reg_write(chip, reg, chip->regmap[reg]); + for (reg = 0; reg < 5; reg++) + reg_write(chip, reg + AK4114_REG_TXCSB0, chip->txcsb[reg]); + /* release powerdown, everything is initialized now */ + reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); + /* bring up statistics / event queing */ + chip->init = 0; + INIT_WORK(&chip->work, ak4114_stats, chip); + queue_delayed_work(chip->workqueue, &chip->work, 1); +} + +static unsigned int external_rate(unsigned char rcs1) +{ + switch (rcs1 & (AK4114_FS0|AK4114_FS1|AK4114_FS2|AK4114_FS3)) { + case AK4114_FS_32000HZ: return 32000; + case AK4114_FS_44100HZ: return 44100; + case AK4114_FS_48000HZ: return 48000; + case AK4114_FS_88200HZ: return 88200; + case AK4114_FS_96000HZ: return 96000; + case AK4114_FS_176400HZ: return 176400; + case AK4114_FS_192000HZ: return 192000; + default: return 0; + } +} + +static int snd_ak4114_in_error_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = LONG_MAX; + return 0; +} + +static int snd_ak4114_in_error_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + long *ptr; + + spin_lock_irq(&chip->lock); + ptr = (long *)(((char *)chip) + kcontrol->private_value); + ucontrol->value.integer.value[0] = *ptr; + *ptr = 0; + spin_unlock_irq(&chip->lock); + return 0; +} + +static int snd_ak4114_in_bit_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ak4114_in_bit_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + unsigned char reg = kcontrol->private_value & 0xff; + unsigned char bit = (kcontrol->private_value >> 8) & 0xff; + unsigned char inv = (kcontrol->private_value >> 31) & 1; + + ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; + return 0; +} + +static int snd_ak4114_rate_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 192000; + return 0; +} + +static int snd_ak4114_rate_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4114_REG_RCS1)); + return 0; +} + +static int snd_ak4114_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int snd_ak4114_spdif_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4114_REG_RXCSB_SIZE; i++) + ucontrol->value.iec958.status[i] = reg_read(chip, AK4114_REG_RXCSB0 + i); + return 0; +} + +static int snd_ak4114_spdif_playback_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4114_REG_TXCSB_SIZE; i++) + ucontrol->value.iec958.status[i] = chip->txcsb[i]; + return 0; +} + +static int snd_ak4114_spdif_playback_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4114_REG_TXCSB_SIZE; i++) + reg_write(chip, AK4114_REG_TXCSB0 + i, ucontrol->value.iec958.status[i]); + return 0; +} + +static int snd_ak4114_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int snd_ak4114_spdif_mask_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + memset(ucontrol->value.iec958.status, 0xff, AK4114_REG_RXCSB_SIZE); + return 0; +} + +static int snd_ak4114_spdif_pinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffff; + uinfo->count = 4; + return 0; +} + +static int snd_ak4114_spdif_pget(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + unsigned short tmp; + + ucontrol->value.integer.value[0] = 0xf8f2; + ucontrol->value.integer.value[1] = 0x4e1f; + tmp = reg_read(chip, AK4114_REG_Pc0) | (reg_read(chip, AK4114_REG_Pc1) << 8); + ucontrol->value.integer.value[2] = tmp; + tmp = reg_read(chip, AK4114_REG_Pd0) | (reg_read(chip, AK4114_REG_Pd1) << 8); + ucontrol->value.integer.value[3] = tmp; + return 0; +} + +static int snd_ak4114_spdif_qinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = AK4114_REG_QSUB_SIZE; + return 0; +} + +static int snd_ak4114_spdif_qget(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4114_t *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4114_REG_QSUB_SIZE; i++) + ucontrol->value.bytes.data[i] = reg_read(chip, AK4114_REG_QSUB_ADDR + i); + return 0; +} + +/* Don't forget to change AK4114_CONTROLS define!!! */ +static snd_kcontrol_new_t snd_ak4114_iec958_controls[] = { +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Parity Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_in_error_info, + .get = snd_ak4114_in_error_get, + .private_value = offsetof(ak4114_t, parity_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 V-Bit Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_in_error_info, + .get = snd_ak4114_in_error_get, + .private_value = offsetof(ak4114_t, v_bit_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 C-CRC Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_in_error_info, + .get = snd_ak4114_in_error_get, + .private_value = offsetof(ak4114_t, ccrc_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Q-CRC Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_in_error_info, + .get = snd_ak4114_in_error_get, + .private_value = offsetof(ak4114_t, qcrc_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 External Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_rate_info, + .get = snd_ak4114_rate_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_ak4114_spdif_mask_info, + .get = snd_ak4114_spdif_mask_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_spdif_info, + .get = snd_ak4114_spdif_playback_get, + .get = snd_ak4114_spdif_playback_put, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_ak4114_spdif_mask_info, + .get = snd_ak4114_spdif_mask_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_spdif_info, + .get = snd_ak4114_spdif_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Preample Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_spdif_pinfo, + .get = snd_ak4114_spdif_pget, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Q-subcode Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_spdif_qinfo, + .get = snd_ak4114_spdif_qget, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Audio", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_in_bit_info, + .get = snd_ak4114_in_bit_get, + .private_value = (1<<31) | (1<<8) | AK4114_REG_RCS0, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Non-PCM Bitstream", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_in_bit_info, + .get = snd_ak4114_in_bit_get, + .private_value = (6<<8) | AK4114_REG_RCS1, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 DTS Bitstream", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4114_in_bit_info, + .get = snd_ak4114_in_bit_get, + .private_value = (3<<8) | AK4114_REG_RCS1, +} +}; + +int snd_ak4114_build(ak4114_t *ak4114, + snd_pcm_substream_t *ply_substream, + snd_pcm_substream_t *cap_substream) +{ + snd_kcontrol_t *kctl; + unsigned int idx; + int err; + + snd_assert(cap_substream, return -EINVAL); + ak4114->playback_substream = ply_substream; + ak4114->capture_substream = cap_substream; + for (idx = 0; idx < AK4114_CONTROLS; idx++) { + kctl = snd_ctl_new1(&snd_ak4114_iec958_controls[idx], ak4114); + if (kctl == NULL) + return -ENOMEM; + if (!strstr(kctl->id.name, "Playback")) { + if (ply_substream == NULL) { + snd_ctl_free_one(kctl); + ak4114->kctls[idx] = NULL; + continue; + } + kctl->id.device = ply_substream->pcm->device; + kctl->id.subdevice = ply_substream->number; + } else { + kctl->id.device = cap_substream->pcm->device; + kctl->id.subdevice = cap_substream->number; + } + err = snd_ctl_add(ak4114->card, kctl); + if (err < 0) + return err; + ak4114->kctls[idx] = kctl; + } + return 0; +} + +int snd_ak4114_external_rate(ak4114_t *ak4114) +{ + unsigned char rcs1; + + rcs1 = reg_read(ak4114, AK4114_REG_RCS1); + return external_rate(rcs1); +} + +int snd_ak4114_check_rate_and_errors(ak4114_t *ak4114, unsigned int flags) +{ + snd_pcm_runtime_t *runtime = ak4114->capture_substream ? ak4114->capture_substream->runtime : NULL; + unsigned long _flags; + int res = 0; + unsigned char rcs0, rcs1; + unsigned char c0, c1; + + rcs1 = reg_read(ak4114, AK4114_REG_RCS1); + if (flags & AK4114_CHECK_NO_STAT) + goto __rate; + rcs0 = reg_read(ak4114, AK4114_REG_RCS0); + printk("AK4114 IRQ: rcs0 = 0x%x, rcs1 = 0x%x\n", rcs0, rcs1); + return 0; + spin_lock_irqsave(&ak4114->lock, _flags); + if (rcs0 & AK4114_PAR) + ak4114->parity_errors++; + if (rcs1 & AK4114_V) + ak4114->v_bit_errors++; + if (rcs1 & AK4114_CCRC) + ak4114->ccrc_errors++; + if (rcs1 & AK4114_QCRC) + ak4114->qcrc_errors++; + c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^ + (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)); + c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0); + ak4114->rcs0 = rcs0 & ~(AK4114_QINT | AK4114_CINT); + ak4114->rcs1 = rcs1; + spin_unlock_irqrestore(&ak4114->lock, _flags); + + if (rcs0 & AK4114_PAR) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[0]->id); + if (rcs0 & AK4114_V) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[1]->id); + if (rcs1 & AK4114_CCRC) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[2]->id); + if (rcs1 & AK4114_QCRC) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[3]->id); + + /* rate change */ + if (c1 & 0xf0) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[4]->id); + + if ((c0 & AK4114_PEM) | (c0 & AK4114_CINT)) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[9]->id); + if (c0 & AK4114_QINT) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[10]->id); + + if (c0 & AK4114_AUDION) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[11]->id); + if (c0 & AK4114_AUTO) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[12]->id); + if (c0 & AK4114_DTSCD) + snd_ctl_notify(ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4114->kctls[13]->id); + + if (ak4114->change_callback && (c0 | c1) != 0) + ak4114->change_callback(ak4114, c0, c1); + + __rate: + /* compare rate */ + res = external_rate(rcs1); + if (!(flags & AK4114_CHECK_NO_RATE) && runtime && runtime->rate != res) { + snd_pcm_stream_lock_irqsave(ak4114->capture_substream, _flags); + if (snd_pcm_running(ak4114->capture_substream)) { + // printk("rate changed (%i <- %i)\n", runtime->rate, res); + snd_pcm_stop(ak4114->capture_substream, SNDRV_PCM_STATE_DRAINING); + wake_up(&runtime->sleep); + res = 1; + } + snd_pcm_stream_unlock_irqrestore(ak4114->capture_substream, _flags); + } + return res; +} + +static void ak4114_stats(void *data) +{ + ak4114_t *chip = (ak4114_t *)data; + + if (chip->init) + return; + snd_ak4114_check_rate_and_errors(chip, 0); + queue_delayed_work(chip->workqueue, &chip->work, 1); +} + +EXPORT_SYMBOL(snd_ak4114_create); +EXPORT_SYMBOL(snd_ak4114_reg_write); +EXPORT_SYMBOL(snd_ak4114_reinit); +EXPORT_SYMBOL(snd_ak4114_build); +EXPORT_SYMBOL(snd_ak4114_external_rate); +EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors); diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index abd82625bfd8..8f176b7129a8 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -1,8 +1,8 @@ /* - * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4381 + * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381 * AD and DA converters * - * Copyright (c) 2000-2003 Jaroslav Kysela , + * Copyright (c) 2000-2004 Jaroslav Kysela , * Takashi Iwai * * This program is free software; you can redistribute it and/or modify @@ -84,6 +84,7 @@ void snd_akm4xxx_reset(akm4xxx_t *ak, int state) /* FIXME: needed for ak4529? */ break; case SND_AK4355: + case SND_AK4358: if (state) { snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */ return; @@ -166,6 +167,24 @@ void snd_akm4xxx_init(akm4xxx_t *ak) 0x01, 0x01, /* 1: un-reset, unmute */ 0xff, 0xff }; + static unsigned char inits_ak4358[] = { + 0x01, 0x02, /* 1: reset and soft-mute */ + 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */ + 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */ + // 0x02, 0x2e, /* quad speed */ + 0x03, 0x01, /* 3: de-emphasis off */ + 0x04, 0x00, /* 4: LOUT1 volume muted */ + 0x05, 0x00, /* 5: ROUT1 volume muted */ + 0x06, 0x00, /* 6: LOUT2 volume muted */ + 0x07, 0x00, /* 7: ROUT2 volume muted */ + 0x08, 0x00, /* 8: LOUT3 volume muted */ + 0x09, 0x00, /* 9: ROUT3 volume muted */ + 0x0b, 0x00, /* b: LOUT4 volume muted */ + 0x0c, 0x00, /* c: ROUT4 volume muted */ + 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */ + 0x01, 0x01, /* 1: un-reset, unmute */ + 0xff, 0xff + }; static unsigned char inits_ak4381[] = { 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ 0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */ @@ -197,6 +216,10 @@ void snd_akm4xxx_init(akm4xxx_t *ak) inits = inits_ak4355; num_chips = 1; break; + case SND_AK4358: + inits = inits_ak4358; + num_chips = 1; + break; case SND_AK4381: inits = inits_ak4381; num_chips = ak->num_dacs / 2; @@ -370,6 +393,12 @@ int snd_akm4xxx_build_controls(akm4xxx_t *ak) 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; @@ -407,7 +436,7 @@ int snd_akm4xxx_build_controls(akm4xxx_t *ak) if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) return err; } - if (ak->type == SND_AK4355) + if (ak->type == SND_AK4355 || ak->type == SND_AK4358) num_emphs = 1; else num_emphs = ak->num_dacs / 2; @@ -432,6 +461,7 @@ int snd_akm4xxx_build_controls(akm4xxx_t *ak) break; } case SND_AK4355: + case SND_AK4358: ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); break; case SND_AK4381: diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 8b5e37cf8c6e..2af5b62d0a17 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c index 3c6129f320e6..ae9dc029ba0d 100644 --- a/sound/pci/ice1712/ak4xxx.c +++ b/sound/pci/ice1712/ak4xxx.c @@ -126,12 +126,16 @@ int snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *temp, { struct snd_ak4xxx_private *priv; - priv = kmalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; + if (_priv != NULL) { + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + *priv = *_priv; + } else { + priv = NULL; + } *ak = *temp; ak->card = ice->card; - *priv = *_priv; ak->private_value[0] = (unsigned long)priv; ak->private_data[0] = ice; if (ak->ops.lock == NULL) diff --git a/sound/pci/ice1712/envy24ht.h b/sound/pci/ice1712/envy24ht.h index 375e5fb00c87..f7878020eaa3 100644 --- a/sound/pci/ice1712/envy24ht.h +++ b/sound/pci/ice1712/envy24ht.h @@ -106,7 +106,7 @@ enum { #define VT1724_REG_I2C_BYTE_ADDR 0x11 /* byte */ #define VT1724_REG_I2C_DATA 0x12 /* byte */ #define VT1724_REG_I2C_CTRL 0x13 /* byte */ -#define VT1724_I2C_EEPROM 0x80 /* EEPROM exists */ +#define VT1724_I2C_EEPROM 0x80 /* 1 = EEPROM exists */ #define VT1724_I2C_BUSY 0x01 /* busy bit */ #define VT1724_REG_GPIO_DATA 0x14 /* word */ diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index fddd9e0e5c43..79fba6be3503 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1014,21 +1014,9 @@ static int snd_ice1712_pro_trigger(snd_pcm_substream_t *substream, static void snd_ice1712_set_pro_rate(ice1712_t *ice, unsigned int rate, int force) { unsigned long flags; - unsigned char val; + unsigned char val, old; unsigned int i; - spin_lock_irqsave(&ice->reg_lock, flags); - if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW| - ICE1712_PLAYBACK_PAUSE| - ICE1712_PLAYBACK_START)) { - spin_unlock_irqrestore(&ice->reg_lock, flags); - return; - } - if (!force && is_pro_rate_locked(ice)) { - spin_unlock_irqrestore(&ice->reg_lock, flags); - return; - } - switch (rate) { case 8000: val = 6; break; case 9600: val = 3; break; @@ -1049,8 +1037,22 @@ static void snd_ice1712_set_pro_rate(ice1712_t *ice, unsigned int rate, int forc rate = 48000; break; } - outb(val, ICEMT(ice, RATE)); + spin_lock_irqsave(&ice->reg_lock, flags); + if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW| + ICE1712_PLAYBACK_PAUSE| + ICE1712_PLAYBACK_START)) { + __out: + spin_unlock_irqrestore(&ice->reg_lock, flags); + return; + } + if (!force && is_pro_rate_locked(ice)) + goto __out; + + old = inb(ICEMT(ice, RATE)); + if (!force && old == val) + goto __out; + outb(val, ICEMT(ice, RATE)); spin_unlock_irqrestore(&ice->reg_lock, flags); if (ice->gpio.set_pro_rate) @@ -2405,6 +2407,7 @@ static int __devinit snd_ice1712_chip_init(ice1712_t *ice) udelay(200); snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0); } + snd_ice1712_set_pro_rate(ice, 48000, 1); return 0; } @@ -2545,6 +2548,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card, ice->cs8427_timeout = cs8427_timeout; spin_lock_init(&ice->reg_lock); init_MUTEX(&ice->gpio_mutex); + init_MUTEX(&ice->i2c_mutex); init_MUTEX(&ice->open_mutex); ice->gpio.set_mask = snd_ice1712_set_gpio_mask; ice->gpio.set_dir = snd_ice1712_set_gpio_dir; diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 4464dd8adf37..e88083da928d 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -340,6 +341,7 @@ struct _snd_ice1712 { akm4xxx_t *akm; struct snd_ice1712_spdif spdif; + struct semaphore i2c_mutex; /* I2C mutex for ICE1724 registers */ snd_i2c_bus_t *i2c; /* I2C bus */ snd_i2c_device_t *cs8427; /* CS8427 I2C device */ unsigned int cs8427_timeout; /* CS8427 reset timeout in HZ/100 */ @@ -355,12 +357,13 @@ struct _snd_ice1712 { unsigned int (*get_data)(ice1712_t *ice); /* misc operators - move to another place? */ void (*set_pro_rate)(ice1712_t *ice, unsigned int rate); + void (*i2s_mclk_changed)(ice1712_t *ice); } gpio; struct semaphore gpio_mutex; /* other board-specific data */ union { - /* additional i2c devices for EWS boards*/ + /* additional i2c devices for EWS boards */ snd_i2c_device_t *i2cdevs[3]; /* AC97 register cache for Aureon */ struct aureon_spec { @@ -375,6 +378,10 @@ struct _snd_ice1712 { unsigned int config; unsigned short boxconfig[4]; } hoontech; + struct { + ak4114_t *ak4114; + unsigned int analog: 1; + } juli; } spec; }; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ce70e510a450..30e90409b90b 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -47,6 +47,7 @@ #include "vt1720_mobo.h" #include "pontis.h" #include "prodigy192.h" +#include "juli.h" MODULE_AUTHOR("Jaroslav Kysela "); @@ -59,6 +60,7 @@ MODULE_SUPPORTED_DEVICE("{" VT1720_MOBO_DEVICE_DESC PONTIS_DEVICE_DESC PRODIGY192_DEVICE_DESC + JULI_DEVICE_DESC "{VIA,VT1720}," "{VIA,VT1724}," "{ICEnsemble,Generic ICE1724}," @@ -401,23 +403,11 @@ static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force { unsigned long flags; unsigned char val, old; - unsigned int i; + unsigned int i, mclk_change; if (rate > get_max_rate(ice)) return; - spin_lock_irqsave(&ice->reg_lock, flags); - if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || - (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { - /* running? we cannot change the rate now... */ - spin_unlock_irqrestore(&ice->reg_lock, flags); - return; - } - if (!force && is_pro_rate_locked(ice)) { - spin_unlock_irqrestore(&ice->reg_lock, flags); - return; - } - switch (rate) { case 8000: val = 6; break; case 9600: val = 3; break; @@ -439,8 +429,21 @@ static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force val = 0; break; } + + spin_lock_irqsave(&ice->reg_lock, flags); + if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || + (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { + /* running? we cannot change the rate now... */ + spin_unlock_irqrestore(&ice->reg_lock, flags); + return; + } + if (!force && is_pro_rate_locked(ice)) { + spin_unlock_irqrestore(&ice->reg_lock, flags); + return; + } + old = inb(ICEMT1724(ice, RATE)); - if (old != val) + if (force || old != val) outb(val, ICEMT1724(ice, RATE)); else if (rate == ice->cur_rate) { spin_unlock_irqrestore(&ice->reg_lock, flags); @@ -450,6 +453,7 @@ static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force ice->cur_rate = rate; /* check MT02 */ + mclk_change = 0; if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) { val = old = inb(ICEMT1724(ice, I2S_FORMAT)); if (rate > 96000) @@ -458,25 +462,23 @@ static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */ if (val != old) { outb(val, ICEMT1724(ice, I2S_FORMAT)); - if (ice->eeprom.subvendor == VT1724_SUBDEVICE_REVOLUTION71) { - /* FIXME: is this revo only? */ - /* assert PRST# to converters; MT05 bit 7 */ - outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); - spin_unlock_irqrestore(&ice->reg_lock, flags); - mdelay(5); - spin_lock_irqsave(&ice->reg_lock, flags); - /* deassert PRST# */ - outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); - } + mclk_change = 1; } } spin_unlock_irqrestore(&ice->reg_lock, flags); + if (mclk_change && ice->gpio.i2s_mclk_changed) + ice->gpio.i2s_mclk_changed(ice); + if (ice->gpio.set_pro_rate) + ice->gpio.set_pro_rate(ice, rate); + /* set up codecs */ for (i = 0; i < ice->akm_codecs; i++) { if (ice->akm[i].ops.set_rate_val) ice->akm[i].ops.set_rate_val(&ice->akm[i], rate); } + if (ice->spdif.ops.setup_rate) + ice->spdif.ops.setup_rate(ice, rate); } static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream, @@ -1866,6 +1868,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1720_mobo_cards, snd_vt1720_pontis_cards, snd_vt1724_prodigy192_cards, + snd_vt1724_juli_cards, NULL, }; @@ -1878,23 +1881,34 @@ static void wait_i2c_busy(ice1712_t *ice) int t = 0x10000; while ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY) && t--) ; + if (t == -1) + printk(KERN_ERR "ice1724: i2c busy timeout\n"); } unsigned char snd_vt1724_read_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr) { + unsigned char val; + + down(&ice->i2c_mutex); outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); wait_i2c_busy(ice); - return inb(ICEREG1724(ice, I2C_DATA)); + val = inb(ICEREG1724(ice, I2C_DATA)); + up(&ice->i2c_mutex); + //printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); + return val; } void snd_vt1724_write_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr, unsigned char data) { + down(&ice->i2c_mutex); wait_i2c_busy(ice); + //printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(data, ICEREG1724(ice, I2C_DATA)); outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); wait_i2c_busy(ice); + up(&ice->i2c_mutex); } static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice, const char *modelname) @@ -1906,7 +1920,8 @@ static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice, const char *modelnam if (! modelname || ! *modelname) { ice->eeprom.subvendor = 0; if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) != 0) - ice->eeprom.subvendor = (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) | + ice->eeprom.subvendor = + (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) | (snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | (snd_vt1724_read_i2c(ice, dev, 0x02) << 16) | (snd_vt1724_read_i2c(ice, dev, 0x03) << 24); @@ -2114,6 +2129,7 @@ static int __devinit snd_vt1724_create(snd_card_t * card, spin_lock_init(&ice->reg_lock); init_MUTEX(&ice->gpio_mutex); init_MUTEX(&ice->open_mutex); + init_MUTEX(&ice->i2c_mutex); ice->gpio.set_mask = snd_vt1724_set_gpio_mask; ice->gpio.set_dir = snd_vt1724_set_gpio_dir; ice->gpio.set_data = snd_vt1724_set_gpio_data; diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c new file mode 100644 index 000000000000..3fb297b969cd --- /dev/null +++ b/sound/pci/ice1712/juli.c @@ -0,0 +1,230 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for ESI Juli@ cards + * + * Copyright (c) 2004 Jaroslav Kysela + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "envy24ht.h" +#include "juli.h" + +/* + * chip addresses on I2C bus + */ +#define AK4114_ADDR 0x20 /* S/PDIF receiver */ +#define AK4358_ADDR 0x22 /* DAC */ + +/* + * GPIO pins + */ +#define GPIO_FREQ_MASK (3<<0) +#define GPIO_FREQ_32KHZ (0<<0) +#define GPIO_FREQ_44KHZ (1<<0) +#define GPIO_FREQ_48KHZ (2<<0) +#define GPIO_MULTI_MASK (3<<2) +#define GPIO_MULTI_4X (0<<2) +#define GPIO_MULTI_2X (1<<2) +#define GPIO_MULTI_1X (2<<2) /* also external */ +#define GPIO_MULTI_HALF (3<<2) +#define GPIO_INTERNAL_CLOCK (1<<4) +#define GPIO_ANALOG_PRESENT (1<<5) /* RO only: 0 = present */ +#define GPIO_RXMCLK_SEL (1<<7) /* must be 0 */ +#define GPIO_AK5385A_CKS0 (1<<8) +#define GPIO_AK5385A_DFS0 (1<<9) /* swapped with DFS1 according doc? */ +#define GPIO_AK5385A_DFS1 (1<<10) +#define GPIO_DIGOUT_MONITOR (1<<11) /* 1 = active */ +#define GPIO_DIGIN_MONITOR (1<<12) /* 1 = active */ +#define GPIO_ANAIN_MONITOR (1<<13) /* 1 = active */ +#define GPIO_AK5385A_MCLK (1<<14) /* must be 0 */ +#define GPIO_MUTE_CONTROL (1<<15) /* 0 = off, 1 = on */ + +static void juli_ak4114_write(void *private_data, unsigned char reg, unsigned char val) +{ + snd_vt1724_write_i2c((ice1712_t *)private_data, AK4114_ADDR, reg, val); +} + +static unsigned char juli_ak4114_read(void *private_data, unsigned char reg) +{ + return snd_vt1724_read_i2c((ice1712_t *)private_data, AK4114_ADDR, reg); +} + +/* + * AK4358 section + */ + +static void juli_akm_lock(akm4xxx_t *ak, int chip) +{ +} + +static void juli_akm_unlock(akm4xxx_t *ak, int chip) +{ +} + +static void juli_akm_write(akm4xxx_t *ak, int chip, + unsigned char addr, unsigned char data) +{ + ice1712_t *ice = ak->private_data[0]; + + snd_assert(chip == 0, return); + snd_vt1724_write_i2c(ice, AK4358_ADDR, addr, data); +} + +/* + * change the rate of envy24HT, AK4358 + */ +static void juli_akm_set_rate_val(akm4xxx_t *ak, unsigned int rate) +{ + unsigned char old, tmp, dfs; + + if (rate == 0) /* no hint - S/PDIF input is master, simply return */ + return; + + /* adjust DFS on codecs */ + if (rate > 96000) + dfs = 2; + else if (rate > 48000) + dfs = 1; + else + dfs = 0; + + tmp = snd_akm4xxx_get(ak, 0, 2); + old = (tmp >> 4) & 0x03; + if (old == dfs) + return; + /* reset DFS */ + snd_akm4xxx_reset(ak, 1); + tmp = snd_akm4xxx_get(ak, 0, 2); + tmp &= ~(0x03 << 4); + tmp |= dfs << 4; + snd_akm4xxx_set(ak, 0, 2, tmp); + snd_akm4xxx_reset(ak, 0); +} + +static akm4xxx_t akm_juli_dac __devinitdata = { + .type = SND_AK4358, + .num_dacs = 2, + .ops = { + .lock = juli_akm_lock, + .unlock = juli_akm_unlock, + .write = juli_akm_write, + .set_rate_val = juli_akm_set_rate_val + } +}; + +static int __devinit juli_add_controls(ice1712_t *ice) +{ + return snd_ice1712_akm4xxx_build_controls(ice); +} + +/* + * initialize the chip + */ +static int __devinit juli_init(ice1712_t *ice) +{ + static unsigned char ak4114_init_vals[] = { + /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, + /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S, + /* AK4114_REG_IO0 */ AK4114_TX1E, + /* AK4114_REG_IO1 */ AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1), + /* AK4114_REG_INT0_MASK */ 0, + /* AK4114_REG_INT1_MASK */ 0 + }; + static unsigned char ak4114_init_txcsb[] = { + 0x41, 0x02, 0x2c, 0x00, 0x00 + }; + int err; + akm4xxx_t *ak; + +#if 0 + for (err = 0; err < 0x20; err++) + juli_ak4114_read(ice, err); + juli_ak4114_write(ice, 0, 0x0f); + juli_ak4114_read(ice, 0); + juli_ak4114_read(ice, 1); +#endif + err = snd_ak4114_create(ice->card, + juli_ak4114_read, + juli_ak4114_write, + ak4114_init_vals, ak4114_init_txcsb, + ice, &ice->spec.juli.ak4114); + if (err < 0) + return err; + + ice->spec.juli.analog = ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT; + + if (ice->spec.juli.analog) { + printk(KERN_INFO "juli@: analog I/O detected\n"); + ice->num_total_dacs = 2; + ice->num_total_adcs = 2; + + ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + if (! ak) + return -ENOMEM; + ice->akm_codecs = 1; + if ((err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice)) < 0) + return err; + } + + return 0; +} + + +/* + * Juli@ boards don't provide the EEPROM data except for the vendor IDs. + * hence the driver needs to sets up it properly. + */ + +static unsigned char juli_eeprom[] __devinitdata = { + 0x20, /* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */ + 0x80, /* ACLINK: I2S */ + 0xf8, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDIF: out-en, out-int, spdif-in */ + 0x9f, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x7f, /* GPIO_DIR2 */ + 0x9f, /* GPIO_MASK */ + 0xff, /* GPIO_MASK1 */ + 0x7f, /* GPIO_MASK2 */ + 0x16, /* GPIO_STATE: internal clock, multiple 1x, 48kHz */ + 0x80, /* GPIO_STATE1: mute */ + 0x00, /* GPIO_STATE2 */ +}; + +/* entry point */ +struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_JULI, + .name = "ESI Juli@", + .model = "juli", + .chip_init = juli_init, + .build_controls = juli_add_controls, + .eeprom_size = sizeof(juli_eeprom), + .eeprom_data = juli_eeprom, + }, + { } /* terminator */ +}; diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h new file mode 100644 index 000000000000..d9f8534fd92e --- /dev/null +++ b/sound/pci/ice1712/juli.h @@ -0,0 +1,10 @@ +#ifndef __SOUND_JULI_H +#define __SOUND_JULI_H + +#define JULI_DEVICE_DESC "{ESI,Juli@}," + +#define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */ + +extern struct snd_ice1712_card_info snd_vt1724_juli_cards[]; + +#endif /* __SOUND_JULI_H */ diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index c8f59a24db03..d2c5963795d7 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -36,12 +36,12 @@ #include "prodigy192.h" #include "stac946x.h" -static void stac9460_put(ice1712_t *ice, int reg, unsigned char val) +static inline void stac9460_put(ice1712_t *ice, int reg, unsigned char val) { snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); } -static unsigned char stac9460_get(ice1712_t *ice, int reg) +static inline unsigned char stac9460_get(ice1712_t *ice, int reg) { return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg); } diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index 82db619b22b6..1fe21009ca84 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -33,6 +33,15 @@ #include "envy24ht.h" #include "revo.h" +static void revo_i2s_mclk_changed(ice1712_t *ice) +{ + /* assert PRST# to converters; MT05 bit 7 */ + outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); + mdelay(5); + /* deassert PRST# */ + outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); +} + /* * change the rate of envy24HT, AK4355 and AK4381 */ @@ -135,6 +144,8 @@ static int __devinit revo_init(ice1712_t *ice) return -EINVAL; } + ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed; + /* second stage of initialization, analog parts and others */ ak = ice->akm = kcalloc(2, sizeof(akm4xxx_t), GFP_KERNEL); if (! ak) -- cgit v1.2.3 From cb72b251efa6a0bddf4aea6f278656f379787fb4 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 14 Feb 2005 18:03:46 +0100 Subject: [ALSA] Remove unused yss225.h Wavefront drivers yss225.h is just obsolete, not used/read by any codes. Let's remove it. Signed-off-by: Takashi Iwai --- include/sound/yss225.h | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 include/sound/yss225.h (limited to 'include') diff --git a/include/sound/yss225.h b/include/sound/yss225.h deleted file mode 100644 index 13b2655e4a92..000000000000 --- a/include/sound/yss225.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __SOUND_YSS225_H -#define __SOUND_YSS225_H - -extern unsigned char page_zero[256]; -extern unsigned char page_one[256]; -extern unsigned char page_two[128]; -extern unsigned char page_three[128]; -extern unsigned char page_four[128]; -extern unsigned char page_six[192]; -extern unsigned char page_seven[256]; -extern unsigned char page_zero_v2[96]; -extern unsigned char page_one_v2[96]; -extern unsigned char page_two_v2[48]; -extern unsigned char page_three_v2[48]; -extern unsigned char page_four_v2[48]; -extern unsigned char page_seven_v2[96]; -extern unsigned char mod_v2[304]; -extern unsigned char coefficients[364]; -extern unsigned char coefficients2[56]; -extern unsigned char coefficients3[404]; - - -#endif /* __SOUND_YSS225_H */ -- cgit v1.2.3 From 3acd4a9a940177d89b5831582ac7392d9948f52d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 2 Mar 2005 16:25:34 +0100 Subject: [ALSA] emu10k1 driver - add multichannel device hw:x,3 [1/8] EMU10K1/EMU10K2 driver Update header file for multichannel support. Add some new register info. Signed-Off-By: Lee Revell Signed-off-by: Jaroslav Kysela --- include/sound/emu10k1.h | 93 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index fd623d13dbcc..c5fd57b862d8 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -51,7 +51,9 @@ #define NUM_MIDI 16 #define NUM_G 64 /* use all channels */ #define NUM_FXSENDS 4 +#define NUM_EFX_PLAYBACK 16 +/* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */ #define EMU10K1_DMA_MASK 0x7fffffffUL /* 31bit */ #define AUDIGY_DMA_MASK 0xffffffffUL /* 32bit */ @@ -82,10 +84,16 @@ /* Clear pending interrupts by writing a 1 to */ /* the relevant bits and zero to the other bits */ +#define IPR_GPIOMSG 0x20000000 /* GPIO message interrupt (RE'd, still not sure + which INTE bits enable it) */ + /* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */ #define IPR_A_MIDITRANSBUFEMPTY2 0x10000000 /* MIDI UART transmit buffer empty */ #define IPR_A_MIDIRECVBUFEMPTY2 0x08000000 /* MIDI UART receive buffer empty */ +#define IPR_SPDIFBUFFULL 0x04000000 /* SPDIF capture related, 10k2 only? (RE) */ +#define IPR_SPDIFBUFHALFFULL 0x02000000 /* SPDIF capture related? (RE) */ + #define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */ #define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */ #define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */ @@ -104,12 +112,12 @@ #define IPR_INTERVALTIMER 0x00000200 /* Interval timer terminal count */ #define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */ #define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */ -#define IPR_CHANNELLOOP 0x00000040 /* One or more channel loop interrupts pending */ +#define IPR_CHANNELLOOP 0x00000040 /* Channel (half) loop interrupt(s) pending */ #define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */ - /* Highest set channel in CLIPL or CLIPH. When */ - /* IP is written with CL set, the bit in CLIPL */ - /* or CLIPH corresponding to the CIN value */ - /* written will be cleared. */ + /* highest set channel in CLIPL, CLIPH, HLIPL, */ + /* or HLIPH. When IP is written with CL set, */ + /* the bit in H/CLIPL or H/CLIPH corresponding */ + /* to the CIN value written will be cleared. */ #define INTE 0x0c /* Interrupt enable register */ #define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */ @@ -236,9 +244,27 @@ #define A_IOCFG 0x18 /* GPIO on Audigy card (16bits) */ #define A_GPINPUT_MASK 0xff00 #define A_GPOUTPUT_MASK 0x00ff -#define A_IOCFG_GPOUT0 0x0044 /* analog/digital? */ -#define A_IOCFG_GPOUT1 0x0002 /* IR */ + +// Audigy output/GPIO stuff taken from the kX drivers +#define A_IOCFG_GPOUT0 0x0044 /* analog/digital */ +#define A_IOCFG_DISABLE_ANALOG 0x0040 /* = 'enable' for Audigy2 (chiprev=4) */ +#define A_IOCFG_ENABLE_DIGITAL 0x0004 +#define A_IOCFG_UNKNOWN_20 0x0020 +#define A_IOCFG_DISABLE_AC97_FRONT 0x0080 /* turn off ac97 front -> front (10k2.1) */ +#define A_IOCFG_GPOUT1 0x0002 /* IR? drive's internal bypass (?) */ #define A_IOCFG_GPOUT2 0x0001 /* IR */ +#define A_IOCFG_MULTIPURPOSE_JACK 0x2000 /* center+lfe+rear_center (a2/a2ex) */ + /* + digital for generic 10k2 */ +#define A_IOCFG_DIGITAL_JACK 0x1000 /* digital for a2 platinum */ +#define A_IOCFG_FRONT_JACK 0x4000 +#define A_IOCFG_REAR_JACK 0x8000 +#define A_IOCFG_PHONES_JACK 0x0100 /* LiveDrive */ + +/* outputs: + * for audigy2 platinum: 0xa00 + * for a2 platinum ex: 0x1c00 + * for a1 platinum: 0x0 + */ #define TIMER 0x1a /* Timer terminal count register */ /* NOTE: After the rate is changed, a maximum */ @@ -464,6 +490,8 @@ /* NOTE: All channels contain internal variables; do */ /* not write to these locations. */ +/* 1f something */ + #define CD0 0x20 /* Cache data 0 register */ #define CD1 0x21 /* Cache data 1 register */ #define CD2 0x22 /* Cache data 2 register */ @@ -481,6 +509,8 @@ #define CDE 0x2e /* Cache data E register */ #define CDF 0x2f /* Cache data F register */ +/* 0x30-3f seem to be the same as 0x20-2f */ + #define PTB 0x40 /* Page table base register */ #define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */ @@ -511,7 +541,11 @@ #define FXWC 0x43 /* FX output write channels register */ /* When set, each bit enables the writing of the */ - /* corresponding FX output channel into host memory */ + /* corresponding FX output channel (internal registers */ + /* 0x20-0x3f) to host memory. This mode of recording */ + /* is 16bit, 48KHz only. All 32 channels can be enabled */ + /* simultaneously. */ + #define FXWC_DEFAULTROUTE_C (1<<0) /* left emu out? */ #define FXWC_DEFAULTROUTE_B (1<<1) /* right emu out? */ #define FXWC_DEFAULTROUTE_A (1<<12) @@ -546,12 +580,16 @@ #define FXBA 0x47 /* FX Buffer Address */ #define FXBA_MASK 0xfffff000 /* 20 bit base address */ +/* 0x48 something - word access, defaults to 3f */ + #define MICBS 0x49 /* Microphone buffer size register */ #define ADCBS 0x4a /* ADC buffer size register */ #define FXBS 0x4b /* FX buffer size register */ +/* register: 0x4c..4f: ffff-ffff current amounts, per-channel */ + /* The following mask values define the size of the ADC, MIX and FX buffers in bytes */ #define ADCBS_BUFSIZE_NONE 0x00000000 #define ADCBS_BUFSIZE_384 0x00000001 @@ -602,6 +640,7 @@ #define A_DBG_SATURATION_OCCURED 0x20000000 #define A_DBG_SATURATION_ADDR 0x0ffc0000 +// NOTE: 0x54,55,56: 64-bit #define SPCS0 0x54 /* SPDIF output Channel Status 0 register */ #define SPCS1 0x55 /* SPDIF output Channel Status 1 register */ @@ -657,6 +696,7 @@ #define AC97SLOT_CNTR 0x10 /* Center enable */ #define AC97SLOT_LFE 0x20 /* LFE enable */ +// NOTE: 0x60,61,62: 64-bit #define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ #define GPSRCS 0x61 /* General Purpose SPDIF sample rate cvt status */ @@ -693,6 +733,19 @@ #define FXIDX_MASK 0x0000ffff /* 16-bit value */ #define FXIDX_IDX 0x10000065 +/* The 32-bit HLIx and HLIPx registers all have one bit per channel control/status */ +#define HLIEL 0x66 /* Channel half loop interrupt enable low register */ + +#define HLIEH 0x67 /* Channel half loop interrupt enable high register */ + +#define HLIPL 0x68 /* Channel half loop interrupt pending low register */ + +#define HLIPH 0x69 /* Channel half loop interrupt pending high register */ + +// 0x6a,6b,6c used for some recording +// 0x6d unused +// 0x6e,6f - tanktable base / offset + /* This is the MPU port on the card (via the game port) */ #define A_MUDATA1 0x70 #define A_MUCMD1 0x71 @@ -715,6 +768,9 @@ #define A_SPDIF_44100 0x00000040 #define A_SPDIF_96000 0x00000080 +/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */ +/* 0x7a, 0x7b - lookup tables */ + #define A_FXRT2 0x7c #define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ #define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */ @@ -726,7 +782,8 @@ #define A_FXSENDAMOUNT_F_MASK 0x00FF0000 #define A_FXSENDAMOUNT_G_MASK 0x0000FF00 #define A_FXSENDAMOUNT_H_MASK 0x000000FF - +/* 0x7c, 0x7e "high bit is used for filtering" */ + /* The send amounts for this one are the same as used with the emu10k1 */ #define A_FXRT1 0x7e #define A_FXRT_CHANNELA 0x0000003f @@ -783,6 +840,7 @@ typedef struct _snd_emu10k1_voice emu10k1_voice_t; typedef struct _snd_emu10k1_pcm emu10k1_pcm_t; typedef enum { + EMU10K1_EFX, EMU10K1_PCM, EMU10K1_SYNTH, EMU10K1_MIDI @@ -793,6 +851,7 @@ struct _snd_emu10k1_voice { int number; int use: 1, pcm: 1, + efx: 1, synth: 1, midi: 1; void (*interrupt)(emu10k1_t *emu, emu10k1_voice_t *pvoice); @@ -802,6 +861,7 @@ struct _snd_emu10k1_voice { typedef enum { PLAYBACK_EMUVOICE, + PLAYBACK_EFX, CAPTURE_AC97ADC, CAPTURE_AC97MIC, CAPTURE_EFX @@ -811,7 +871,7 @@ struct _snd_emu10k1_pcm { emu10k1_t *emu; snd_emu10k1_pcm_type_t type; snd_pcm_substream_t *substream; - emu10k1_voice_t *voices[2]; + emu10k1_voice_t *voices[NUM_EFX_PLAYBACK]; emu10k1_voice_t *extra; unsigned short running; unsigned short first_ptr; @@ -985,23 +1045,27 @@ struct _snd_emu10k1 { spinlock_t voice_lock; struct semaphore ptb_lock; - emu10k1_voice_t voices[64]; + emu10k1_voice_t voices[NUM_G]; emu10k1_pcm_mixer_t pcm_mixer[32]; + emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK]; snd_kcontrol_t *ctl_send_routing; snd_kcontrol_t *ctl_send_volume; snd_kcontrol_t *ctl_attn; + snd_kcontrol_t *ctl_efx_send_routing; + snd_kcontrol_t *ctl_efx_send_volume; + snd_kcontrol_t *ctl_efx_attn; void (*hwvol_interrupt)(emu10k1_t *emu, unsigned int status); void (*capture_interrupt)(emu10k1_t *emu, unsigned int status); void (*capture_mic_interrupt)(emu10k1_t *emu, unsigned int status); void (*capture_efx_interrupt)(emu10k1_t *emu, unsigned int status); - void (*timer_interrupt)(emu10k1_t *emu); void (*spdif_interrupt)(emu10k1_t *emu, unsigned int status); void (*dsp_interrupt)(emu10k1_t *emu); snd_pcm_substream_t *pcm_capture_substream; snd_pcm_substream_t *pcm_capture_mic_substream; snd_pcm_substream_t *pcm_capture_efx_substream; + snd_pcm_substream_t *pcm_playback_efx_substream; snd_timer_t *timer; @@ -1009,6 +1073,7 @@ struct _snd_emu10k1 { emu10k1_midi_t midi2; /* for audigy */ unsigned int efx_voices_mask[2]; + unsigned int next_free_voice; }; int snd_emu10k1_create(snd_card_t * card, @@ -1022,6 +1087,7 @@ int snd_emu10k1_create(snd_card_t * card, int snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm); int snd_emu10k1_pcm_mic(emu10k1_t * emu, int device, snd_pcm_t ** rpcm); int snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm); +int snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm); int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm); int snd_emu10k1_mixer(emu10k1_t * emu); int snd_emu10k1_timer(emu10k1_t * emu, int device); @@ -1044,6 +1110,9 @@ void snd_emu10k1_intr_disable(emu10k1_t *emu, unsigned int intrenb); void snd_emu10k1_voice_intr_enable(emu10k1_t *emu, unsigned int voicenum); void snd_emu10k1_voice_intr_disable(emu10k1_t *emu, unsigned int voicenum); void snd_emu10k1_voice_intr_ack(emu10k1_t *emu, unsigned int voicenum); +void snd_emu10k1_voice_half_loop_intr_enable(emu10k1_t *emu, unsigned int voicenum); +void snd_emu10k1_voice_half_loop_intr_disable(emu10k1_t *emu, unsigned int voicenum); +void snd_emu10k1_voice_half_loop_intr_ack(emu10k1_t *emu, unsigned int voicenum); void snd_emu10k1_voice_set_loop_stop(emu10k1_t *emu, unsigned int voicenum); void snd_emu10k1_voice_clear_loop_stop(emu10k1_t *emu, unsigned int voicenum); void snd_emu10k1_wait(emu10k1_t *emu, unsigned int wait); -- cgit v1.2.3 From 2359b08ad7053fd5a8fe11c0189c79ab38b486aa Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 2 Mar 2005 16:31:07 +0100 Subject: [ALSA] use unsigned 1-bit fields Virtual Midi Can't have a boolean and a sign bit in 1 bit. Fix (14) boolean/bitfield sparse warning: include/sound/seq_virmidi.h:41:16: warning: dubious one-bit signed bitfield Signed-off-by: Randy Dunlap Signed-off-by: Takashi Iwai --- include/sound/seq_virmidi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h index 9bb1a80a991c..cf4e2388103f 100644 --- a/include/sound/seq_virmidi.h +++ b/include/sound/seq_virmidi.h @@ -38,7 +38,7 @@ typedef struct _snd_virmidi { int seq_mode; int client; int port; - int trigger: 1; + unsigned int trigger: 1; snd_midi_event_t *parser; snd_seq_event_t event; snd_virmidi_dev_t *rdev; -- cgit v1.2.3 From 7c3f7e28d77ee16c04aebae48a7d6103761dc409 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 2 Mar 2005 16:33:19 +0100 Subject: [ALSA] [SPARSE] Use unsigned int :1 bitfields EMU10K1/EMU10K2 driver,GUS Library,ALSA<-OSS emulation,Trident driver YMFPCI driver,CMIPCI driver,Intel8x0-modem driver,Maestro3 driver ALI5451 driver,ICE1712 driver Use unsigned int :1 bitfields. Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 4 ++-- include/sound/gus.h | 4 ++-- include/sound/mixer_oss.h | 2 +- include/sound/trident.h | 6 +++--- include/sound/ymfpci.h | 8 ++++---- sound/pci/ali5451/ali5451.c | 4 ++-- sound/pci/cmipci.c | 6 +++--- sound/pci/ice1712/ice1712.h | 2 +- sound/pci/intel8x0m.c | 2 +- sound/pci/maestro3.c | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index c5fd57b862d8..3dd95212aab4 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -849,7 +849,7 @@ typedef enum { struct _snd_emu10k1_voice { emu10k1_t *emu; int number; - int use: 1, + unsigned int use: 1, pcm: 1, efx: 1, synth: 1, @@ -999,7 +999,7 @@ struct _snd_emu10k1 { int irq; unsigned long port; /* I/O port number */ - int APS: 1, /* APS flag */ + unsigned int APS: 1, /* APS flag */ no_ac97: 1, /* no AC'97 */ tos_link: 1, /* tos link detected */ rear_ac97: 1, /* rear channels are on AC'97 */ diff --git a/include/sound/gus.h b/include/sound/gus.h index cac8cc070ad9..8b6287a6fff5 100644 --- a/include/sound/gus.h +++ b/include/sound/gus.h @@ -230,7 +230,7 @@ typedef struct { int mode; /* operation mode */ int client; /* sequencer client number */ int port; /* sequencer port number */ - int midi_has_voices: 1; + unsigned int midi_has_voices: 1; } snd_gus_port_t; typedef struct _snd_gus_voice snd_gus_voice_t; @@ -264,7 +264,7 @@ typedef enum { struct _snd_gus_voice { int number; - int use: 1, + unsigned int use: 1, pcm: 1, synth:1, midi: 1; diff --git a/include/sound/mixer_oss.h b/include/sound/mixer_oss.h index a2fbad2b8c40..ed75b2fb00ab 100644 --- a/include/sound/mixer_oss.h +++ b/include/sound/mixer_oss.h @@ -38,7 +38,7 @@ typedef int (*snd_mixer_oss_put_recsrce_t)(snd_mixer_oss_file_t *fmixer, unsigne struct _snd_oss_mixer_slot { int number; - int stereo: 1; + unsigned int stereo: 1; snd_mixer_oss_get_volume_t get_volume; snd_mixer_oss_put_volume_t put_volume; snd_mixer_oss_get_recsrc_t get_recsrc; diff --git a/include/sound/trident.h b/include/sound/trident.h index ccb3a60d120f..3ac027d45673 100644 --- a/include/sound/trident.h +++ b/include/sound/trident.h @@ -290,7 +290,7 @@ typedef struct { int mode; /* operation mode */ int client; /* sequencer client number */ int port; /* sequencer port number */ - int midi_has_voices: 1; + unsigned int midi_has_voices: 1; } snd_trident_port_t; typedef struct snd_trident_memblk_arg { @@ -308,7 +308,7 @@ typedef struct { struct _snd_trident_voice { unsigned int number; - int use: 1, + unsigned int use: 1, pcm: 1, synth:1, midi: 1; @@ -347,7 +347,7 @@ struct _snd_trident_voice { trident_t *trident; snd_pcm_substream_t *substream; snd_trident_voice_t *extra; /* extra PCM voice (acts as interrupt generator) */ - int running: 1, + unsigned int running: 1, capture: 1, spdif: 1, foldback: 1, diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h index b87453365f79..12e036b0b867 100644 --- a/include/sound/ymfpci.h +++ b/include/sound/ymfpci.h @@ -262,7 +262,7 @@ typedef enum { struct _snd_ymfpci_voice { ymfpci_t *chip; int number; - int use: 1, + unsigned int use: 1, pcm: 1, synth: 1, midi: 1; @@ -288,9 +288,9 @@ struct _snd_ymfpci_pcm { snd_ymfpci_pcm_type_t type; snd_pcm_substream_t *substream; ymfpci_voice_t *voices[2]; /* playback only */ - int running: 1; - int output_front: 1; - int output_rear: 1; + unsigned int running: 1; + unsigned int output_front: 1; + unsigned int output_rear: 1; u32 period_size; /* cached from runtime->period_size */ u32 buffer_size; /* cached from runtime->buffer_size */ u32 period_pos; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 6c4deeaaa455..984d5d4ba4e1 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -188,7 +188,7 @@ typedef struct snd_ali_channel_control { struct snd_ali_stru_voice { unsigned int number; - int use: 1, + unsigned int use: 1, pcm: 1, midi: 1, mode: 1, @@ -199,7 +199,7 @@ struct snd_ali_stru_voice { snd_pcm_substream_t *substream; snd_ali_voice_t *extra; - int running: 1; + unsigned int running: 1; int eso; /* final ESO value for channel */ int count; /* runtime->period_size */ diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 17fbed0f0641..663d1be0839c 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -458,7 +458,7 @@ struct snd_stru_cmipci { int opened[2]; /* open mode */ struct semaphore open_mutex; - int mixer_insensitive: 1; + unsigned int mixer_insensitive: 1; snd_kcontrol_t *mixer_res_ctl[CM_SAVED_MIXERS]; int mixer_res_status[CM_SAVED_MIXERS]; @@ -2108,8 +2108,8 @@ typedef struct snd_cmipci_switch_args { int reg; /* register index */ unsigned int mask; /* mask bits */ unsigned int mask_on; /* mask bits to turn on */ - int is_byte: 1; /* byte access? */ - int ac3_sensitive: 1; /* access forbidden during non-audio operation? */ + unsigned int is_byte: 1; /* byte access? */ + unsigned int ac3_sensitive: 1; /* access forbidden during non-audio operation? */ } snd_cmipci_switch_args_t; static int snd_cmipci_uswitch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index e88083da928d..d4b60860bf9b 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -484,7 +484,7 @@ struct snd_ice1712_card_info { char *driver; int (*chip_init)(ice1712_t *); int (*build_controls)(ice1712_t *); - int no_mpu401: 1; + unsigned int no_mpu401: 1; unsigned int eeprom_size; unsigned char *eeprom_data; }; diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 68a7f48025b2..5875be9d5b03 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -247,7 +247,7 @@ struct _snd_intel8x0m { snd_pcm_t *pcm[2]; ichdev_t ichd[2]; - int in_ac97_init: 1; + unsigned int in_ac97_init: 1; ac97_bus_t *ac97_bus; ac97_t *ac97; diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index e4af8a5d96aa..2cf33083d7cc 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -820,7 +820,7 @@ struct snd_m3 { unsigned long iobase; int irq; - int allegro_flag : 1; + unsigned int allegro_flag : 1; ac97_t *ac97; -- cgit v1.2.3 From 38dc7aa8f591135bee5e4f2e034fc81926a34015 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 2 Mar 2005 17:00:33 +0100 Subject: [ALSA] remove _snd_rawmidi_runtime.trigger RawMidi Midlevel Remove the trigger field from _snd_rawmidi_runtime because it is never ever read. (This may be why nobody noticed that snd_rawmidi_transmit_empty sets it to the wrong value.) Signed-off-by: Clemens Ladisch --- include/sound/rawmidi.h | 3 +-- sound/core/rawmidi.c | 11 ----------- 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'include') diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 3df418d4f51e..370f6e6a01ee 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -65,8 +65,7 @@ typedef struct _snd_rawmidi_global_ops { } snd_rawmidi_global_ops_t; struct _snd_rawmidi_runtime { - unsigned int trigger: 1, /* transfer is running */ - drain: 1, /* drain stage */ + unsigned int drain: 1, /* drain stage */ oss: 1; /* OSS compatible mode */ /* midi stream buffer */ unsigned char *buffer; /* buffer for MIDI data */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7433aa7500cf..0022d50e2c40 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -117,7 +117,6 @@ int snd_rawmidi_drop_output(snd_rawmidi_substream_t * substream) snd_rawmidi_runtime_t *runtime = substream->runtime; substream->ops->trigger(substream, 0); - runtime->trigger = 0; runtime->drain = 0; /* interrupts are not enabled at this moment, so spinlock is not required */ @@ -160,7 +159,6 @@ int snd_rawmidi_drain_input(snd_rawmidi_substream_t * substream) snd_rawmidi_runtime_t *runtime = substream->runtime; substream->ops->trigger(substream, 0); - runtime->trigger = 0; runtime->drain = 0; /* interrupts aren't enabled at this moment, so spinlock isn't needed */ runtime->appl_ptr = runtime->hw_ptr = 0; @@ -462,7 +460,6 @@ int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile) substream = rfile->input; rfile->input = NULL; runtime = substream->runtime; - runtime->trigger = 0; substream->ops->trigger(substream, 0); substream->ops->close(substream); snd_rawmidi_done_buffer(runtime); @@ -928,7 +925,6 @@ static long snd_rawmidi_kernel_read1(snd_rawmidi_substream_t *substream, long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char *buf, long count) { - substream->runtime->trigger = 1; substream->ops->trigger(substream, 1); return snd_rawmidi_kernel_read1(substream, buf, count, 1); } @@ -946,7 +942,6 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun if (substream == NULL) return -EIO; runtime = substream->runtime; - runtime->trigger = 1; substream->ops->trigger(substream, 1); result = 0; while (count > 0) { @@ -998,8 +993,6 @@ int snd_rawmidi_transmit_empty(snd_rawmidi_substream_t * substream) } spin_lock_irqsave(&runtime->lock, flags); result = runtime->avail >= runtime->buffer_size; - if (result) - runtime->trigger = 1; spin_unlock_irqrestore(&runtime->lock, flags); return result; } @@ -1032,7 +1025,6 @@ int snd_rawmidi_transmit_peek(snd_rawmidi_substream_t * substream, unsigned char spin_lock_irqsave(&runtime->lock, flags); if (runtime->avail >= runtime->buffer_size) { /* warning: lowlevel layer MUST trigger down the hardware */ - runtime->trigger = 0; goto __skip; } if (count == 1) { /* special case, faster code */ @@ -1158,8 +1150,6 @@ static long snd_rawmidi_kernel_write1(snd_rawmidi_substream_t * substream, const count -= count1; } __end: - if (result > 0) - runtime->trigger = 1; count1 = runtime->avail < runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); if (count1) @@ -1248,7 +1238,6 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait) rfile = file->private_data; if (rfile->input != NULL) { runtime = rfile->input->runtime; - runtime->trigger = 1; rfile->input->ops->trigger(rfile->input, 1); poll_wait(file, &runtime->sleep, wait); } -- cgit v1.2.3 From 10b92f2f3718d780ea988155953119e4e7a4e20f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 2 Mar 2005 17:01:23 +0100 Subject: [ALSA] Fix the Audigy SPDIF sample rate register definitions EMU10K1/EMU10K2 driver Signed-off-by: Lee Revell Signed-off-by: Jaroslav Kysela --- include/sound/emu10k1.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 3dd95212aab4..89ff420adf3f 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -765,8 +765,8 @@ #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ #define A_SPDIF_RATE_MASK 0x000000c0 #define A_SPDIF_48000 0x00000000 -#define A_SPDIF_44100 0x00000040 -#define A_SPDIF_96000 0x00000080 +#define A_SPDIF_44100 0x00000080 +#define A_SPDIF_96000 0x00000040 /* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */ /* 0x7a, 0x7b - lookup tables */ -- cgit v1.2.3 From 91a700ed26922af3eba7e977422637c230d14954 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 10 Mar 2005 11:26:12 +0100 Subject: [ALSA] move rawmidi event callback into tasklet RawMidi Midlevel Move the event callback into a tasklet instead of calling it directly from snd_rawmidi_transmit_ack/_receive to prevent recursive calls to the trigger callback. This means that drivers no longer have to check that they're called inside their own spinlock. Signed-off-by: Clemens Ladisch --- include/sound/rawmidi.h | 2 ++ sound/core/rawmidi.c | 54 +++++++++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 370f6e6a01ee..92260e2d548c 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -79,6 +80,7 @@ struct _snd_rawmidi_runtime { spinlock_t lock; wait_queue_head_t sleep; /* event handler (room [output] or new bytes [input]) */ + struct tasklet_struct event_tasklet; void (*event)(snd_rawmidi_substream_t *substream); /* private data */ void *private_data; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0e4c7c6f4143..04f33178502b 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -85,6 +85,12 @@ static inline int snd_rawmidi_ready_append(snd_rawmidi_substream_t * substream, (!substream->append || runtime->avail >= count); } +static void snd_rawmidi_event_tasklet(unsigned long data) +{ + snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data; + substream->runtime->event(substream); +} + static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream) { snd_rawmidi_runtime_t *runtime; @@ -93,6 +99,8 @@ static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream) return -ENOMEM; spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); + tasklet_init(&runtime->event_tasklet, snd_rawmidi_event_tasklet, + (unsigned long)substream); runtime->event = NULL; runtime->buffer_size = PAGE_SIZE; runtime->avail_min = 1; @@ -119,11 +127,18 @@ static int snd_rawmidi_runtime_free(snd_rawmidi_substream_t * substream) return 0; } +static void snd_rawmidi_trigger(snd_rawmidi_substream_t * substream, int up) +{ + substream->ops->trigger(substream, up); + if (!up && substream->runtime->event) + tasklet_kill(&substream->runtime->event_tasklet); +} + int snd_rawmidi_drop_output(snd_rawmidi_substream_t * substream) { snd_rawmidi_runtime_t *runtime = substream->runtime; - substream->ops->trigger(substream, 0); + snd_rawmidi_trigger(substream, 0); runtime->drain = 0; /* interrupts are not enabled at this moment, so spinlock is not required */ @@ -165,7 +180,7 @@ int snd_rawmidi_drain_input(snd_rawmidi_substream_t * substream) { snd_rawmidi_runtime_t *runtime = substream->runtime; - substream->ops->trigger(substream, 0); + snd_rawmidi_trigger(substream, 0); runtime->drain = 0; /* interrupts aren't enabled at this moment, so spinlock isn't needed */ runtime->appl_ptr = runtime->hw_ptr = 0; @@ -443,7 +458,7 @@ int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile) substream = rfile->input; rfile->input = NULL; runtime = substream->runtime; - substream->ops->trigger(substream, 0); + snd_rawmidi_trigger(substream, 0); substream->ops->close(substream); if (runtime->private_free != NULL) runtime->private_free(substream); @@ -462,7 +477,7 @@ int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile) snd_rawmidi_kernel_write(substream, &buf, 1); } if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) - substream->ops->trigger(substream, 0); + snd_rawmidi_trigger(substream, 0); substream->ops->close(substream); if (runtime->private_free != NULL) runtime->private_free(substream); @@ -858,13 +873,13 @@ int snd_rawmidi_receive(snd_rawmidi_substream_t * substream, const unsigned char } } } - if (result > 0 && runtime->event == NULL) { - if (snd_rawmidi_ready(substream)) + if (result > 0) { + if (runtime->event) + tasklet_hi_schedule(&runtime->event_tasklet); + else if (snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } spin_unlock_irqrestore(&runtime->lock, flags); - if (result > 0 && runtime->event) - runtime->event(substream); return result; } @@ -904,7 +919,7 @@ static long snd_rawmidi_kernel_read1(snd_rawmidi_substream_t *substream, long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char *buf, long count) { - substream->ops->trigger(substream, 1); + snd_rawmidi_trigger(substream, 1); return snd_rawmidi_kernel_read1(substream, buf, count, 1); } @@ -921,7 +936,7 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun if (substream == NULL) return -EIO; runtime = substream->runtime; - substream->ops->trigger(substream, 1); + snd_rawmidi_trigger(substream, 1); result = 0; while (count > 0) { spin_lock_irq(&runtime->lock); @@ -1056,15 +1071,14 @@ int snd_rawmidi_transmit_ack(snd_rawmidi_substream_t * substream, int count) runtime->hw_ptr %= runtime->buffer_size; runtime->avail += count; substream->bytes += count; - if (runtime->drain) - wake_up(&runtime->sleep); - else - if (count > 0 && runtime->event == NULL) - if (snd_rawmidi_ready(substream)) - wake_up(&runtime->sleep); + if (count > 0) { + if (runtime->drain || + (runtime->event == NULL && snd_rawmidi_ready(substream))) + wake_up(&runtime->sleep); + if (runtime->event) + tasklet_hi_schedule(&runtime->event_tasklet); + } spin_unlock_irqrestore(&runtime->lock, flags); - if (count > 0 && runtime->event) - runtime->event(substream); return count; } @@ -1132,7 +1146,7 @@ static long snd_rawmidi_kernel_write1(snd_rawmidi_substream_t * substream, const count1 = runtime->avail < runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); if (count1) - substream->ops->trigger(substream, 1); + snd_rawmidi_trigger(substream, 1); return result; } @@ -1217,7 +1231,7 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait) rfile = file->private_data; if (rfile->input != NULL) { runtime = rfile->input->runtime; - rfile->input->ops->trigger(rfile->input, 1); + snd_rawmidi_trigger(rfile->input, 1); poll_wait(file, &runtime->sleep, wait); } if (rfile->output != NULL) { -- cgit v1.2.3 From 9024d50ac07b0fa4b2d559aa95d77fdff091dc69 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 10 Mar 2005 11:29:52 +0100 Subject: [ALSA] fix locking for rawmidi trigger callbacks Generic drivers,MPU401 UART,SB8 driver,Wavefront drivers,CS4281 driver ENS1370/1+ driver,CS46xx driver,EMU10K1/EMU10K2 driver,RME HDSP driver Use spin_lock_irqsave() instead of spin_lock() in places where we could be interrupted by another hardware interrupt that could call the rawmidi trigger callback that could try to take the same lock. Additionally, remove locking code that is no longer needed now that the trigger callback is no longer called recursively from the rawmidi 'event' handler. Signed-off-by: Clemens Ladisch --- include/sound/mpu401.h | 3 --- sound/drivers/mpu401/mpu401_uart.c | 50 ++++++++++++------------------------ sound/drivers/mtpav.c | 12 ++++----- sound/drivers/serial-u16550.c | 12 +++++---- sound/isa/sb/sb8_midi.c | 8 ++---- sound/isa/wavefront/wavefront_midi.c | 8 ++---- sound/pci/cs4281.c | 22 ++++++++-------- sound/pci/cs46xx/cs46xx_lib.c | 23 +++++++++-------- sound/pci/emu10k1/emu10k1x.c | 7 +++-- sound/pci/emu10k1/emumpu401.c | 7 +++-- sound/pci/ens1370.c | 41 ++++++++++++++++------------- sound/pci/rme9652/hdsp.c | 7 ++--- 12 files changed, 90 insertions(+), 110 deletions(-) (limited to 'include') diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h index 8c5d6e0c89cc..ae39e38bf996 100644 --- a/include/sound/mpu401.h +++ b/include/sound/mpu401.h @@ -86,9 +86,6 @@ struct _snd_mpu401 { spinlock_t output_lock; spinlock_t timer_lock; - atomic_t rx_loop; - atomic_t tx_loop; - struct timer_list timer; void (*write) (mpu401_t * mpu, unsigned char data, unsigned long addr); diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index ef36d9e66147..433055d4f89b 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -92,24 +92,21 @@ static void snd_mpu401_uart_clear_rx(mpu401_t *mpu) static void _snd_mpu401_uart_interrupt(mpu401_t *mpu) { - spin_lock(&mpu->input_lock); + unsigned long flags; + + spin_lock_irqsave(&mpu->input_lock, flags); if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { - atomic_dec(&mpu->rx_loop); snd_mpu401_uart_input_read(mpu); - atomic_inc(&mpu->rx_loop); } else { snd_mpu401_uart_clear_rx(mpu); } - spin_unlock(&mpu->input_lock); + spin_unlock_irqrestore(&mpu->input_lock, flags); /* ok. for better Tx performance try do some output when input is done */ if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { - if (spin_trylock(&mpu->output_lock)) { - atomic_dec(&mpu->tx_loop); - snd_mpu401_uart_output_write(mpu); - atomic_inc(&mpu->tx_loop); - spin_unlock(&mpu->output_lock); - } + spin_lock_irqsave(&mpu->output_lock, flags); + snd_mpu401_uart_output_write(mpu); + spin_unlock_irqrestore(&mpu->output_lock, flags); } } @@ -137,13 +134,14 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *reg */ static void snd_mpu401_uart_timer(unsigned long data) { + unsigned long flags; mpu401_t *mpu = (mpu401_t *)data; - spin_lock(&mpu->timer_lock); + spin_lock_irqsave(&mpu->timer_lock, flags); /*mpu->mode |= MPU401_MODE_TIMER;*/ mpu->timer.expires = 1 + jiffies; add_timer(&mpu->timer); - spin_unlock(&mpu->timer_lock); + spin_unlock_irqrestore(&mpu->timer_lock, flags); if (mpu->rmidi) _snd_mpu401_uart_interrupt(mpu); } @@ -243,7 +241,6 @@ static int snd_mpu401_uart_input_open(snd_rawmidi_substream_t * substream) snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); } mpu->substream_input = substream; - atomic_set(&mpu->rx_loop, 1); set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); return 0; } @@ -261,7 +258,6 @@ static int snd_mpu401_uart_output_open(snd_rawmidi_substream_t * substream) snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); } mpu->substream_output = substream; - atomic_set(&mpu->tx_loop, 1); set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); return 0; } @@ -314,16 +310,9 @@ static void snd_mpu401_uart_input_trigger(snd_rawmidi_substream_t * substream, i } /* read data in advance */ - /* prevent double enter via rawmidi->event callback */ - if (atomic_dec_and_test(&mpu->rx_loop)) { - local_irq_save(flags); - if (spin_trylock(&mpu->input_lock)) { - snd_mpu401_uart_input_read(mpu); - spin_unlock(&mpu->input_lock); - } - local_irq_restore(flags); - } - atomic_inc(&mpu->rx_loop); + spin_trylock_irqsave(&mpu->input_lock, flags); + snd_mpu401_uart_input_read(mpu); + spin_unlock_irqrestore(&mpu->input_lock, flags); } else { if (mpu->irq < 0) snd_mpu401_uart_remove_timer(mpu, 1); @@ -405,16 +394,9 @@ static void snd_mpu401_uart_output_trigger(snd_rawmidi_substream_t * substream, snd_mpu401_uart_add_timer(mpu, 0); /* output pending data */ - /* prevent double enter via rawmidi->event callback */ - if (atomic_dec_and_test(&mpu->tx_loop)) { - local_irq_save(flags); - if (spin_trylock(&mpu->output_lock)) { - snd_mpu401_uart_output_write(mpu); - spin_unlock(&mpu->output_lock); - } - local_irq_restore(flags); - } - atomic_inc(&mpu->tx_loop); + spin_lock_irqsave(&mpu->output_lock, flags); + snd_mpu401_uart_output_write(mpu); + spin_unlock_irqrestore(&mpu->output_lock, flags); } else { snd_mpu401_uart_remove_timer(mpu, 0); clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 2c572345c90b..4cc76e21915c 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -413,10 +413,11 @@ static void snd_mtpav_input_trigger(snd_rawmidi_substream_t * substream, int up) static void snd_mtpav_output_timer(unsigned long data) { + unsigned long flags; mtpav_t *chip = (mtpav_t *)data; int p; - spin_lock(&chip->spinlock); + spin_lock_irqsave(&chip->spinlock, flags); /* reprogram timer */ chip->timer.expires = 1 + jiffies; add_timer(&chip->timer); @@ -426,7 +427,7 @@ static void snd_mtpav_output_timer(unsigned long data) if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED) && portp->output) snd_mtpav_output_port_write(portp, portp->output); } - spin_unlock(&chip->spinlock); + spin_unlock_irqrestore(&chip->spinlock, flags); } /* spinlock held! */ @@ -514,9 +515,7 @@ static void snd_mtpav_inmidi_process(mtpav_t *mcrd, u8 inbyte) portp = &mcrd->ports[mcrd->inmidiport]; if (portp->mode & MTPAV_MODE_INPUT_TRIGGERED) { - spin_unlock(&mcrd->spinlock); snd_rawmidi_receive(portp->input, &inbyte, 1); - spin_lock(&mcrd->spinlock); } } @@ -581,12 +580,13 @@ static void snd_mtpav_read_bytes(mtpav_t * mcrd) static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; mtpav_t *mcard = dev_id; //printk("irqh()\n"); - spin_lock(&mcard->spinlock); + spin_lock_irqsave(&mcard->spinlock, flags); snd_mtpav_read_bytes(mcard); - spin_unlock(&mcard->spinlock); + spin_unlock_irqrestore(&mcard->spinlock, flags); return IRQ_HANDLED; } diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 9bd806ff2828..b2849983f348 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -292,30 +292,32 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) */ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; snd_uart16550_t *uart; uart = (snd_uart16550_t *) dev_id; - spin_lock(&uart->open_lock); + spin_lock_irqsave(&uart->open_lock, flags); if (uart->filemode == SERIAL_MODE_NOT_OPENED) { - spin_unlock(&uart->open_lock); + spin_unlock_irqrestore(&uart->open_lock, flags); return IRQ_NONE; } inb(uart->base + UART_IIR); /* indicate to the UART that the interrupt has been serviced */ snd_uart16550_io_loop(uart); - spin_unlock(&uart->open_lock); + spin_unlock_irqrestore(&uart->open_lock, flags); return IRQ_HANDLED; } /* When the polling mode, this function calls snd_uart16550_io_loop. */ static void snd_uart16550_buffer_timer(unsigned long data) { + unsigned long flags; snd_uart16550_t *uart; uart = (snd_uart16550_t *)data; - spin_lock(&uart->open_lock); + spin_lock_irqsave(&uart->open_lock, flags); snd_uart16550_del_timer(uart); snd_uart16550_io_loop(uart); - spin_unlock(&uart->open_lock); + spin_unlock_irqrestore(&uart->open_lock, flags); } /* diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index 90b01e79879d..d2c633a40e74 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -46,20 +46,16 @@ irqreturn_t snd_sb8dsp_midi_interrupt(sb_t * chip) inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */ return IRQ_NONE; } + spin_lock(&chip->midi_input_lock); while (max-- > 0) { - spin_lock(&chip->midi_input_lock); if (inb(SBP(chip, DATA_AVAIL)) & 0x80) { byte = inb(SBP(chip, READ)); if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) { - spin_unlock(&chip->midi_input_lock); snd_rawmidi_receive(chip->midi_substream_input, &byte, 1); - } else { - spin_unlock(&chip->midi_input_lock); } - } else { - spin_unlock(&chip->midi_input_lock); } } + spin_unlock(&chip->midi_input_lock); return IRQ_HANDLED; } diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index 3918fbcdeb2d..6f51d64fb565 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -413,8 +413,8 @@ snd_wavefront_midi_interrupt (snd_wavefront_card_t *card) return; } + spin_lock_irqsave (&midi->virtual, flags); while (--max) { - spin_lock_irqsave (&midi->virtual, flags); if (input_avail (midi)) { byte = read_data (midi); @@ -433,21 +433,17 @@ snd_wavefront_midi_interrupt (snd_wavefront_card_t *card) } if (substream == NULL) { - spin_unlock_irqrestore (&midi->virtual, flags); continue; } if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { - spin_unlock_irqrestore (&midi->virtual, flags); snd_rawmidi_receive(substream, &byte, 1); - } else { - spin_unlock_irqrestore (&midi->virtual, flags); } } else { - spin_unlock_irqrestore (&midi->virtual, flags); break; } } + spin_unlock_irqrestore (&midi->virtual, flags); snd_wavefront_midi_output_write(card); } diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 3a5fd96d6e87..f3868140e431 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -697,10 +697,11 @@ static unsigned short snd_cs4281_ac97_read(ac97_t *ac97, static int snd_cs4281_trigger(snd_pcm_substream_t *substream, int cmd) { + unsigned long flags; cs4281_dma_t *dma = (cs4281_dma_t *)substream->runtime->private_data; cs4281_t *chip = snd_pcm_substream_chip(substream); - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: dma->valDCR |= BA0_DCR_MSK; @@ -727,13 +728,13 @@ static int snd_cs4281_trigger(snd_pcm_substream_t *substream, int cmd) dma->valFCR &= ~BA0_FCR_FEN; break; default: - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return -EINVAL; } snd_cs4281_pokeBA0(chip, dma->regDMR, dma->valDMR); snd_cs4281_pokeBA0(chip, dma->regFCR, dma->valFCR); snd_cs4281_pokeBA0(chip, dma->regDCR, dma->valDCR); - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -1847,6 +1848,7 @@ static int __devinit snd_cs4281_midi(cs4281_t * chip, int device, snd_rawmidi_t static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs) { cs4281_t *chip = dev_id; + unsigned long flags; unsigned int status, dma, val; cs4281_dma_t *cdma; @@ -1862,7 +1864,7 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *r for (dma = 0; dma < 4; dma++) if (status & BA0_HISR_DMA(dma)) { cdma = &chip->dma[dma]; - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); /* ack DMA IRQ */ val = snd_cs4281_peekBA0(chip, cdma->regHDSR); /* workaround, sometimes CS4281 acknowledges */ @@ -1871,16 +1873,16 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *r if ((val & BA0_HDSR_DHTC) && !(cdma->frag & 1)) { cdma->frag--; chip->spurious_dhtc_irq++; - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); continue; } if ((val & BA0_HDSR_DTC) && (cdma->frag & 1)) { cdma->frag--; chip->spurious_dtc_irq++; - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); continue; } - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); snd_pcm_period_elapsed(cdma->substream); } } @@ -1888,14 +1890,12 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *r if ((status & BA0_HISR_MIDI) && chip->rmidi) { unsigned char c; - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); while ((snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_RBE) == 0) { c = snd_cs4281_peekBA0(chip, BA0_MIDRP); if ((chip->midcr & BA0_MIDCR_RIE) == 0) continue; - spin_unlock(&chip->reg_lock); snd_rawmidi_receive(chip->midi_input, &c, 1); - spin_lock(&chip->reg_lock); } while ((snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_TBF) == 0) { if ((chip->midcr & BA0_MIDCR_TIE) == 0) @@ -1907,7 +1907,7 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *r } snd_cs4281_pokeBA0(chip, BA0_MIDWP, c); } - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); } /* EOI to the PCI part... reenables interrupts */ diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 2a8e4a0a8172..03917bc8a4fa 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -765,6 +765,9 @@ static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, int cmd) { +#ifndef CONFIG_SND_CS46XX_NEW_DSP + unsigned long flags; +#endif cs46xx_t *chip = snd_pcm_substream_chip(substream); /*snd_pcm_runtime_t *runtime = substream->runtime;*/ int result = 0; @@ -789,7 +792,7 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, if (substream->runtime->periods != CS46XX_FRAGS) snd_cs46xx_playback_transfer(substream); #else - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); if (substream->runtime->periods != CS46XX_FRAGS) snd_cs46xx_playback_transfer(substream); { unsigned int tmp; @@ -797,7 +800,7 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, tmp &= 0x0000ffff; snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp); } - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); #endif break; case SNDRV_PCM_TRIGGER_STOP: @@ -810,13 +813,13 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, if (!cpcm->pcm_channel->unlinked) cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel); #else - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); { unsigned int tmp; tmp = snd_cs46xx_peek(chip, BA1_PCTL); tmp &= 0x0000ffff; snd_cs46xx_poke(chip, BA1_PCTL, tmp); } - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); #endif break; default: @@ -830,11 +833,12 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream, int cmd) { + unsigned long flags; cs46xx_t *chip = snd_pcm_substream_chip(substream); unsigned int tmp; int result = 0; - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -852,7 +856,7 @@ static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream, result = -EINVAL; break; } - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return result; } @@ -1149,6 +1153,7 @@ static int snd_cs46xx_capture_prepare(snd_pcm_substream_t * substream) static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; cs46xx_t *chip = dev_id; u32 status1; #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -1212,14 +1217,12 @@ static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *r if ((status1 & HISR_MIDI) && chip->rmidi) { unsigned char c; - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_RBE) == 0) { c = snd_cs46xx_peekBA0(chip, BA0_MIDRP); if ((chip->midcr & MIDCR_RIE) == 0) continue; - spin_unlock(&chip->reg_lock); snd_rawmidi_receive(chip->midi_input, &c, 1); - spin_lock(&chip->reg_lock); } while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_TBF) == 0) { if ((chip->midcr & MIDCR_TIE) == 0) @@ -1231,7 +1234,7 @@ static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *r } snd_cs46xx_pokeBA0(chip, BA0_MIDWP, c); } - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); } /* * EOI to the PCI part....reenables interrupts diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index e60d58158a13..0c64e24e1bc1 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1265,6 +1265,7 @@ static void mpu401_clear_rx(emu10k1x_t *emu, emu10k1x_midi_t *mpu) static void do_emu10k1x_midi_interrupt(emu10k1x_t *emu, emu10k1x_midi_t *midi, unsigned int status) { + unsigned long flags; unsigned char byte; if (midi->rmidi == NULL) { @@ -1278,15 +1279,13 @@ static void do_emu10k1x_midi_interrupt(emu10k1x_t *emu, emu10k1x_midi_t *midi, u mpu401_clear_rx(emu, midi); } else { byte = mpu401_read_data(emu, midi); - spin_unlock(&midi->input_lock); if (midi->substream_input) snd_rawmidi_receive(midi->substream_input, &byte, 1); - spin_lock(&midi->input_lock); } } spin_unlock(&midi->input_lock); - spin_lock(&midi->output_lock); + spin_lock_irqsave(&midi->output_lock, flags); if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { if (midi->substream_output && snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { @@ -1295,7 +1294,7 @@ static void do_emu10k1x_midi_interrupt(emu10k1x_t *emu, emu10k1x_midi_t *midi, u snd_emu10k1x_intr_disable(emu, midi->tx_enable); } } - spin_unlock(&midi->output_lock); + spin_unlock_irqrestore(&midi->output_lock, flags); } static void snd_emu10k1x_midi_interrupt(emu10k1x_t *emu, unsigned int status) diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 5c4cfc829ce4..c54d0fc7ed90 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -73,6 +73,7 @@ static void mpu401_clear_rx(emu10k1_t *emu, emu10k1_midi_t *mpu) static void do_emu10k1_midi_interrupt(emu10k1_t *emu, emu10k1_midi_t *midi, unsigned int status) { + unsigned long flags; unsigned char byte; if (midi->rmidi == NULL) { @@ -86,15 +87,13 @@ static void do_emu10k1_midi_interrupt(emu10k1_t *emu, emu10k1_midi_t *midi, unsi mpu401_clear_rx(emu, midi); } else { byte = mpu401_read_data(emu, midi); - spin_unlock(&midi->input_lock); if (midi->substream_input) snd_rawmidi_receive(midi->substream_input, &byte, 1); - spin_lock(&midi->input_lock); } } spin_unlock(&midi->input_lock); - spin_lock(&midi->output_lock); + spin_lock_irqsave(&midi->output_lock, flags); if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { if (midi->substream_output && snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { @@ -103,7 +102,7 @@ static void do_emu10k1_midi_interrupt(emu10k1_t *emu, emu10k1_midi_t *midi, unsi snd_emu10k1_intr_disable(emu, midi->tx_enable); } } - spin_unlock(&midi->output_lock); + spin_unlock_irqrestore(&midi->output_lock, flags); } static void snd_emu10k1_midi_interrupt(emu10k1_t *emu, unsigned int status) diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 900069b69af9..effb296660d2 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -754,6 +754,8 @@ static void snd_es1371_dac2_rate(ensoniq_t * ensoniq, unsigned int rate) static int snd_ensoniq_trigger(snd_pcm_substream_t *substream, int cmd) { + unsigned long flags; + ensoniq_t *ensoniq = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -773,13 +775,13 @@ static int snd_ensoniq_trigger(snd_pcm_substream_t *substream, int cmd) } else if (s == ensoniq->capture_substream) return -EINVAL; } - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) ensoniq->sctrl |= what; else ensoniq->sctrl &= ~what; outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); break; } case SNDRV_PCM_TRIGGER_START: @@ -801,13 +803,13 @@ static int snd_ensoniq_trigger(snd_pcm_substream_t *substream, int cmd) snd_pcm_trigger_done(s, substream); } } - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); if (cmd == SNDRV_PCM_TRIGGER_START) ensoniq->ctrl |= what; else ensoniq->ctrl &= ~what; outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); break; } default: @@ -956,10 +958,11 @@ static int snd_ensoniq_capture_prepare(snd_pcm_substream_t * substream) static snd_pcm_uframes_t snd_ensoniq_playback1_pointer(snd_pcm_substream_t * substream) { + unsigned long flags; ensoniq_t *ensoniq = snd_pcm_substream_chip(substream); size_t ptr; - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); if (inl(ES_REG(ensoniq, CONTROL)) & ES_DAC1_EN) { outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, DAC1_SIZE))); @@ -967,16 +970,17 @@ static snd_pcm_uframes_t snd_ensoniq_playback1_pointer(snd_pcm_substream_t * sub } else { ptr = 0; } - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); return ptr; } static snd_pcm_uframes_t snd_ensoniq_playback2_pointer(snd_pcm_substream_t * substream) { + unsigned long flags; ensoniq_t *ensoniq = snd_pcm_substream_chip(substream); size_t ptr; - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); if (inl(ES_REG(ensoniq, CONTROL)) & ES_DAC2_EN) { outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, DAC2_SIZE))); @@ -984,16 +988,17 @@ static snd_pcm_uframes_t snd_ensoniq_playback2_pointer(snd_pcm_substream_t * sub } else { ptr = 0; } - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); return ptr; } static snd_pcm_uframes_t snd_ensoniq_capture_pointer(snd_pcm_substream_t * substream) { + unsigned long flags; ensoniq_t *ensoniq = snd_pcm_substream_chip(substream); size_t ptr; - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); if (inl(ES_REG(ensoniq, CONTROL)) & ES_ADC_EN) { outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE)); ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, ADC_SIZE))); @@ -1001,7 +1006,7 @@ static snd_pcm_uframes_t snd_ensoniq_capture_pointer(snd_pcm_substream_t * subst } else { ptr = 0; } - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); return ptr; } @@ -2030,27 +2035,26 @@ static int __devinit snd_ensoniq_create(snd_card_t * card, static void snd_ensoniq_midi_interrupt(ensoniq_t * ensoniq) { + unsigned long flags; snd_rawmidi_t * rmidi = ensoniq->rmidi; unsigned char status, mask, byte; if (rmidi == NULL) return; /* do Rx at first */ - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); mask = ensoniq->uartm & ES_MODE_INPUT ? ES_RXRDY : 0; while (mask) { status = inb(ES_REG(ensoniq, UART_STATUS)); if ((status & mask) == 0) break; byte = inb(ES_REG(ensoniq, UART_DATA)); - spin_unlock(&ensoniq->reg_lock); snd_rawmidi_receive(ensoniq->midi_input, &byte, 1); - spin_lock(&ensoniq->reg_lock); } - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); /* do Tx at second */ - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); mask = ensoniq->uartm & ES_MODE_OUTPUT ? ES_TXRDY : 0; while (mask) { status = inb(ES_REG(ensoniq, UART_STATUS)); @@ -2064,7 +2068,7 @@ static void snd_ensoniq_midi_interrupt(ensoniq_t * ensoniq) outb(byte, ES_REG(ensoniq, UART_DATA)); } } - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); } static int snd_ensoniq_midi_input_open(snd_rawmidi_substream_t * substream) @@ -2231,6 +2235,7 @@ static int __devinit snd_ensoniq_midi(ensoniq_t * ensoniq, int device, snd_rawmi static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; ensoniq_t *ensoniq = dev_id; unsigned int status, sctrl; @@ -2241,7 +2246,7 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs if (!(status & ES_INTR)) return IRQ_NONE; - spin_lock(&ensoniq->reg_lock); + spin_lock_irqsave(&ensoniq->reg_lock, flags); sctrl = ensoniq->sctrl; if (status & ES_DAC1) sctrl &= ~ES_P1_INT_EN; @@ -2251,7 +2256,7 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs sctrl &= ~ES_R1_INT_EN; outl(sctrl, ES_REG(ensoniq, SERIAL)); outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); - spin_unlock(&ensoniq->reg_lock); + spin_unlock_irqrestore(&ensoniq->reg_lock, flags); if (status & ES_UART) snd_ensoniq_midi_interrupt(ensoniq); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 12efbf0fab54..cb0b8fbe18f8 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3905,6 +3905,7 @@ static int snd_hdsp_ioctl(snd_pcm_substream_t *substream, static int snd_hdsp_trigger(snd_pcm_substream_t *substream, int cmd) { + unsigned long flags; hdsp_t *hdsp = snd_pcm_substream_chip(substream); snd_pcm_substream_t *other; int running; @@ -3924,7 +3925,7 @@ static int snd_hdsp_trigger(snd_pcm_substream_t *substream, int cmd) return -EIO; } - spin_lock(&hdsp->lock); + spin_lock_irqsave(&hdsp->lock, flags); running = hdsp->running; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -3935,7 +3936,7 @@ static int snd_hdsp_trigger(snd_pcm_substream_t *substream, int cmd) break; default: snd_BUG(); - spin_unlock(&hdsp->lock); + spin_unlock_irqrestore(&hdsp->lock, flags); return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -3977,7 +3978,7 @@ static int snd_hdsp_trigger(snd_pcm_substream_t *substream, int cmd) else if (hdsp->running && !running) hdsp_stop_audio(hdsp); hdsp->running = running; - spin_unlock(&hdsp->lock); + spin_unlock_irqrestore(&hdsp->lock, flags); return 0; } -- cgit v1.2.3 From 4eaf05ae2cba578ce00d92c1c274d18d256bc919 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 11 Mar 2005 10:57:50 +0100 Subject: [ALSA] AC97 wm9713 support AC97 Codec This patch series adds support for the WM9713/WM9714 family of AC97 codecs. This family is different from 'standard' AC97 codecs in that the default codec power state is 'off'. i.e. performing a register reset will power the device down. This patch also adds better support for larger single/double channel enumerated mixer types. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- include/sound/ac97_codec.h | 14 +++ sound/pci/ac97/ac97_codec.c | 279 ++++++++++++++++++++------------------------ sound/pci/ac97/ac97_local.h | 16 +++ sound/pci/ac97/ac97_patch.c | 130 +++++++++++++++++++++ sound/pci/ac97/ac97_patch.h | 1 + 5 files changed, 290 insertions(+), 150 deletions(-) (limited to 'include') diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index d421d964cf63..a841033c1c76 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -366,6 +366,13 @@ #define AC97_DOUBLE_RATE (1<<5) /* supports double rate playback */ #define AC97_HAS_NO_MASTER_VOL (1<<6) /* no Master volume */ #define AC97_HAS_NO_PCM_VOL (1<<7) /* no PCM volume */ +#define AC97_DEFAULT_POWER_OFF (1<<8) /* no RESET write */ +#define AC97_MODEM_PATCH (1<<9) /* modem patch */ +#define AC97_HAS_NO_REC_GAIN (1<<10) /* no Record gain */ +#define AC97_HAS_NO_PHONE (1<<11) /* no PHONE volume */ +#define AC97_HAS_NO_PC_BEEP (1<<12) /* no PC Beep volume */ +#define AC97_HAS_NO_VIDEO (1<<13) /* no Video volume */ +#define AC97_HAS_NO_CD (1<<14) /* no CD volume */ /* rates indexes */ #define AC97_RATES_FRONT_DAC 0 @@ -580,4 +587,11 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, int snd_ac97_pcm_close(struct ac97_pcm *pcm); int snd_ac97_pcm_double_rate_rules(snd_pcm_runtime_t *runtime); +struct ac97_enum { + unsigned char reg; + unsigned char shift_l; + unsigned char shift_r; + unsigned short mask; + const char **texts; +}; #endif /* __SOUND_AC97_CODEC_H */ diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 78d370abcbd8..c2c9d0a5466c 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -56,6 +56,7 @@ typedef struct { const char *name; int (*patch)(ac97_t *ac97); int (*mpatch)(ac97_t *ac97); + unsigned int flags; } ac97_codec_id_t; static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = { @@ -162,6 +163,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { { 0x574d4C05, 0xffffffff, "WM9705/WM9710", patch_wolfson05, NULL}, { 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL}, { 0x574d4C12, 0xffffffff, "WM9711/WM9712", patch_wolfson11, NULL}, +{ 0x574d4c13, 0xffffffff, "WM9713/WM9714", patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF}, { 0x594d4800, 0xffffffff, "YMF743", NULL, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, { 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL }, @@ -442,108 +444,52 @@ static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned sho * Controls */ -/* input mux */ -static int snd_ac97_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +int snd_ac97_info_enum_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[8] = { - "Mic", "CD", "Video", "Aux", "Line", - "Mix", "Mix Mono", "Phone" - }; - + struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item > 7) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int snd_ac97_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; + uinfo->count = e->shift_l == e->shift_r ? 1 : 2; + uinfo->value.enumerated.items = e->mask; - val = snd_ac97_read_cache(ac97, AC97_REC_SEL); - ucontrol->value.enumerated.item[0] = (val >> 8) & 7; - ucontrol->value.enumerated.item[1] = (val >> 0) & 7; + if (uinfo->value.enumerated.item > e->mask - 1) + uinfo->value.enumerated.item = e->mask - 1; + strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]); return 0; } -static int snd_ac97_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; unsigned short val; - if (ucontrol->value.enumerated.item[0] > 7 || - ucontrol->value.enumerated.item[1] > 7) - return -EINVAL; - val = (ucontrol->value.enumerated.item[0] << 8) | - (ucontrol->value.enumerated.item[1] << 0); - return snd_ac97_update(ac97, AC97_REC_SEL, val); -} - -/* standard stereo enums */ -#define AC97_ENUM_DOUBLE(xname, reg, shift, invert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_enum_double, \ - .get = snd_ac97_get_enum_double, .put = snd_ac97_put_enum_double, \ - .private_value = reg | (shift << 8) | (invert << 24) } - -static int snd_ac97_info_enum_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - static char *texts1[2] = { "pre 3D", "post 3D" }; - static char *texts2[2] = { "Mix", "Mic" }; - static char *texts3[2] = { "Mic1", "Mic2" }; - char **texts = NULL; - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0xff; - - switch (reg) { - case AC97_GENERAL_PURPOSE: - switch (shift) { - case 15: texts = texts1; break; - case 9: texts = texts2; break; - case 8: texts = texts3; break; - } - } - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} + val = snd_ac97_read_cache(ac97, e->reg); + ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1); + if (e->shift_l != e->shift_r) + ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1); -static int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; - - val = (snd_ac97_read_cache(ac97, reg) >> shift) & 1; - if (invert) - val ^= 1; - ucontrol->value.enumerated.item[0] = val; return 0; } -static int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; unsigned short val; - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; + unsigned short mask; - if (ucontrol->value.enumerated.item[0] > 1) + if (ucontrol->value.enumerated.item[0] > e->mask - 1) return -EINVAL; - val = !!ucontrol->value.enumerated.item[0]; - if (invert) - val = !val; - return snd_ac97_update_bits(ac97, reg, 1 << shift, val << shift); + val = ucontrol->value.enumerated.item[0] << e->shift_l; + mask = (e->mask - 1) << e->shift_l; + if (e->shift_l != e->shift_r) { + if (ucontrol->value.enumerated.item[1] > e->mask - 1) + return -EINVAL; + val |= ucontrol->value.enumerated.item[1] << e->shift_r; + mask |= (e->mask - 1) << e->shift_r; + } + return snd_ac97_update_bits(ac97, e->reg, mask, val); } /* save/restore ac97 v2.3 paging */ @@ -635,11 +581,6 @@ int snd_ac97_put_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontro return err; } -#define AC97_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_ac97_info_volsw, \ - .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \ - .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) } - static const snd_kcontrol_new_t snd_ac97_controls_master_mono[2] = { AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), AC97_SINGLE("Master Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1) @@ -659,14 +600,21 @@ static const snd_kcontrol_new_t snd_ac97_controls_mic_boost = AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0); -static const snd_kcontrol_new_t snd_ac97_control_capture_src = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_ac97_info_mux, - .get = snd_ac97_get_mux, - .put = snd_ac97_put_mux, +static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"}; +static const char* std_3d_path[] = {"pre 3D", "post 3D"}; +static const char* std_mix[] = {"Mix", "Mic"}; +static const char* std_mic[] = {"Mic1", "Mic2"}; + +static const struct ac97_enum std_enum[] = { +AC97_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, std_rec_sel), +AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, std_3d_path), +AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, std_mix), +AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, std_mic), }; +static const snd_kcontrol_new_t snd_ac97_control_capture_src = +AC97_ENUM("Capture Source", std_enum[0]); + static const snd_kcontrol_new_t snd_ac97_control_capture_vol = AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0); @@ -686,12 +634,12 @@ typedef enum { } ac97_general_index_t; static const snd_kcontrol_new_t snd_ac97_controls_general[7] = { -AC97_ENUM_DOUBLE("PCM Out Path & Mute", AC97_GENERAL_PURPOSE, 15, 0), +AC97_ENUM("PCM Out Path & Mute", std_enum[1]), AC97_SINGLE("Simulated Stereo Enhancement", AC97_GENERAL_PURPOSE, 14, 1, 0), AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0), AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0), -AC97_ENUM_DOUBLE("Mono Output Select", AC97_GENERAL_PURPOSE, 9, 0), -AC97_ENUM_DOUBLE("Mic Select", AC97_GENERAL_PURPOSE, 8, 0), +AC97_ENUM("Mono Output Select", std_enum[2]), +AC97_ENUM("Mic Select", std_enum[3]), AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0) }; @@ -1360,8 +1308,9 @@ static int snd_ac97_mixer_build(ac97_t * ac97) } /* build PC Speaker controls */ - if ((ac97->flags & AC97_HAS_PC_BEEP) || - snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP)) { + if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) && + ((ac97->flags & AC97_HAS_PC_BEEP) || + snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) return err; @@ -1370,9 +1319,11 @@ static int snd_ac97_mixer_build(ac97_t * ac97) } /* build Phone controls */ - if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { - if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0) - return err; + if (!(ac97->flags & AC97_HAS_NO_PHONE)) { + if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { + if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0) + return err; + } } /* build MIC controls */ @@ -1390,15 +1341,19 @@ static int snd_ac97_mixer_build(ac97_t * ac97) } /* build CD controls */ - if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { - if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0) - return err; + if (!(ac97->flags & AC97_HAS_NO_CD)) { + if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { + if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0) + return err; + } } /* build Video controls */ - if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { - if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0) - return err; + if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { + if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { + if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0) + return err; + } } /* build Aux controls */ @@ -1444,17 +1399,18 @@ static int snd_ac97_mixer_build(ac97_t * ac97) } /* build Capture controls */ - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) - return err; - if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { - if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0) + if (!(ac97->flags & AC97_HAS_NO_REC_GAIN)) { + if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) return err; + if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { + if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0) + return err; + } + if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) + return err; + snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); + snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); } - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) - return err; - snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); - snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); - /* build MIC Capture controls */ if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { for (idx = 0; idx < 2; idx++) @@ -1672,6 +1628,18 @@ static unsigned int snd_ac97_determine_spdif_rates(ac97_t *ac97) return result; } +/* look for the codec id table matching with the given id */ +static const ac97_codec_id_t *look_for_codec_id(const ac97_codec_id_t *table, + unsigned int id) +{ + const ac97_codec_id_t *pid; + + for (pid = table; pid->id; pid++) + if (pid->id == (id & pid->mask)) + return pid; + return NULL; +} + void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem) { const ac97_codec_id_t *pid; @@ -1680,35 +1648,30 @@ void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem) printable(id >> 24), printable(id >> 16), printable(id >> 8)); - for (pid = snd_ac97_codec_id_vendors; pid->id; pid++) - if (pid->id == (id & pid->mask)) { - strcpy(name, pid->name); - if (ac97) { - if (!modem && pid->patch) - pid->patch(ac97); - else if (modem && pid->mpatch) - pid->mpatch(ac97); - } - goto __vendor_ok; - } - return; + pid = look_for_codec_id(snd_ac97_codec_id_vendors, id); + if (! pid) + return; - __vendor_ok: - for (pid = snd_ac97_codec_ids; pid->id; pid++) - if (pid->id == (id & pid->mask)) { - strcat(name, " "); - strcat(name, pid->name); - if (pid->mask != 0xffffffff) - sprintf(name + strlen(name), " rev %d", id & ~pid->mask); - if (ac97) { - if (!modem && pid->patch) - pid->patch(ac97); - else if (modem && pid->mpatch) - pid->mpatch(ac97); - } - return; + strcpy(name, pid->name); + if (ac97 && pid->patch) { + if ((modem && (pid->flags & AC97_MODEM_PATCH)) || + (! modem && ! (pid->flags & AC97_MODEM_PATCH))) + pid->patch(ac97); + } + + pid = look_for_codec_id(snd_ac97_codec_ids, id); + if (pid) { + strcat(name, " "); + strcat(name, pid->name); + if (pid->mask != 0xffffffff) + sprintf(name + strlen(name), " rev %d", id & ~pid->mask); + if (ac97 && pid->patch) { + if ((modem && (pid->flags & AC97_MODEM_PATCH)) || + (! modem && ! (pid->flags & AC97_MODEM_PATCH))) + pid->patch(ac97); } - sprintf(name + strlen(name), " id %x", id & 0xff); + } else + sprintf(name + strlen(name), " id %x", id & 0xff); } /** @@ -1850,6 +1813,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) char name[64]; unsigned long end_time; unsigned int reg; + const ac97_codec_id_t *pid; static snd_device_ops_t ops = { .dev_free = snd_ac97_dev_free, }; @@ -1900,6 +1864,14 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) goto __access_ok; } + ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; + ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); + if (ac97->id && ac97->id != (unsigned int)-1) { + pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id); + if (pid && (pid->flags & AC97_DEFAULT_POWER_OFF)) + goto __access_ok; + } + snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ if (bus->ops->wait) bus->ops->wait(ac97); @@ -1926,6 +1898,9 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) snd_ac97_free(ac97); return -EIO; } + pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id); + if (pid) + ac97->flags |= pid->flags; /* test for AC'97 */ if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) { @@ -1964,10 +1939,12 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) if (ac97_is_audio(ac97)) { /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0); - snd_ac97_write_cache(ac97, AC97_RESET, 0); /* reset to defaults */ - udelay(100); + if (! (ac97->flags & AC97_DEFAULT_POWER_OFF)) { + snd_ac97_write_cache(ac97, AC97_RESET, 0); /* reset to defaults */ + udelay(100); + snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0); + } /* nothing should be in powerdown mode */ - snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0); snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); end_time = jiffies + (HZ / 10); do { @@ -2234,9 +2211,11 @@ void snd_ac97_resume(ac97_t *ac97) } snd_ac97_write(ac97, AC97_POWERDOWN, 0); - snd_ac97_write(ac97, AC97_RESET, 0); - udelay(100); - snd_ac97_write(ac97, AC97_POWERDOWN, 0); + if (! (ac97->flags & AC97_DEFAULT_POWER_OFF)) { + snd_ac97_write(ac97, AC97_RESET, 0); + udelay(100); + snd_ac97_write(ac97, AC97_POWERDOWN, 0); + } snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0); snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]); diff --git a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h index fe41f9c3d818..536a4d4793af 100644 --- a/sound/pci/ac97/ac97_local.h +++ b/sound/pci/ac97/ac97_local.h @@ -32,6 +32,19 @@ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_volsw, \ .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \ .private_value = AC97_PAGE_SINGLE_VALUE(reg, shift, mask, invert, page) } +#define AC97_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_ac97_info_volsw, \ + .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \ + .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) } +#define AC97_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ +{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ + .mask = xmask, .texts = xtexts } +#define AC97_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \ + AC97_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts) +#define AC97_ENUM(xname, xenum) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_enum_double, \ + .get = snd_ac97_get_enum_double, .put = snd_ac97_put_enum_double, \ + .private_value = (unsigned long)&xenum } /* ac97_codec.c */ extern const char *snd_ac97_stereo_enhancements[]; @@ -49,6 +62,9 @@ int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char * void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst); void snd_ac97_restore_status(ac97_t *ac97); void snd_ac97_restore_iec958(ac97_t *ac97); +int snd_ac97_info_enum_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo); +int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); +int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_update_bits_nolock(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value); diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 3df9bef91f1e..65e6b2149d86 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -305,6 +305,136 @@ int patch_wolfson11(ac97_t * ac97) return 0; } +static const char* wm9713_mic_mixer[] = {"Stereo", "Mic1", "Mic2", "Mute"}; +static const char* wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; +static const char* wm9713_rec_src_l[] = {"Mic1", "Mic2", "Line L", "Mono In", "HP Mix L", "Spk Mix", "Mono Mix", "Zh"}; +static const char* wm9713_rec_src_r[] = {"Mic1", "Mic2", "Line R", "Mono In", "HP Mix R", "Spk Mix", "Mono Mix", "Zh"}; + +static const struct ac97_enum wm9713_enum[] = { +AC97_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer), +AC97_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux), +AC97_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux), +AC97_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src_l), +AC97_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src_r), +}; + +static const snd_kcontrol_new_t wm13_snd_ac97_controls_line_in[] = { +AC97_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1), +AC97_SINGLE("Line In to Headphone Mute", AC97_PC_BEEP, 15, 1, 1), +AC97_SINGLE("Line In to Speaker Mute", AC97_PC_BEEP, 14, 1, 1), +AC97_SINGLE("Line In to Mono Mute", AC97_PC_BEEP, 13, 1, 1), +}; + +static const snd_kcontrol_new_t wm13_snd_ac97_controls_dac[] = { +AC97_DOUBLE("DAC Volume", AC97_PHONE, 8, 0, 31, 1), +AC97_SINGLE("DAC to Headphone Mute", AC97_PHONE, 15, 1, 1), +AC97_SINGLE("DAC to Speaker Mute", AC97_PHONE, 14, 1, 1), +AC97_SINGLE("DAC to Mono Mute", AC97_PHONE, 13, 1, 1), +}; + +static const snd_kcontrol_new_t wm13_snd_ac97_controls_mic[] = { +AC97_SINGLE("MICA Volume", AC97_MIC, 8, 31, 1), +AC97_SINGLE("MICB Volume", AC97_MIC, 0, 31, 1), +AC97_SINGLE("MICA to Mono Mute", AC97_LINE, 7, 1, 1), +AC97_SINGLE("MICB to Mono Mute", AC97_LINE, 6, 1, 1), +AC97_SINGLE("MIC Boost (+20dB)", AC97_LINE, 5, 1, 1), +AC97_ENUM("MIC Headphone Routing", wm9713_enum[0]), +AC97_SINGLE("MIC Headphone Mixer Volume", AC97_LINE, 0, 7, 1) +}; + +static const snd_kcontrol_new_t wm13_snd_ac97_controls_adc[] = { +AC97_SINGLE("ADC Mute", AC97_CD, 15, 1, 1), +AC97_DOUBLE("Gain Step Size (1.5dB/0.75dB)", AC97_CD, 14, 6, 1, 1), +AC97_DOUBLE("ADC Volume",AC97_CD, 8, 0, 15, 0), +AC97_SINGLE("ADC Zero Cross", AC97_CD, 7, 1, 1), +}; + +static const snd_kcontrol_new_t wm13_snd_ac97_controls_recsel[] = { +AC97_ENUM("Record to Headphone Path", wm9713_enum[1]), +AC97_SINGLE("Record to Headphone Volume", AC97_VIDEO, 11, 7, 0), +AC97_ENUM("Record to Mono Path", wm9713_enum[2]), +AC97_SINGLE("Record to Mono Boost (+20dB)", AC97_VIDEO, 8, 1, 0), +AC97_SINGLE("Record ADC Boost (+20dB)", AC97_VIDEO, 6, 1, 0), +AC97_ENUM("Record Select Left", wm9713_enum[3]), +AC97_ENUM("Record Select Right", wm9713_enum[4]), +}; + +static int patch_wolfson_wm9713_specific(ac97_t * ac97) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_line_in); i++) { + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_line_in[i], ac97))) < 0) + return err; + } + snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808); + + for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_dac); i++) { + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_dac[i], ac97))) < 0) + return err; + } + snd_ac97_write_cache(ac97, AC97_PHONE, 0x0808); + + for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_mic); i++) { + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_mic[i], ac97))) < 0) + return err; + } + snd_ac97_write_cache(ac97, AC97_MIC, 0x0808); + snd_ac97_write_cache(ac97, AC97_LINE, 0x00da); + + for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_adc); i++) { + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_adc[i], ac97))) < 0) + return err; + } + snd_ac97_write_cache(ac97, AC97_CD, 0x0808); + + for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_recsel); i++) { + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_recsel[i], ac97))) < 0) + return err; + } + snd_ac97_write_cache(ac97, AC97_VIDEO, 0xd612); + snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x1ba0); + + return 0; +} + +#ifdef CONFIG_PM +static void patch_wolfson_wm9713_suspend (ac97_t * ac97) +{ + snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xfeff); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xffff); +} + +static void patch_wolfson_wm9713_resume (ac97_t * ac97) +{ + snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810); + snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0x0); +} +#endif + +static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = { + .build_specific = patch_wolfson_wm9713_specific, +#ifdef CONFIG_PM + .suspend = patch_wolfson_wm9713_suspend, + .resume = patch_wolfson_wm9713_resume +#endif +}; + +int patch_wolfson13(ac97_t * ac97) +{ + ac97->build_ops = &patch_wolfson_wm9713_ops; + + ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_PHONE | + AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD; + + snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810); + snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0x0); + + return 0; +} + /* * Tritech codec */ diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 641b0be889ea..6db51c96f5d0 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -28,6 +28,7 @@ int patch_wolfson03(ac97_t * ac97); int patch_wolfson04(ac97_t * ac97); int patch_wolfson05(ac97_t * ac97); int patch_wolfson11(ac97_t * ac97); +int patch_wolfson13(ac97_t * ac97); int patch_tritech_tr28028(ac97_t * ac97); int patch_sigmatel_stac9700(ac97_t * ac97); int patch_sigmatel_stac9708(ac97_t * ac97); -- cgit v1.2.3