Commit 91fd73cd authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA update

  - Added hotplug support - disconnection of devices
  - usbaudio
    - added hotplug support
    - added support for resolution to ALSA mixer
  - ALI5451
    - added initialization for ALi 7101
  - via82xx
    - added rate initialization for all AC97 streams
  - RME HDSP
    - fixed multiface initialization
  - ICE1712
    - spin-lock cleanups
parent 2f2fc324
......@@ -111,6 +111,8 @@ snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid);
snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id);
int snd_ctl_register(snd_card_t *card);
int snd_ctl_disconnect(snd_card_t *card);
int snd_ctl_can_unregister(snd_card_t *card);
int snd_ctl_unregister(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);
......
......@@ -58,8 +58,9 @@ typedef enum {
} snd_device_type_t;
typedef enum {
SNDRV_DEV_BUILD = 0,
SNDRV_DEV_REGISTERED = 1
SNDRV_DEV_BUILD,
SNDRV_DEV_REGISTERED,
SNDRV_DEV_DISCONNECTED
} snd_device_state_t;
typedef enum {
......@@ -73,11 +74,13 @@ typedef struct _snd_device snd_device_t;
typedef int (snd_dev_free_t)(snd_device_t *device);
typedef int (snd_dev_register_t)(snd_device_t *device);
typedef int (snd_dev_disconnect_t)(snd_device_t *device);
typedef int (snd_dev_unregister_t)(snd_device_t *device);
typedef struct {
snd_dev_free_t *dev_free;
snd_dev_register_t *dev_register;
snd_dev_disconnect_t *dev_disconnect;
snd_dev_unregister_t *dev_unregister;
} snd_device_ops_t;
......@@ -109,6 +112,15 @@ typedef struct _snd_hwdep snd_hwdep_t;
typedef struct _snd_oss_mixer snd_mixer_oss_t;
#endif
/* monitor files for graceful shutdown (hotplug) */
struct snd_monitor_file {
struct file *file;
struct snd_monitor_file *next;
};
struct snd_shutdown_f_ops; /* define it later */
/* main structure for soundcard */
struct _snd_card {
......@@ -139,6 +151,12 @@ struct _snd_card {
snd_info_entry_t *proc_id; /* the card id */
struct proc_dir_entry *proc_root_link; /* number link to real id */
struct snd_monitor_file *files; /* all files associated to this card */
struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown state */
spinlock_t files_lock; /* lock the files for this card */
int shutdown; /* this card is going down */
wait_queue_head_t shutdown_sleep;
#ifdef CONFIG_PM
int (*set_power_state) (snd_card_t *card, unsigned int state);
void *power_state_private_data;
......@@ -285,19 +303,27 @@ int copy_from_user_toio(unsigned long dst, const void *src, size_t count);
/* init.c */
extern int snd_cards_count;
extern unsigned int snd_cards_lock;
extern snd_card_t *snd_cards[SNDRV_CARDS];
extern rwlock_t snd_card_rwlock;
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
extern int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int free_flag);
#define SND_MIXER_OSS_NOTIFY_REGISTER 0
#define SND_MIXER_OSS_NOTIFY_DISCONNECT 1
#define SND_MIXER_OSS_NOTIFY_FREE 2
extern int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int cmd);
#endif
snd_card_t *snd_card_new(int idx, const char *id,
struct module *module, int extra_size);
int snd_card_disconnect(snd_card_t *card);
int snd_card_free(snd_card_t *card);
int snd_card_free_in_thread(snd_card_t *card);
int snd_card_register(snd_card_t *card);
int snd_card_info_init(void);
int snd_card_info_done(void);
int snd_component_add(snd_card_t *card, const char *component);
int snd_card_file_add(snd_card_t *card, struct file *file);
int snd_card_file_remove(snd_card_t *card, struct file *file);
/* device.c */
......@@ -305,6 +331,8 @@ int snd_device_new(snd_card_t *card, snd_device_type_t type,
void *device_data, snd_device_ops_t *ops);
int snd_device_register(snd_card_t *card, void *device_data);
int snd_device_register_all(snd_card_t *card);
int snd_device_disconnect(snd_card_t *card, void *device_data);
int snd_device_disconnect_all(snd_card_t *card);
int snd_device_free(snd_card_t *card, void *device_data);
int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd);
......
......@@ -156,11 +156,10 @@ static int __init get_id(char **str, char **dst)
for (s = *str; isalpha(*s) || isdigit(*s) || *s == '_'; s++);
if (s != *str) {
*dst = (char *)kmalloc(s - *str, GFP_KERNEL);
if ((d = *dst) != NULL) {
s = *str;
while (isalpha(*s) || isdigit(*s) || *s == '_')
s = *str; d = *dst;
while (isalpha(*s) || isdigit(*s) || *s == '_')
if (d != NULL)
*d++ = *s++;
}
}
*str = s;
if (*s == ',') {
......
......@@ -61,6 +61,7 @@ struct _snd_oss_mixer {
void (*private_free_recsrc)(snd_mixer_oss_t *mixer);
struct semaphore reg_mutex;
snd_info_entry_t *proc_entry;
int oss_dev_alloc;
/* --- */
int oss_recsrc;
};
......
......@@ -443,8 +443,9 @@ struct _snd_pcm {
};
typedef struct _snd_pcm_notify {
int (*n_register) (unsigned short minor, snd_pcm_t * pcm);
int (*n_unregister) (unsigned short minor, snd_pcm_t * pcm);
int (*n_register) (snd_pcm_t * pcm);
int (*n_disconnect) (snd_pcm_t * pcm);
int (*n_unregister) (snd_pcm_t * pcm);
struct list_head list;
} snd_pcm_notify_t;
......
......@@ -77,6 +77,7 @@ typedef struct _snd_pcm_oss_stream {
typedef struct _snd_pcm_oss {
int reg;
unsigned int reg_mask;
} snd_pcm_oss_t;
#endif /* __SOUND_PCM_OSS_H */
......@@ -62,9 +62,14 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
err = -ENODEV;
goto __error1;
}
err = snd_card_file_add(card, file);
if (err < 0) {
err = -ENODEV;
goto __error1;
}
if (!try_inc_mod_count(card->module)) {
err = -EFAULT;
goto __error1;
goto __error2;
}
ctl = snd_magic_kcalloc(snd_ctl_file_t, 0, GFP_KERNEL);
if (ctl == NULL) {
......@@ -84,6 +89,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
__error:
dec_mod_count(card->module);
__error2:
snd_card_file_remove(card, file);
__error1:
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
......@@ -118,7 +125,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
card = ctl->card;
write_lock_irqsave(&card->control_rwlock, flags);
list_del(&ctl->list);
write_unlock_irqrestore(&card->control_rwlock, flags);
write_lock(&card->control_owner_lock);
list_for_each(list, &card->controls) {
control = snd_kcontrol(list);
......@@ -126,9 +132,11 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
control->owner = NULL;
}
write_unlock(&card->control_owner_lock);
write_unlock_irqrestore(&card->control_rwlock, flags);
snd_ctl_empty_read_queue(ctl);
snd_magic_kfree(ctl);
dec_mod_count(card->module);
snd_card_file_remove(card, file);
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
......@@ -808,6 +816,21 @@ int snd_ctl_register(snd_card_t *card)
return 0;
}
int snd_ctl_disconnect(snd_card_t *card)
{
struct list_head *flist;
snd_ctl_file_t *ctl;
read_lock_irq(&card->control_rwlock);
list_for_each(flist, &card->ctl_files) {
ctl = snd_ctl_file(flist);
wake_up(&ctl->change_sleep);
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
}
read_unlock_irq(&card->control_rwlock);
return 0;
}
int snd_ctl_unregister(snd_card_t *card)
{
int err, cardnum;
......
......@@ -56,7 +56,8 @@ int snd_device_free(snd_card_t *card, void *device_data)
continue;
/* unlink */
list_del(&dev->list);
if (dev->state == SNDRV_DEV_REGISTERED && dev->ops->dev_unregister) {
if ((dev->state == SNDRV_DEV_REGISTERED || dev->state == SNDRV_DEV_DISCONNECTED) &&
dev->ops->dev_unregister) {
if (dev->ops->dev_unregister(dev))
snd_printk(KERN_ERR "device unregister failure\n");
} else {
......@@ -72,6 +73,28 @@ int snd_device_free(snd_card_t *card, void *device_data)
return -ENXIO;
}
int snd_device_disconnect(snd_card_t *card, void *device_data)
{
struct list_head *list;
snd_device_t *dev;
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
if (dev->device_data != device_data)
continue;
if (dev->state == SNDRV_DEV_REGISTERED && dev->ops->dev_disconnect) {
if (dev->ops->dev_disconnect(dev))
snd_printk(KERN_ERR "device disconnect failure\n");
dev->state = SNDRV_DEV_DISCONNECTED;
}
return 0;
}
snd_printd("device disconnect %p (from %p), not found\n", device_data, __builtin_return_address(0));
return -ENXIO;
}
int snd_device_register(snd_card_t *card, void *device_data)
{
struct list_head *list;
......@@ -113,6 +136,21 @@ int snd_device_register_all(snd_card_t *card)
return 0;
}
int snd_device_disconnect_all(snd_card_t *card)
{
snd_device_t *dev;
struct list_head *list;
int err = 0;
snd_assert(card != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
if (snd_device_disconnect(card, dev->device_data) < 0)
err = -ENXIO;
}
return err;
}
int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd)
{
snd_device_t *dev;
......
......@@ -933,11 +933,7 @@ snd_info_entry_t *snd_info_create_device(const char *name, unsigned int number,
p = create_proc_entry(entry->name, entry->mode, snd_proc_dev);
if (p) {
snd_info_device_entry_prepare(p, entry);
#ifndef LINUX_2_2
/* we should not set this - at least on 2.4.14 or later it causes
problems! */
/* p->proc_fops = &snd_fops; */
#else
#ifdef LINUX_2_2
p->ops = &snd_info_device_inode_operations;
#endif
} else {
......
......@@ -21,15 +21,23 @@
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/ctype.h>
#include <linux/smp_lock.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
struct snd_shutdown_f_ops {
struct file_operations f_ops;
struct snd_shutdown_f_ops *next;
};
int snd_cards_count = 0;
static unsigned int snd_cards_lock = 0; /* locked for registering/using */
unsigned int snd_cards_lock = 0; /* locked for registering/using */
snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
rwlock_t snd_card_rwlock = RW_LOCK_UNLOCKED;
......@@ -42,6 +50,16 @@ static void snd_card_id_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer
snd_iprintf(buffer, "%s\n", entry->card->id);
}
/**
* snd_card_new: create and initialize a soundcard structure
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
* @xid: card identification (ASCII string)
* @module: top level module for locking
* @extra_size: allocate this extra size after the main soundcard structure
*
* Returns kmallocated snd_card_t structure. Creates the ALSA control interface
* (which is blocked until #snd_card_register function is called).
*/
snd_card_t *snd_card_new(int idx, const char *xid,
struct module *module, int extra_size)
{
......@@ -85,6 +103,8 @@ snd_card_t *snd_card_new(int idx, const char *xid,
rwlock_init(&card->control_owner_lock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
init_waitqueue_head(&card->shutdown_sleep);
#ifdef CONFIG_PM
init_MUTEX(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
......@@ -110,17 +130,123 @@ snd_card_t *snd_card_new(int idx, const char *xid,
return NULL;
}
static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
{
return POLLERR | POLLNVAL;
}
/**
* snd_card_disconnect: disconnect all APIs from the file-operations (user space)
* @card: soundcard structure
*
* Returns - zero, otherwise a negative error code.
*
* Note: The current implementation replaces all active file->f_op with special
* dummy file operations (they do nothing except release).
*/
int snd_card_disconnect(snd_card_t * card)
{
struct snd_monitor_file *mfile;
struct file *file;
struct snd_shutdown_f_ops *s_f_ops;
struct file_operations *f_ops, *old_f_ops;
int err;
write_lock(&card->files_lock);
if (card->shutdown) {
write_unlock(&card->files_lock);
return 0;
}
card->shutdown = 1;
write_unlock(&card->files_lock);
/* phase 1: disable fops (user space) operations for ALSA API */
write_lock(&snd_card_rwlock);
snd_cards[card->number] = NULL;
write_unlock(&snd_card_rwlock);
/* phase 2: replace file->f_op with special dummy operations */
spin_lock(&card->files_lock);
mfile = card->files;
while (mfile) {
file = mfile->file;
/* it's critical part, use endless loop */
/* we have no room to fail */
s_f_ops = kmalloc(sizeof(struct snd_shutdown_f_ops), GFP_ATOMIC);
if (s_f_ops == NULL)
panic("Atomic allocation failed for snd_shutdown_f_ops!");
f_ops = &s_f_ops->f_ops;
memset(f_ops, 0, sizeof(*f_ops));
f_ops->owner = file->f_op->owner;
f_ops->release = file->f_op->release;
f_ops->poll = snd_disconnect_poll;
s_f_ops->next = card->s_f_ops;
card->s_f_ops = s_f_ops;
f_ops = fops_get(f_ops);
old_f_ops = file->f_op;
file->f_op = f_ops; /* must be atomic */
fops_put(old_f_ops);
mfile = mfile->next;
}
spin_unlock(&card->files_lock);
/* phase 3: notify all connected devices about disconnection */
/* at this point, they cannot respond to any calls except release() */
snd_ctl_disconnect(card);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);
#endif
/* notify all devices that we are disconnected */
err = snd_device_disconnect_all(card);
if (err < 0)
snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
return 0;
}
/**
* snd_card_free: frees given soundcard structure
* @card: soundcard structure
*
* Returns - zero. Frees all associated devices and frees the control
* interface associated to given soundcard.
*/
int snd_card_free(snd_card_t * card)
{
wait_queue_t wait;
struct snd_shutdown_f_ops *s_f_ops;
if (card == NULL)
return -EINVAL;
write_lock(&snd_card_rwlock);
snd_cards[card->number] = NULL;
snd_cards_count--;
write_unlock(&snd_card_rwlock);
/* wait, until all devices are ready for the free operation */
init_waitqueue_entry(&wait, current);
add_wait_queue(&card->shutdown_sleep, &wait);
while (card->files) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(30 * HZ);
}
remove_wait_queue(&card->shutdown_sleep, &wait);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, 1);
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
#endif
if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
snd_printk(KERN_ERR "unable to free all devices (pre)\n");
......@@ -145,6 +271,11 @@ int snd_card_free(snd_card_t * card)
snd_printk(KERN_WARNING "unable to free card info\n");
/* Not fatal error */
}
while (card->s_f_ops) {
s_f_ops = card->s_f_ops;
card->s_f_ops = s_f_ops->next;
kfree(s_f_ops);
}
write_lock(&snd_card_rwlock);
snd_cards_lock &= ~(1 << card->number);
write_unlock(&snd_card_rwlock);
......@@ -152,7 +283,65 @@ int snd_card_free(snd_card_t * card)
return 0;
}
static void choose_default_id(snd_card_t *card)
static int snd_card_free_thread(void * __card)
{
snd_card_t *card = __card;
struct module * module;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
lock_kernel();
#endif
daemonize();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
reparent_to_init();
#endif
strcpy(current->comm, "snd-free");
if (!try_inc_mod_count(module = card->module)) {
snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
module = NULL;
}
wait_event(card->shutdown_sleep, card->files == NULL);
snd_card_free(card);
if (module)
__MOD_DEC_USE_COUNT(module);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
unlock_kernel();
#endif
return 0;
}
/**
* snd_card_free_in_thread: call snd_card_free() in thread
* @card: soundcard structure
*
* Returns - zero otherwise a negative error code if the start of thread failed.
*/
int snd_card_free_in_thread(snd_card_t * card)
{
int pid;
if (card->files == NULL) {
snd_card_free(card);
return 0;
}
pid = kernel_thread(snd_card_free_thread, card, 0);
if (pid >= 0)
return 0;
snd_printk(KERN_ERR "kernel_thread failed in snd_card_free_in_thread for card %i\n", card->number);
/* try to free the structure immediately */
snd_card_free(card);
return -EFAULT;
}
static void choose_default_id(snd_card_t * card)
{
int i, len, idx_flag = 0, loops = 8;
char *id, *spos;
......@@ -246,7 +435,7 @@ int snd_card_register(snd_card_t * card)
__skip_info:
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, 0);
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
#endif
return 0;
}
......@@ -312,7 +501,6 @@ int __init snd_card_info_init(void)
return -ENOMEM;
}
snd_card_info_entry = entry;
return 0;
}
......@@ -343,6 +531,56 @@ int snd_component_add(snd_card_t *card, const char *component)
return 0;
}
int snd_card_file_add(snd_card_t *card, struct file *file)
{
struct snd_monitor_file *mfile;
mfile = kmalloc(sizeof(*mfile), GFP_KERNEL);
if (mfile == NULL)
return -ENOMEM;
mfile->file = file;
mfile->next = NULL;
spin_lock(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
kfree(mfile);
return -ENODEV;
}
mfile->next = card->files;
card->files = mfile;
spin_unlock(&card->files_lock);
return 0;
}
int snd_card_file_remove(snd_card_t *card, struct file *file)
{
struct snd_monitor_file *mfile, *pfile = NULL;
spin_lock(&card->files_lock);
mfile = card->files;
while (mfile) {
if (mfile->file == file) {
if (pfile)
pfile->next = mfile->next;
else
card->files = mfile->next;
break;
}
pfile = mfile;
mfile = mfile->next;
}
spin_unlock(&card->files_lock);
if (card->files == NULL)
wake_up(&card->shutdown_sleep);
if (mfile) {
kfree(mfile);
} else {
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
return -ENOENT;
}
return 0;
}
#ifdef CONFIG_PM
/* the power lock must be active before call */
void snd_power_wait(snd_card_t *card)
......@@ -352,6 +590,7 @@ void snd_power_wait(snd_card_t *card)
init_waitqueue_entry(&wait, current);
add_wait_queue(&card->power_sleep, &wait);
snd_power_unlock(card);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(30 * HZ);
remove_wait_queue(&card->power_sleep, &wait);
snd_power_lock(card);
......
......@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <sound/core.h>
#include <sound/control.h>
......
......@@ -20,7 +20,6 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <asm/uaccess.h>
......
......@@ -20,7 +20,6 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <asm/uaccess.h>
......
......@@ -20,7 +20,6 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <asm/uaccess.h>
......
......@@ -45,14 +45,20 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
int cardnum = SNDRV_MINOR_OSS_CARD(minor(inode->i_rdev));
snd_card_t *card;
snd_mixer_oss_file_t *fmixer;
int err;
if ((card = snd_cards[cardnum]) == NULL)
return -ENODEV;
if (card->mixer_oss == NULL)
return -ENODEV;
err = snd_card_file_add(card, file);
if (err < 0)
return err;
fmixer = (snd_mixer_oss_file_t *)snd_kcalloc(sizeof(*fmixer), GFP_KERNEL);
if (fmixer == NULL)
if (fmixer == NULL) {
snd_card_file_remove(card, file);
return -ENOMEM;
}
fmixer->card = card;
fmixer->mixer = card->mixer_oss;
file->private_data = fmixer;
......@@ -64,6 +70,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
snd_card_file_remove(card, file);
return -EFAULT;
}
return 0;
......@@ -79,6 +86,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
snd_card_file_remove(fmixer->card, file);
kfree(fmixer);
}
return 0;
......@@ -765,7 +773,7 @@ static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, int *active_i
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &fmixer->mixer->slots[idx];
pslot = &mixer->slots[idx];
slot = (struct slot *)pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
......@@ -812,7 +820,7 @@ static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, int active_in
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &fmixer->mixer->slots[idx];
pslot = &mixer->slots[idx];
slot = (struct slot *)pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
......@@ -1200,10 +1208,11 @@ static int snd_mixer_oss_free1(void *private)
return 0;
}
static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd)
{
if (!free_flag) {
snd_mixer_oss_t *mixer;
snd_mixer_oss_t *mixer;
if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
char name[128];
int idx, err;
......@@ -1220,6 +1229,7 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
snd_magic_kfree(mixer);
return err;
}
mixer->oss_dev_alloc = 1;
mixer->card = card;
if (*card->mixername) {
strncpy(mixer->name, card->mixername, sizeof(mixer->name) - 1);
......@@ -1236,14 +1246,21 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
card->mixer_oss = mixer;
snd_mixer_oss_build(mixer);
snd_mixer_oss_proc_init(mixer);
} else {
snd_mixer_oss_t *mixer = card->mixer_oss;
} else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
mixer = card->mixer_oss;
if (mixer == NULL || !mixer->oss_dev_alloc)
return 0;
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
mixer->oss_dev_alloc = 0;
} else { /* free */
mixer = card->mixer_oss;
if (mixer == NULL)
return 0;
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
#endif
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
if (mixer->oss_dev_alloc)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
snd_mixer_oss_proc_done(mixer);
return snd_mixer_oss_free1(mixer);
}
......@@ -1257,7 +1274,7 @@ static int __init alsa_mixer_oss_init(void)
snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_cards[idx])
snd_mixer_oss_notify_handler(snd_cards[idx], 0);
snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
}
return 0;
}
......@@ -1269,7 +1286,7 @@ static void __exit alsa_mixer_oss_exit(void)
snd_mixer_oss_notify_callback = NULL;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_cards[idx])
snd_mixer_oss_notify_handler(snd_cards[idx], 1);
snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
}
}
......
......@@ -1554,13 +1554,16 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
err = -ENODEV;
goto __error1;
}
err = snd_card_file_add(pcm->card, file);
if (err < 0)
goto __error1;
if (!try_inc_mod_count(pcm->card->module)) {
err = -EFAULT;
goto __error1;
goto __error2;
}
if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
err = -EFAULT;
goto __error1;
goto __error;
}
if (file->f_mode & FMODE_WRITE)
psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
......@@ -1584,13 +1587,12 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
init_waitqueue_entry(&wait, current);
add_wait_queue(&pcm->open_wait, &wait);
down(&pcm->open_mutex);
while (1) {
down(&pcm->open_mutex);
err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
minor, psetup, csetup);
if (err >= 0)
break;
up(&pcm->open_mutex);
if (err == -EAGAIN) {
if (nonblock) {
err = -EBUSY;
......@@ -1599,7 +1601,9 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
} else
break;
set_current_state(TASK_INTERRUPTIBLE);
up(&pcm->open_mutex);
schedule();
down(&pcm->open_mutex);
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
......@@ -1607,13 +1611,15 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&pcm->open_wait, &wait);
up(&pcm->open_mutex);
if (err < 0)
goto __error;
up(&pcm->open_mutex);
return err;
__error:
dec_mod_count(pcm->card->module);
__error2:
snd_card_file_remove(pcm->card, file);
__error1:
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
......@@ -1639,6 +1645,7 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file)
up(&pcm->open_mutex);
wake_up(&pcm->open_wait);
dec_mod_count(pcm->card->module);
snd_card_file_remove(pcm->card, file);
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
......@@ -2108,7 +2115,7 @@ static snd_minor_t snd_pcm_oss_reg =
.f_ops = &snd_pcm_oss_f_reg,
};
static void register_oss_dsp(unsigned short native_minor, snd_pcm_t *pcm, int index)
static void register_oss_dsp(snd_pcm_t *pcm, int index)
{
char name[128];
sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
......@@ -2119,14 +2126,13 @@ static void register_oss_dsp(unsigned short native_minor, snd_pcm_t *pcm, int in
}
}
static int snd_pcm_oss_register_minor(unsigned short native_minor,
snd_pcm_t * pcm)
static int snd_pcm_oss_register_minor(snd_pcm_t * pcm)
{
pcm->oss.reg = 0;
if (dsp_map[pcm->card->number] == pcm->device) {
char name[128];
int duplex;
register_oss_dsp(native_minor, pcm, 0);
register_oss_dsp(pcm, 0);
duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 &&
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count &&
!(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX));
......@@ -2137,10 +2143,12 @@ static int snd_pcm_oss_register_minor(unsigned short native_minor,
name);
#endif
pcm->oss.reg++;
pcm->oss.reg_mask |= 1;
}
if (adsp_map[pcm->card->number] == pcm->device) {
register_oss_dsp(native_minor, pcm, 1);
register_oss_dsp(pcm, 1);
pcm->oss.reg++;
pcm->oss.reg_mask |= 2;
}
if (pcm->oss.reg)
......@@ -2149,20 +2157,32 @@ static int snd_pcm_oss_register_minor(unsigned short native_minor,
return 0;
}
static int snd_pcm_oss_unregister_minor(unsigned short native_minor,
snd_pcm_t * pcm)
static int snd_pcm_oss_disconnect_minor(snd_pcm_t * pcm)
{
if (pcm->oss.reg) {
if (dsp_map[pcm->card->number] == pcm->device) {
if (pcm->oss.reg_mask & 1) {
pcm->oss.reg_mask &= ~1;
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, 0);
}
if (pcm->oss.reg_mask & 2) {
pcm->oss.reg_mask &= ~2;
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, 1);
}
}
return 0;
}
static int snd_pcm_oss_unregister_minor(snd_pcm_t * pcm)
{
snd_pcm_oss_disconnect_minor(pcm);
if (pcm->oss.reg) {
if (dsp_map[pcm->card->number] == pcm->device) {
#ifdef SNDRV_OSS_INFO_DEV_AUDIO
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
#endif
}
if (adsp_map[pcm->card->number] == pcm->device)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, 1);
pcm->oss.reg = 0;
snd_pcm_oss_proc_done(pcm);
}
......@@ -2172,6 +2192,7 @@ static int snd_pcm_oss_unregister_minor(unsigned short native_minor,
static snd_pcm_notify_t snd_pcm_oss_notify =
{
.n_register = snd_pcm_oss_register_minor,
.n_disconnect = snd_pcm_oss_disconnect_minor,
.n_unregister = snd_pcm_oss_unregister_minor,
};
......@@ -2180,8 +2201,6 @@ static int __init alsa_pcm_oss_init(void)
int i;
int err;
if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
return err;
/* check device map table */
for (i = 0; i < SNDRV_CARDS; i++) {
if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
......@@ -2193,6 +2212,8 @@ static int __init alsa_pcm_oss_init(void)
adsp_map[i] = 1;
}
}
if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
return err;
return 0;
}
......
......@@ -37,9 +37,10 @@ snd_pcm_t *snd_pcm_devices[SNDRV_CARDS * SNDRV_PCM_DEVICES];
static LIST_HEAD(snd_pcm_notify_list);
static DECLARE_MUTEX(register_mutex);
int snd_pcm_free(snd_pcm_t *pcm);
static int snd_pcm_free(snd_pcm_t *pcm);
static int snd_pcm_dev_free(snd_device_t *device);
static int snd_pcm_dev_register(snd_device_t *device);
static int snd_pcm_dev_disconnect(snd_device_t *device);
static int snd_pcm_dev_unregister(snd_device_t *device);
void snd_pcm_lock(int xup)
......@@ -590,7 +591,7 @@ int snd_pcm_new_stream(snd_pcm_t *pcm, int stream, int substream_count)
}
int snd_pcm_new(snd_card_t * card, char *id, int device,
int playback_count, int capture_count,
int playback_count, int capture_count,
snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
......@@ -598,6 +599,7 @@ int snd_pcm_new(snd_card_t * card, char *id, int device,
static snd_device_ops_t ops = {
.dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
.dev_unregister = snd_pcm_dev_unregister
};
......@@ -653,7 +655,7 @@ static void snd_pcm_free_stream(snd_pcm_str_t * pstr)
#endif
}
int snd_pcm_free(snd_pcm_t *pcm)
static int snd_pcm_free(snd_pcm_t *pcm)
{
snd_assert(pcm != NULL, return -ENXIO);
if (pcm->private_free)
......@@ -664,7 +666,7 @@ int snd_pcm_free(snd_pcm_t *pcm)
return 0;
}
int snd_pcm_dev_free(snd_device_t *device)
static int snd_pcm_dev_free(snd_device_t *device)
{
snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO);
return snd_pcm_free(pcm);
......@@ -793,7 +795,7 @@ void snd_pcm_release_substream(snd_pcm_substream_t *substream)
substream->pstr->substream_opened--;
}
int snd_pcm_dev_register(snd_device_t *device)
static int snd_pcm_dev_register(snd_device_t *device)
{
int idx, cidx, err;
unsigned short minor;
......@@ -837,7 +839,25 @@ int snd_pcm_dev_register(snd_device_t *device)
list_for_each(list, &snd_pcm_notify_list) {
snd_pcm_notify_t *notify;
notify = list_entry(list, snd_pcm_notify_t, list);
notify->n_register(-1 /* idx + SNDRV_MINOR_PCM */, pcm);
notify->n_register(pcm);
}
snd_pcm_lock(1);
return 0;
}
static int snd_pcm_dev_disconnect(snd_device_t *device)
{
snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO);
struct list_head *list;
int idx;
snd_pcm_lock(0);
idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
snd_pcm_devices[idx] = NULL;
list_for_each(list, &snd_pcm_notify_list) {
snd_pcm_notify_t *notify;
notify = list_entry(list, snd_pcm_notify_t, list);
notify->n_disconnect(pcm);
}
snd_pcm_lock(1);
return 0;
......@@ -853,10 +873,7 @@ static int snd_pcm_dev_unregister(snd_device_t *device)
snd_assert(pcm != NULL, return -ENXIO);
snd_pcm_lock(0);
idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
if (snd_pcm_devices[idx] != pcm) {
snd_pcm_lock(1);
return -EINVAL;
}
snd_pcm_devices[idx] = NULL;
for (cidx = 0; cidx < 2; cidx++) {
devtype = -1;
switch (cidx) {
......@@ -874,9 +891,8 @@ static int snd_pcm_dev_unregister(snd_device_t *device)
list_for_each(list, &snd_pcm_notify_list) {
snd_pcm_notify_t *notify;
notify = list_entry(list, snd_pcm_notify_t, list);
notify->n_unregister(-1 /* SNDRV_MINOR_PCM + idx */, pcm);
notify->n_unregister(pcm);
}
snd_pcm_devices[idx] = NULL;
snd_pcm_lock(1);
return snd_pcm_free(pcm);
}
......@@ -892,16 +908,14 @@ int snd_pcm_notify(snd_pcm_notify_t *notify, int nfree)
for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
if (snd_pcm_devices[idx] == NULL)
continue;
notify->n_unregister(-1 /* idx + SNDRV_MINOR_PCM */,
snd_pcm_devices[idx]);
notify->n_unregister(snd_pcm_devices[idx]);
}
} else {
list_add_tail(&notify->list, &snd_pcm_notify_list);
for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
if (snd_pcm_devices[idx] == NULL)
continue;
notify->n_register(-1 /* idx + SNDRV_MINOR_PCM */,
snd_pcm_devices[idx]);
notify->n_register(snd_pcm_devices[idx]);
}
}
snd_pcm_lock(1);
......
......@@ -1796,9 +1796,12 @@ int snd_pcm_open(struct inode *inode, struct file *file)
err = -ENODEV;
goto __error1;
}
err = snd_card_file_add(pcm->card, file);
if (err < 0)
goto __error1;
if (!try_inc_mod_count(pcm->card->module)) {
err = -EFAULT;
goto __error1;
goto __error2;
}
init_waitqueue_entry(&wait, current);
add_wait_queue(&pcm->open_wait, &wait);
......@@ -1831,6 +1834,8 @@ int snd_pcm_open(struct inode *inode, struct file *file)
__error:
dec_mod_count(pcm->card->module);
__error2:
snd_card_file_remove(pcm->card, file);
__error1:
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
......@@ -1859,6 +1864,7 @@ int snd_pcm_release(struct inode *inode, struct file *file)
up(&pcm->open_mutex);
wake_up(&pcm->open_wait);
dec_mod_count(pcm->card->module);
snd_card_file_remove(pcm->card, file);
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
......
......@@ -51,6 +51,7 @@ MODULE_PARM_SYNTAX(amidi_map, "default:1,skill:advanced");
static int snd_rawmidi_free(snd_rawmidi_t *rawmidi);
static int snd_rawmidi_dev_free(snd_device_t *device);
static int snd_rawmidi_dev_register(snd_device_t *device);
static int snd_rawmidi_dev_disconnect(snd_device_t *device);
static int snd_rawmidi_dev_unregister(snd_device_t *device);
snd_rawmidi_t *snd_rawmidi_devices[SNDRV_CARDS * SNDRV_RAWMIDI_DEVICES];
......@@ -389,19 +390,24 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device];
if (rmidi == NULL)
return -ENODEV;
card = rmidi->card;
#ifdef CONFIG_SND_OSSEMUL
if (maj == SOUND_MAJOR && !rmidi->ossreg)
return -ENXIO;
#endif
fflags = snd_rawmidi_file_flags(file);
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */
card = rmidi->card;
err = snd_card_file_add(card, file);
if (err < 0)
return -ENODEV;
fflags = snd_rawmidi_file_flags(file);
if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */
fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
rawmidi_file = snd_magic_kmalloc(snd_rawmidi_file_t, 0, GFP_KERNEL);
if (rawmidi_file == NULL)
if (rawmidi_file == NULL) {
snd_card_file_remove(card, file);
return -ENOMEM;
}
init_waitqueue_entry(&wait, current);
add_wait_queue(&rmidi->open_wait, &wait);
while (1) {
......@@ -443,6 +449,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if (err >= 0) {
file->private_data = rawmidi_file;
} else {
snd_card_file_remove(card, file);
snd_magic_kfree(rawmidi_file);
}
return err;
......@@ -507,12 +514,15 @@ int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile)
static int snd_rawmidi_release(struct inode *inode, struct file *file)
{
snd_rawmidi_file_t *rfile;
snd_rawmidi_t *rmidi;
int err;
rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO);
err = snd_rawmidi_kernel_release(rfile);
wake_up(&rfile->rmidi->open_wait);
rmidi = rfile->rmidi;
wake_up(&rmidi->open_wait);
snd_magic_kfree(rfile);
snd_card_file_remove(rmidi->card, file);
return err;
}
......@@ -1318,6 +1328,7 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device,
static snd_device_ops_t ops = {
.dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect,
.dev_unregister = snd_rawmidi_dev_unregister
};
......@@ -1466,6 +1477,18 @@ static int snd_rawmidi_dev_register(snd_device_t *device)
return 0;
}
static int snd_rawmidi_dev_disconnect(snd_device_t *device)
{
snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO);
int idx;
down(&register_mutex);
idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
snd_rawmidi_devices[idx] = NULL;
up(&register_mutex);
return 0;
}
static int snd_rawmidi_dev_unregister(snd_device_t *device)
{
int idx;
......@@ -1474,10 +1497,7 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device)
snd_assert(rmidi != NULL, return -ENXIO);
down(&register_mutex);
idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
if (snd_rawmidi_devices[idx] != rmidi) {
up(&register_mutex);
return -EINVAL;
}
snd_rawmidi_devices[idx] = NULL;
if (rmidi->proc_entry) {
snd_info_unregister(rmidi->proc_entry);
rmidi->proc_entry = NULL;
......@@ -1498,7 +1518,6 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device)
if (rmidi->ops && rmidi->ops->dev_unregister)
rmidi->ops->dev_unregister(rmidi);
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
snd_rawmidi_devices[idx] = NULL;
up(&register_mutex);
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
if (rmidi->seq_dev) {
......
......@@ -29,51 +29,53 @@ endif
obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_SERIAL_U16550) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_MTPAV) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_MPU401) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ALS100) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_AZT2320) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_DT019X) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_ES18XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_OPL3SA2) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_AD1816A) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_CS4231) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_CS4232) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_CS4236) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_ES1688) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_GUSCLASSIC) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_GUSMAX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_GUSEXTREME) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_INTERWAVE) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_OPTI93X) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_SB8) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_SB16) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_SBAWE) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o snd-seq-virmidi.o
obj-$(CONFIG_SND_ES968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_ALS4000) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_CMIPCI) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_CS4281) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_ENS1370) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ENS1371) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ES1938) += snd-seq-device.o snd-seq-midi-emul.o snd-seq.o snd-seq-instr.o snd-seq-midi.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ES1968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_FM801) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_INTEL8X0) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_SONICVIBES) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_VIA82XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_CS46XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_EMU10K1) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-virmidi.o
obj-$(CONFIG_SND_TRIDENT) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_YMFPCI) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_USB_AUDIO) += snd-seq.o snd-seq-device.o snd-seq-midi-event.o
RAWMIDI_OBJS = snd-seq-midi.o snd-seq-midi-event.o
OPL3_OBJS = snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
obj-$(CONFIG_SND_SERIAL_U16550) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_MTPAV) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_MPU401) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_ALS100) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_AZT2320) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_DT019X) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ES18XX) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_OPL3SA2) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_AD1816A) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_CS4231) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_CS4232) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_CS4236) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ES1688) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_GUSCLASSIC) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_GUSMAX) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_GUSEXTREME) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_INTERWAVE) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_INTERWAVE_STB) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_OPTI92X_AD1848) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_OPTI92X_CS4231) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_OPTI93X) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_SB8) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_SB16) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_SBAWE) += $(RAWMIDI_OBJS) $(OPL3_OBJS) snd-seq-virmidi.o
obj-$(CONFIG_SND_ES968) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_WAVEFRONT) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ALS4000) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_CMIPCI) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_CS4281) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ENS1370) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_ENS1371) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_ES1938) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ES1968) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_FM801) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ICE1712) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_INTEL8X0) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_SONICVIBES) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_VIA82XX) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_ALI5451) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_CS46XX) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_EMU10K1) += $(RAWMIDI_OBJS) snd-seq-midi-emul.o snd-seq-virmidi.o
obj-$(CONFIG_SND_TRIDENT) += $(RAWMIDI_OBJS) snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_YMFPCI) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_USB_AUDIO) += $(RAWMIDI_OBJS)
obj-m := $(sort $(obj-m))
......
......@@ -92,6 +92,7 @@ static snd_info_entry_t *info_entry = NULL;
static int snd_seq_device_free(snd_seq_device_t *dev);
static int snd_seq_device_dev_free(snd_device_t *device);
static int snd_seq_device_dev_register(snd_device_t *device);
static int snd_seq_device_dev_disconnect(snd_device_t *device);
static int snd_seq_device_dev_unregister(snd_device_t *device);
static int init_device(snd_seq_device_t *dev, ops_list_t *ops);
......@@ -166,6 +167,7 @@ int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize,
static snd_device_ops_t dops = {
.dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect,
.dev_unregister = snd_seq_device_dev_unregister
};
......@@ -268,6 +270,22 @@ static int snd_seq_device_dev_register(snd_device_t *device)
return 0;
}
/*
* disconnect the device
*/
static int snd_seq_device_dev_disconnect(snd_device_t *device)
{
snd_seq_device_t *dev = snd_magic_cast(snd_seq_device_t, device->device_data, return -ENXIO);
ops_list_t *ops;
ops = find_driver(dev->id, 0);
if (ops == NULL)
return -ENOENT;
free_device(dev, ops);
return 0;
}
/*
* unregister the existing device
*/
......
......@@ -76,8 +76,12 @@ static devfs_handle_t devfs_handle = NULL;
void snd_request_card(int card)
{
char str[32];
int locked;
if (snd_cards[card] != NULL)
read_lock(&snd_card_rwlock);
locked = snd_cards_lock & (1 << card);
read_unlock(&snd_card_rwlock);
if (locked)
return;
if (card < 0 || card >= snd_ecards_limit)
return;
......@@ -423,9 +427,13 @@ EXPORT_SYMBOL(snd_cards);
EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
#endif
EXPORT_SYMBOL(snd_card_new);
EXPORT_SYMBOL(snd_card_disconnect);
EXPORT_SYMBOL(snd_card_free);
EXPORT_SYMBOL(snd_card_free_in_thread);
EXPORT_SYMBOL(snd_card_register);
EXPORT_SYMBOL(snd_component_add);
EXPORT_SYMBOL(snd_card_file_add);
EXPORT_SYMBOL(snd_card_file_remove);
#ifdef CONFIG_PM
EXPORT_SYMBOL(snd_power_wait);
#endif
......
......@@ -13,58 +13,37 @@ snd-opl3-synth-objs += opl3_oss.o
endif
endif
# Toplevel Module Dependency
obj-$(CONFIG_SND_ALS100) += snd-opl3-lib.o
obj-$(CONFIG_SND_AZT2320) += snd-opl3-lib.o
obj-$(CONFIG_SND_DT019X) += snd-opl3-lib.o
obj-$(CONFIG_SND_ES18XX) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3-lib.o
obj-$(CONFIG_SND_AD1816A) += snd-opl3-lib.o
obj-$(CONFIG_SND_CS4232) += snd-opl3-lib.o
obj-$(CONFIG_SND_CS4236) += snd-opl3-lib.o
obj-$(CONFIG_SND_ES1688) += snd-opl3-lib.o
obj-$(CONFIG_SND_GUSEXTREME) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI93X) += snd-opl3-lib.o
obj-$(CONFIG_SND_SB8) += snd-opl3-lib.o
obj-$(CONFIG_SND_SB16) += snd-opl3-lib.o
obj-$(CONFIG_SND_SBAWE) += snd-opl3-lib.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-lib.o
obj-$(CONFIG_SND_ALS4000) += snd-opl3-lib.o
obj-$(CONFIG_SND_CMIPCI) += snd-opl3-lib.o
obj-$(CONFIG_SND_CS4281) += snd-opl3-lib.o
obj-$(CONFIG_SND_ES1938) += snd-opl3-lib.o
obj-$(CONFIG_SND_FM801) += snd-opl3-lib.o
obj-$(CONFIG_SND_SONICVIBES) += snd-opl3-lib.o
obj-$(CONFIG_SND_YMFPCI) += snd-opl3-lib.o
OPL3_OBJS = snd-opl3-lib.o
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_ALS100) += snd-opl3-synth.o
obj-$(CONFIG_SND_AZT2320) += snd-opl3-synth.o
obj-$(CONFIG_SND_DT019X) += snd-opl3-synth.o
obj-$(CONFIG_SND_ES18XX) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3-synth.o
obj-$(CONFIG_SND_AD1816A) += snd-opl3-synth.o
obj-$(CONFIG_SND_CS4232) += snd-opl3-synth.o
obj-$(CONFIG_SND_CS4236) += snd-opl3-synth.o
obj-$(CONFIG_SND_ES1688) += snd-opl3-synth.o
obj-$(CONFIG_SND_GUSEXTREME) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPTI93X) += snd-opl3-synth.o
obj-$(CONFIG_SND_SB8) += snd-opl3-synth.o
obj-$(CONFIG_SND_SB16) += snd-opl3-synth.o
obj-$(CONFIG_SND_SBAWE) += snd-opl3-synth.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-synth.o
obj-$(CONFIG_SND_ALS4000) += snd-opl3-synth.o
obj-$(CONFIG_SND_CMIPCI) += snd-opl3-synth.o
obj-$(CONFIG_SND_CS4281) += snd-opl3-synth.o
obj-$(CONFIG_SND_ES1938) += snd-opl3-synth.o
obj-$(CONFIG_SND_FM801) += snd-opl3-synth.o
obj-$(CONFIG_SND_SONICVIBES) += snd-opl3-synth.o
obj-$(CONFIG_SND_YMFPCI) += snd-opl3-synth.o
OPL3_OBJS += snd-opl3-synth.o
endif
# Toplevel Module Dependency
obj-$(CONFIG_SND_ALS100) += $(OPL3_OBJS)
obj-$(CONFIG_SND_AZT2320) += $(OPL3_OBJS)
obj-$(CONFIG_SND_DT019X) += $(OPL3_OBJS)
obj-$(CONFIG_SND_ES18XX) += $(OPL3_OBJS)
obj-$(CONFIG_SND_OPL3SA2) += $(OPL3_OBJS)
obj-$(CONFIG_SND_AD1816A) += $(OPL3_OBJS)
obj-$(CONFIG_SND_CS4232) += $(OPL3_OBJS)
obj-$(CONFIG_SND_CS4236) += $(OPL3_OBJS)
obj-$(CONFIG_SND_ES1688) += $(OPL3_OBJS)
obj-$(CONFIG_SND_GUSEXTREME) += $(OPL3_OBJS)
obj-$(CONFIG_SND_OPTI92X_AD1848) += $(OPL3_OBJS)
obj-$(CONFIG_SND_OPTI92X_CS4231) += $(OPL3_OBJS)
obj-$(CONFIG_SND_OPTI93X) += $(OPL3_OBJS)
obj-$(CONFIG_SND_SB8) += $(OPL3_OBJS)
obj-$(CONFIG_SND_SB16) += $(OPL3_OBJS)
obj-$(CONFIG_SND_SBAWE) += $(OPL3_OBJS)
obj-$(CONFIG_SND_WAVEFRONT) += $(OPL3_OBJS)
obj-$(CONFIG_SND_ALS4000) += $(OPL3_OBJS)
obj-$(CONFIG_SND_CMIPCI) += $(OPL3_OBJS)
obj-$(CONFIG_SND_CS4281) += $(OPL3_OBJS)
obj-$(CONFIG_SND_ES1938) += $(OPL3_OBJS)
obj-$(CONFIG_SND_FM801) += $(OPL3_OBJS)
obj-$(CONFIG_SND_SONICVIBES) += $(OPL3_OBJS)
obj-$(CONFIG_SND_YMFPCI) += $(OPL3_OBJS)
obj-m := $(sort $(obj-m))
include $(TOPDIR)/Rules.make
......@@ -263,6 +263,8 @@ static struct isapnp_card_id snd_card_pnpids[] __devinitdata = {
ISAPNP_CS4232('C','S','C',0xd937,0x0000,0x0010,0x0003),
/* CS4235 without MPU401 */
ISAPNP_CS4232_WOMPU('C','S','C',0xe825,0x0100,0x0110),
/* IBM IntelliStation M Pro 6898 11U - CS4236B */
ISAPNP_CS4232_WOMPU('C','S','C',0xe835,0x0000,0x0010),
/* Some noname CS4236 based card */
ISAPNP_CS4232('C','S','C',0xe936,0x0000,0x0010,0x0003),
/* CS4236B */
......@@ -609,12 +611,10 @@ module_exit(alsa_card_cs423x_exit)
/* format is: snd-cs4232=enable,index,id,isapnp,port,
cport,mpu_port,fm_port,sb_port,
irq,mpu_irq,dma1,dma1_size,
dma2,dma2_size */
irq,mpu_irq,dma1,dma2 */
/* format is: snd-cs4236=enable,index,id,isapnp,port,
cport,mpu_port,fm_port,sb_port,
irq,mpu_irq,dma1,dma1_size,
dma2,dma2_size */
irq,mpu_irq,dma1,dma2 */
static int __init alsa_card_cs423x_setup(char *str)
{
......
......@@ -182,6 +182,8 @@ static struct isapnp_card_id snd_sb16_pnpids[] __devinitdata = {
/* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0024,0x0031),
/* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0025,0x0031),
/* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0026,0x0031),
/* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0027,0x0031),
......
This diff is collapsed.
......@@ -43,4 +43,6 @@
#define AC97_ID_CS4299 0x43525930
#define AC97_ID_CS4201 0x43525948
#define AC97_ID_CS4205 0x43525958
#define AC97_ID_CS_MASK 0xfffffff8 /* bit 0-2: rev */
#define AC97_ID_ALC650 0x414c4720
#define AC97_ID_YMF753 0x594d4803
......@@ -37,6 +37,20 @@
* Chip specific initialization
*/
int patch_yamaha_ymf753(ac97_t * ac97)
{
/* Patch for Yamaha YMF753, Copyright (c) by David Shust, dshust@shustring.com.
This chip has nonstandard and extended behaviour with regard to its S/PDIF output.
The AC'97 spec states that the S/PDIF signal is to be output at pin 48.
The YMF753 will ouput the S/PDIF signal to pin 43, 47 (EAPD), or 48.
By default, no output pin is selected, and the S/PDIF signal is not output.
There is also a bit to mute S/PDIF output in a vendor-specific register.
*/
ac97->caps |= AC97_BC_BASS_TREBLE;
ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */
return 0;
}
int patch_wolfson00(ac97_t * ac97)
{
/* This sequence is suspect because it was designed for
......
......@@ -22,6 +22,7 @@
*
*/
int patch_yamaha_ymf753(ac97_t * ac97);
int patch_wolfson00(ac97_t * ac97);
int patch_wolfson03(ac97_t * ac97);
int patch_wolfson04(ac97_t * ac97);
......
......@@ -529,7 +529,8 @@ static int snd_ali_reset_5451(ali_t *codec)
udelay(5000);
}
return -1;
snd_printk(KERN_WARNING "ali5451: reset time out\n");
return 0;
}
#ifdef CODEC_RESET
......@@ -1999,14 +2000,10 @@ static int snd_ali_chip_init(ali_t *codec)
if (codec->revision == ALI_5451_V02) {
pci_dev = codec->pci_m1533;
if (pci_dev == NULL)
return -1;
pci_read_config_byte(pci_dev, 0x59, &temp);
pci_dev = pci_find_device(0x10b9,0x7101, pci_dev);
if (pci_dev == NULL)
return -1;
pci_read_config_byte(pci_dev,0xb8,&temp);
pci_dev = codec->pci_m7101;
pci_read_config_byte(pci_dev, 0xb8, &temp);
temp |= 1 << 6;
pci_write_config_byte(pci_dev, 0xB8, temp);
}
......@@ -2139,10 +2136,22 @@ static int __devinit snd_ali_create(snd_card_t * card,
codec->chregs.data.aint = 0x00;
codec->chregs.data.ainten = 0x00;
pci_dev = pci_find_device(0x10b9,0x1533, pci_dev);
/* M1533: southbridge */
pci_dev = pci_find_device(0x10b9, 0x1533, NULL);
codec->pci_m1533 = pci_dev;
pci_dev = pci_find_device(0x10b9,0x7101, pci_dev);
if (! codec->pci_m1533) {
snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.\n");
snd_ali_free(codec);
return -ENODEV;
}
/* M7101: power management */
pci_dev = pci_find_device(0x10b9, 0x7101, NULL);
codec->pci_m7101 = pci_dev;
if (! codec->pci_m7101) {
snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n");
snd_ali_free(codec);
return -ENODEV;
}
snd_ali_printk("snd_device_new is called.\n");
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) {
......
......@@ -1804,7 +1804,7 @@ static int snd_cs4281_midi_output_open(snd_rawmidi_substream_t * substream)
spin_lock_irqsave(&chip->reg_lock, flags);
chip->uartm |= CS4281_MODE_OUTPUT;
chip->midcr |= BA0_MIDCR_TXE;
chip->midi_input = substream;
chip->midi_output = substream;
if (!(chip->uartm & CS4281_MODE_INPUT)) {
snd_cs4281_midi_reset(chip);
} else {
......
......@@ -81,7 +81,7 @@ void snd_ice1712_ak4524_write(ice1712_t *ice, int chip,
udelay(1);
}
if (ak->type == SND_AK4524) {
if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0)
ak->images[chip][addr] = data;
else
......
......@@ -189,19 +189,18 @@ static void delta_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucont
static int delta_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{
unsigned long flags;
unsigned int val;
int change;
val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958);
spin_lock_irqsave(&ice->reg_lock, flags);
spin_lock_irq(&ice->reg_lock);
change = ice->spdif.cs8403_bits != val;
ice->spdif.cs8403_bits = val;
if (change && ice->playback_pro_substream == NULL) {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
snd_ice1712_delta_cs8403_spdif_write(ice, val);
} else {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
}
return change;
}
......@@ -213,19 +212,18 @@ static void delta_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontr
static int delta_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{
unsigned long flags;
unsigned int val;
int change;
val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958);
spin_lock_irqsave(&ice->reg_lock, flags);
spin_lock_irq(&ice->reg_lock);
change = ice->spdif.cs8403_stream_bits != val;
ice->spdif.cs8403_stream_bits = val;
if (change && ice->playback_pro_substream != NULL) {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
snd_ice1712_delta_cs8403_spdif_write(ice, val);
} else {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
}
return change;
}
......
......@@ -245,19 +245,18 @@ static void ews88_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucont
static int ews88_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{
unsigned long flags;
unsigned int val;
int change;
val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
spin_lock_irqsave(&ice->reg_lock, flags);
spin_lock_irq(&ice->reg_lock);
change = ice->spdif.cs8403_bits != val;
ice->spdif.cs8403_bits = val;
if (change && ice->playback_pro_substream == NULL) {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
snd_ice1712_ews_cs8404_spdif_write(ice, val);
} else {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
}
return change;
}
......@@ -269,19 +268,18 @@ static void ews88_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontr
static int ews88_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{
unsigned long flags;
unsigned int val;
int change;
val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
spin_lock_irqsave(&ice->reg_lock, flags);
spin_lock_irq(&ice->reg_lock);
change = ice->spdif.cs8403_stream_bits != val;
ice->spdif.cs8403_stream_bits = val;
if (change && ice->playback_pro_substream != NULL) {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
snd_ice1712_ews_cs8404_spdif_write(ice, val);
} else {
spin_unlock_irqrestore(&ice->reg_lock, flags);
spin_unlock_irq(&ice->reg_lock);
}
return change;
}
......
This diff is collapsed.
......@@ -2,6 +2,7 @@
* ALSA driver for RME Hammerfall DSP audio interface(s)
*
* Copyright (c) 2002 Paul Davis
* Marcus Andersson
*
* 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
......@@ -81,7 +82,7 @@ typedef enum {
#define DIGIFACE_SS_CHANNELS 26
#define DIGIFACE_DS_CHANNELS 14
#define MULTIFACE_SS_CHANNELS 18
#define MULTIFACE_DS_CHANNELS 10
#define MULTIFACE_DS_CHANNELS 14
/* Write registers. These are defined as byte-offsets from the iobase value.
*/
......@@ -687,6 +688,7 @@ static int hdsp_set_rate(hdsp_t *hdsp, int rate)
rate = HDSP_Frequency96KHz;
break;
default:
spin_unlock_irq(&hdsp->lock);
return -EINVAL;
}
......@@ -747,10 +749,12 @@ static void hdsp_set_thru(hdsp_t *hdsp, int channel, int enable)
mapped_channel = hdsp->channel_map[channel];
snd_assert(mapped_channel > -1, return);
if (enable) {
hdsp_write_gain (hdsp, INPUT_TO_OUTPUT_KEY(channel,channel), UNITY_GAIN);
hdsp_write_gain (hdsp, INPUT_TO_OUTPUT_KEY(mapped_channel,mapped_channel), UNITY_GAIN);
} else {
hdsp_write_gain (hdsp, INPUT_TO_OUTPUT_KEY(channel,channel), MINUS_INFINITY_GAIN);
hdsp_write_gain (hdsp, INPUT_TO_OUTPUT_KEY(mapped_channel,mapped_channel), MINUS_INFINITY_GAIN);
}
}
}
......@@ -1605,10 +1609,18 @@ static int snd_hdsp_get_playback_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol);
unsigned long flags;
int addr;
int chn;
int channel;
int mapped_channel;
channel = ucontrol->id.index - 1;
snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return -EINVAL);
if ((mapped_channel = hdsp->channel_map[channel]) < 0) {
return -EINVAL;
}
chn = ucontrol->id.index - 1;
addr = PLAYBACK_TO_OUTPUT_KEY(chn, chn);
addr = PLAYBACK_TO_OUTPUT_KEY(mapped_channel, mapped_channel);
spin_lock_irqsave(&hdsp->lock, flags);
ucontrol->value.integer.value[0] = hdsp_read_gain (hdsp, addr);
......@@ -1622,14 +1634,22 @@ static int snd_hdsp_put_playback_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
unsigned long flags;
int change;
int addr;
int chn;
int channel;
int mapped_channel;
int gain;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
chn = ucontrol->id.index - 1;
addr = PLAYBACK_TO_OUTPUT_KEY(chn, chn);
channel = ucontrol->id.index - 1;
snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return -EINVAL);
if ((mapped_channel = hdsp->channel_map[channel]) < 0) {
return -EINVAL;
}
addr = PLAYBACK_TO_OUTPUT_KEY(mapped_channel, mapped_channel);
gain = ucontrol->value.integer.value[0];
......@@ -2434,15 +2454,15 @@ static int snd_hdsp_channel_info(snd_pcm_substream_t *substream,
snd_pcm_channel_info_t *info)
{
hdsp_t *hdsp = _snd_pcm_substream_chip(substream);
int chn;
int mapped_channel;
snd_assert(info->channel < HDSP_MAX_CHANNELS, return -EINVAL);
if ((chn = hdsp->channel_map[info->channel]) < 0) {
if ((mapped_channel = hdsp->channel_map[info->channel]) < 0) {
return -EINVAL;
}
info->offset = chn * HDSP_CHANNEL_BUFFER_BYTES;
info->offset = mapped_channel * HDSP_CHANNEL_BUFFER_BYTES;
info->first = 0;
info->step = 32;
return 0;
......@@ -2567,7 +2587,7 @@ static snd_pcm_hardware_t snd_hdsp_playback_subinfo =
SNDRV_PCM_RATE_96000),
.rate_min = 32000,
.rate_max = 96000,
.channels_min = 10,
.channels_min = 14,
.channels_max = HDSP_MAX_CHANNELS,
.buffer_bytes_max = 1024*1024,
.period_bytes_min = 1,
......@@ -2592,7 +2612,7 @@ static snd_pcm_hardware_t snd_hdsp_capture_subinfo =
SNDRV_PCM_RATE_96000),
.rate_min = 32000,
.rate_max = 96000,
.channels_min = 10,
.channels_min = 14,
.channels_max = HDSP_MAX_CHANNELS,
.buffer_bytes_max = 1024*1024,
.period_bytes_min = 1,
......@@ -2902,11 +2922,15 @@ static int __devinit snd_hdsp_initialize_firmware (hdsp_t *hdsp)
}
}
if (hdsp_fifo_wait (hdsp, 3, HDSP_LONG_WAIT)) {
if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
snd_printk ("timeout at end of firmware loading\n");
return -EIO;
}
hdsp_write (hdsp, HDSP_jtagReg, 0);
snd_printk ("finished firmware loading\n");
mdelay(3000);
} else {
/* firmware already loaded, but we need to know what type
......
......@@ -613,6 +613,9 @@ static int snd_via82xx_playback_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_PCM_SURR_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
if (chip->chip_type == TYPE_VIA8233 &&
chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
unsigned int tmp;
......
......@@ -1181,7 +1181,6 @@ static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction,
runtime->private_data = subs;
subs->pcm_substream = substream;
setup_hw_info(runtime, subs);
return 0;
}
......@@ -1189,6 +1188,7 @@ static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction)
{
snd_usb_stream_t *as = snd_pcm_substream_chip(substream);
snd_usb_substream_t *subs = &as->substream[direction];
release_substream_urbs(subs);
if (subs->interface >= 0)
usb_set_interface(subs->dev, subs->interface, 0);
......@@ -2171,6 +2171,10 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
for (i = 0; i < SNDRV_CARDS; i++) {
if (usb_chip[i] && usb_chip[i]->dev == dev) {
chip = usb_chip[i];
if (chip->shutdown) {
snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n");
goto __error;
}
break;
}
}
......@@ -2247,14 +2251,41 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
{
snd_usb_audio_t *chip;
snd_card_t *card;
struct list_head *p;
snd_usb_stream_t *as;
snd_usb_substream_t *subs;
int idx;
if (ptr == (void *)-1)
return;
chip = snd_magic_cast(snd_usb_audio_t, ptr, return);
card = chip->card;
down(&register_mutex);
chip->shutdown = 1;
chip->num_interfaces--;
if (chip->num_interfaces <= 0)
snd_card_free(chip->card);
snd_card_disconnect(card);
list_for_each(p, &chip->pcm_list) {
as = list_entry(p, snd_usb_stream_t, list);
for (idx = 0; idx < 2; idx++) {
subs = &as->substream[idx];
if (!subs->num_formats)
continue;
release_substream_urbs(subs);
if (subs->interface >= 0) {
usb_set_interface(subs->dev, subs->interface, 0);
subs->interface = -1;
}
}
}
if (chip->num_interfaces <= 0) {
up(&register_mutex);
snd_card_free_in_thread(card);
} else {
up(&register_mutex);
}
}
......@@ -2317,7 +2348,7 @@ module_exit(snd_usb_audio_cleanup);
#ifndef MODULE
/*
* format is snd-usb-audio=enable,index,id
* format is snd-usb-audio=enable,index,id,vid,pid
*/
static int __init snd_usb_audio_module_setup(char* str)
{
......@@ -2327,7 +2358,9 @@ static int __init snd_usb_audio_module_setup(char* str)
return 0;
(void)(get_option(&str, &enable[nr_dev]) == 2 &&
get_option(&str, &index[nr_dev]) == 2 &&
get_id(&str, &id[nr_dev]) == 2);
get_id(&str, &id[nr_dev]) == 2 &&
get_option(&str, &vid[nr_dev]) == 2 &&
get_option(&str, &pid[nr_dev]) == 2);
++nr_dev;
return 1;
}
......
......@@ -133,6 +133,7 @@ struct snd_usb_audio {
int index;
struct usb_device *dev;
snd_card_t *card;
int shutdown;
int num_interfaces;
struct list_head pcm_list; /* list of pcm streams */
......
......@@ -65,6 +65,8 @@ struct usb_mixer_build {
unsigned char *buffer;
unsigned int buflen;
unsigned int ctrlif;
unsigned short vendor;
unsigned short product;
DECLARE_BITMAP(unitbitmap, 32*32);
usb_audio_term_t oterm;
const struct usbmix_name_map *map;
......@@ -78,8 +80,9 @@ struct usb_mixer_elem_info {
unsigned int cmask; /* channel mask bitmap: 0 = master */
int channels;
int val_type;
int min, max;
unsigned int initialized: 1;
int min, max, res;
unsigned int initialized: 1,
hack_hole1: 1; /* -256 value is missing */
};
......@@ -253,15 +256,16 @@ static int get_relative_value(usb_mixer_elem_info_t *cval, int val)
if (val < cval->min)
return 0;
else if (val > cval->max)
return cval->max - cval->min;
return (cval->max - cval->min) / cval->res;
else
return val - cval->min;
return (val - cval->min) / cval->res;
}
static int get_abs_value(usb_mixer_elem_info_t *cval, int val)
{
if (val < 0)
return cval->min;
val *= cval->res;
val += cval->min;
if (val > cval->max)
return cval->max;
......@@ -562,6 +566,7 @@ static int get_min_max(usb_mixer_elem_info_t *cval)
/* for failsafe */
cval->min = 0;
cval->max = 1;
cval->res = 1;
if (cval->val_type == USB_MIXER_BOOLEAN ||
cval->val_type == USB_MIXER_INV_BOOLEAN) {
......@@ -581,6 +586,21 @@ static int get_min_max(usb_mixer_elem_info_t *cval)
snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id);
return -EINVAL;
}
if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
cval->res = 1;
} else {
int last_valid_res = cval->res;
while (cval->res > 1) {
if (set_ctl_value(cval, SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0)
break;
cval->res /= 2;
}
if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0)
cval->res = last_valid_res;
}
if (cval->res == 0)
cval->res = 1;
cval->initialized = 1;
}
return 0;
......@@ -606,7 +626,7 @@ static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t
if (! cval->initialized)
get_min_max(cval);
uinfo->value.integer.min = 0;
uinfo->value.integer.max = cval->max - cval->min;
uinfo->value.integer.max = (cval->max - cval->min) / cval->res;
}
return 0;
}
......@@ -680,6 +700,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
set_cur_mix_value(cval, c + 1, val);
changed = 1;
}
get_cur_mix_value(cval, c + 1, &val);
cnt++;
}
}
......@@ -812,8 +833,19 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
break;
}
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
/* quirk for UDA1321/N101 */
/* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */
/* is not very clear from datasheets */
/* I hope that the min value is -15360 for newer firmware --jk */
if (((state->vendor == 0x471 && (state->product == 0x104 || state->product == 0x105 || state->product == 0x101)) ||
(state->vendor == 0x672 && state->product == 0x1041)) && !strcmp(kctl->id.name, "PCM Playback Volume") &&
cval->min == -15616) {
snd_printk("USB Audio: using volume control quirk for the UDA1321/N101 chip\n");
cval->max = -256;
}
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
add_control_to_empty(state->chip->card, kctl);
}
......@@ -1430,6 +1462,8 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffe
state.buffer = buffer;
state.buflen = buflen;
state.ctrlif = ctrlif;
state.vendor = dev->idVendor;
state.product = dev->idProduct;
/* check the mapping table */
for (map = usbmix_ctl_maps; map->vendor; map++) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment