#include <sound/driver.h>
#include <linux/threads.h>
#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
err = -EFAULT;
goto __error2;
}
- ctl = snd_magic_kcalloc(snd_ctl_file_t, 0, GFP_KERNEL);
+ ctl = kcalloc(1, sizeof(*ctl), GFP_KERNEL);
if (ctl == NULL) {
err = -ENOMEM;
goto __error;
snd_kcontrol_t *control;
unsigned int idx;
- ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+ ctl = file->private_data;
fasync_helper(-1, file, 0, &ctl->fasync);
file->private_data = NULL;
card = ctl->card;
}
up_write(&card->controls_rwsem);
snd_ctl_empty_read_queue(ctl);
- snd_magic_kfree(ctl);
+ kfree(ctl);
module_put(card->module);
snd_card_file_remove(card, file);
return 0;
goto _found;
}
}
- ev = snd_kcalloc(sizeof(*ev), GFP_ATOMIC);
+ ev = kcalloc(1, sizeof(*ev), GFP_ATOMIC);
if (ev) {
ev->id = *id;
ev->mask = mask;
snd_runtime_check(control != NULL, return NULL);
snd_runtime_check(control->count > 0, return NULL);
- kctl = (snd_kcontrol_t *)snd_magic_kcalloc(snd_kcontrol_t,
- sizeof(snd_kcontrol_volatile_t) * control->count,
- GFP_KERNEL);
+ kctl = kcalloc(1, sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL);
if (kctl == NULL)
return NULL;
*kctl = *control;
if (kcontrol) {
if (kcontrol->private_free)
kcontrol->private_free(kcontrol);
- snd_magic_kfree(kcontrol);
+ kfree(kcontrol);
}
}
}
static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, void __user *arg)
{
snd_ctl_card_info_t info;
strlcpy(info.mixername, card->mixername, sizeof(info.mixername));
strlcpy(info.components, card->components, sizeof(info.components));
up_read(&snd_ioctl_rwsem);
- if (copy_to_user((void *) arg, &info, sizeof(snd_ctl_card_info_t)))
+ if (copy_to_user(arg, &info, sizeof(snd_ctl_card_info_t)))
return -EFAULT;
return 0;
}
-static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t *_list)
+static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list)
{
struct list_head *plist;
snd_ctl_elem_list_t list;
return 0;
}
-static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *_info)
+static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
{
snd_card_t *card = ctl->card;
snd_ctl_elem_info_t info;
return result;
}
-static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *_control)
+static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t __user *_control)
{
snd_ctl_elem_value_t *control;
snd_kcontrol_t *kctl;
return result;
}
-static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t *_control)
+static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control)
{
snd_card_t *card = file->card;
snd_ctl_elem_value_t *control;
return result;
}
-static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
+static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
{
snd_card_t *card = file->card;
snd_ctl_elem_id_t id;
return result;
}
-static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
+static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
{
snd_card_t *card = file->card;
snd_ctl_elem_id_t id;
kfree(kcontrol->private_data);
}
-static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *_info, int replace)
+static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
{
snd_card_t *card = file->card;
snd_ctl_elem_info_t info;
if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT))
for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++)
dimen_size += sizeof(unsigned short);
- ue = snd_kcalloc(sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL);
+ ue = kcalloc(1, sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL);
if (ue == NULL)
return -ENOMEM;
ue->type = info.type;
return 0;
}
-static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
+static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
{
snd_ctl_elem_id_t id;
return snd_ctl_remove_unlocked_id(file, &id);
}
-static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int *ptr)
+static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int __user *ptr)
{
int subscribe;
if (get_user(subscribe, ptr))
return 0;
}
-static int snd_ctl_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+#ifdef CONFIG_PM
+/*
+ * change the power state
+ */
+static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state)
+{
+ switch (power_state) {
+ case SNDRV_CTL_POWER_D0:
+ case SNDRV_CTL_POWER_D1:
+ case SNDRV_CTL_POWER_D2:
+ if (card->power_state != power_state)
+ /* FIXME: pass the correct state value */
+ card->pm_resume(card, 0);
+ break;
+ case SNDRV_CTL_POWER_D3hot:
+ case SNDRV_CTL_POWER_D3cold:
+ if (card->power_state != power_state)
+ /* FIXME: pass the correct state value */
+ card->pm_suspend(card, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
+static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
snd_ctl_file_t *ctl;
snd_card_t *card;
struct list_head *list;
snd_kctl_ioctl_t *p;
+ void __user *argp = (void __user *)arg;
+ int __user *ip = argp;
int err;
- ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+ ctl = file->private_data;
card = ctl->card;
snd_assert(card != NULL, return -ENXIO);
switch (cmd) {
case SNDRV_CTL_IOCTL_PVERSION:
- return put_user(SNDRV_CTL_VERSION, (int *)arg) ? -EFAULT : 0;
+ return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
case SNDRV_CTL_IOCTL_CARD_INFO:
- return snd_ctl_card_info(card, ctl, cmd, arg);
+ return snd_ctl_card_info(card, ctl, cmd, argp);
case SNDRV_CTL_IOCTL_ELEM_LIST:
- return snd_ctl_elem_list(ctl->card, (snd_ctl_elem_list_t *) arg);
+ return snd_ctl_elem_list(ctl->card, argp);
case SNDRV_CTL_IOCTL_ELEM_INFO:
- return snd_ctl_elem_info(ctl, (snd_ctl_elem_info_t *) arg);
+ return snd_ctl_elem_info(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_READ:
- return snd_ctl_elem_read(ctl->card, (snd_ctl_elem_value_t *) arg);
+ return snd_ctl_elem_read(ctl->card, argp);
case SNDRV_CTL_IOCTL_ELEM_WRITE:
- return snd_ctl_elem_write(ctl, (snd_ctl_elem_value_t *) arg);
+ return snd_ctl_elem_write(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_LOCK:
- return snd_ctl_elem_lock(ctl, (snd_ctl_elem_id_t *) arg);
+ return snd_ctl_elem_lock(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
- return snd_ctl_elem_unlock(ctl, (snd_ctl_elem_id_t *) arg);
+ return snd_ctl_elem_unlock(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_ADD:
- return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 0);
+ return snd_ctl_elem_add(ctl, argp, 0);
case SNDRV_CTL_IOCTL_ELEM_REPLACE:
- return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 1);
+ return snd_ctl_elem_add(ctl, argp, 1);
case SNDRV_CTL_IOCTL_ELEM_REMOVE:
- return snd_ctl_elem_remove(ctl, (snd_ctl_elem_id_t *) arg);
+ return snd_ctl_elem_remove(ctl, argp);
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
- return snd_ctl_subscribe_events(ctl, (int *) arg);
+ return snd_ctl_subscribe_events(ctl, ip);
case SNDRV_CTL_IOCTL_POWER:
- if (get_user(err, (int *)arg))
+ if (get_user(err, ip))
return -EFAULT;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
#ifdef CONFIG_PM
- if (card->set_power_state) {
+ if (card->pm_suspend && card->pm_resume) {
snd_power_lock(card);
- err = card->set_power_state(card, err);
+ err = snd_ctl_set_power_state(card, err);
snd_power_unlock(card);
} else
#endif
return err;
case SNDRV_CTL_IOCTL_POWER_STATE:
#ifdef CONFIG_PM
- return put_user(card->power_state, (int *)arg) ? -EFAULT : 0;
+ return put_user(card->power_state, ip) ? -EFAULT : 0;
#else
- return put_user(SNDRV_CTL_POWER_D0, (int *)arg) ? -EFAULT : 0;
+ return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
#endif
}
down_read(&snd_ioctl_rwsem);
return -ENOTTY;
}
-static ssize_t snd_ctl_read(struct file *file, char *buffer, size_t count, loff_t * offset)
+/* 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;
int err = 0;
ssize_t result = 0;
- ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+ ctl = file->private_data;
snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);
if (!ctl->subscribed)
return -EBADFD;
wait_queue_t wait;
if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
err = -EAGAIN;
- goto __end;
+ goto __end_lock;
}
init_waitqueue_entry(&wait, current);
add_wait_queue(&ctl->change_sleep, &wait);
count -= sizeof(snd_ctl_event_t);
result += sizeof(snd_ctl_event_t);
}
- __end:
+ __end_lock:
spin_unlock_irq(&ctl->read_lock);
+ __end:
return result > 0 ? result : err;
}
unsigned int mask;
snd_ctl_file_t *ctl;
- ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return 0);
+ ctl = file->private_data;
if (!ctl->subscribed)
return 0;
poll_wait(file, &ctl->change_sleep, wait);
{
snd_kctl_ioctl_t *pn;
- pn = (snd_kctl_ioctl_t *)
- snd_kcalloc(sizeof(snd_kctl_ioctl_t), GFP_KERNEL);
+ pn = kcalloc(1, sizeof(snd_kctl_ioctl_t), GFP_KERNEL);
if (pn == NULL)
return -ENOMEM;
pn->fioctl = fcn;
{
snd_ctl_file_t *ctl;
int err;
- ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+ ctl = file->private_data;
err = fasync_helper(fd, file, on, &ctl->fasync);
if (err < 0)
return err;