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); ...@@ -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); 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_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_unregister(snd_card_t *card);
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn); int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn); int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
......
...@@ -58,8 +58,9 @@ typedef enum { ...@@ -58,8 +58,9 @@ typedef enum {
} snd_device_type_t; } snd_device_type_t;
typedef enum { typedef enum {
SNDRV_DEV_BUILD = 0, SNDRV_DEV_BUILD,
SNDRV_DEV_REGISTERED = 1 SNDRV_DEV_REGISTERED,
SNDRV_DEV_DISCONNECTED
} snd_device_state_t; } snd_device_state_t;
typedef enum { typedef enum {
...@@ -73,11 +74,13 @@ typedef struct _snd_device snd_device_t; ...@@ -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_free_t)(snd_device_t *device);
typedef int (snd_dev_register_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 int (snd_dev_unregister_t)(snd_device_t *device);
typedef struct { typedef struct {
snd_dev_free_t *dev_free; snd_dev_free_t *dev_free;
snd_dev_register_t *dev_register; snd_dev_register_t *dev_register;
snd_dev_disconnect_t *dev_disconnect;
snd_dev_unregister_t *dev_unregister; snd_dev_unregister_t *dev_unregister;
} snd_device_ops_t; } snd_device_ops_t;
...@@ -109,6 +112,15 @@ typedef struct _snd_hwdep snd_hwdep_t; ...@@ -109,6 +112,15 @@ typedef struct _snd_hwdep snd_hwdep_t;
typedef struct _snd_oss_mixer snd_mixer_oss_t; typedef struct _snd_oss_mixer snd_mixer_oss_t;
#endif #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 */ /* main structure for soundcard */
struct _snd_card { struct _snd_card {
...@@ -139,6 +151,12 @@ struct _snd_card { ...@@ -139,6 +151,12 @@ struct _snd_card {
snd_info_entry_t *proc_id; /* the card id */ snd_info_entry_t *proc_id; /* the card id */
struct proc_dir_entry *proc_root_link; /* number link to real 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 #ifdef CONFIG_PM
int (*set_power_state) (snd_card_t *card, unsigned int state); int (*set_power_state) (snd_card_t *card, unsigned int state);
void *power_state_private_data; void *power_state_private_data;
...@@ -285,19 +303,27 @@ int copy_from_user_toio(unsigned long dst, const void *src, size_t count); ...@@ -285,19 +303,27 @@ int copy_from_user_toio(unsigned long dst, const void *src, size_t count);
/* init.c */ /* init.c */
extern int snd_cards_count; extern int snd_cards_count;
extern unsigned int snd_cards_lock;
extern snd_card_t *snd_cards[SNDRV_CARDS]; extern snd_card_t *snd_cards[SNDRV_CARDS];
extern rwlock_t snd_card_rwlock; extern rwlock_t snd_card_rwlock;
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) #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 #endif
snd_card_t *snd_card_new(int idx, const char *id, snd_card_t *snd_card_new(int idx, const char *id,
struct module *module, int extra_size); 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(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_register(snd_card_t *card);
int snd_card_info_init(void); int snd_card_info_init(void);
int snd_card_info_done(void); int snd_card_info_done(void);
int snd_component_add(snd_card_t *card, const char *component); 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 */ /* device.c */
...@@ -305,6 +331,8 @@ int snd_device_new(snd_card_t *card, snd_device_type_t type, ...@@ -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); void *device_data, snd_device_ops_t *ops);
int snd_device_register(snd_card_t *card, void *device_data); int snd_device_register(snd_card_t *card, void *device_data);
int snd_device_register_all(snd_card_t *card); 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(snd_card_t *card, void *device_data);
int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd); int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd);
......
...@@ -156,12 +156,11 @@ static int __init get_id(char **str, char **dst) ...@@ -156,12 +156,11 @@ static int __init get_id(char **str, char **dst)
for (s = *str; isalpha(*s) || isdigit(*s) || *s == '_'; s++); for (s = *str; isalpha(*s) || isdigit(*s) || *s == '_'; s++);
if (s != *str) { if (s != *str) {
*dst = (char *)kmalloc(s - *str, GFP_KERNEL); *dst = (char *)kmalloc(s - *str, GFP_KERNEL);
if ((d = *dst) != NULL) { s = *str; d = *dst;
s = *str;
while (isalpha(*s) || isdigit(*s) || *s == '_') while (isalpha(*s) || isdigit(*s) || *s == '_')
if (d != NULL)
*d++ = *s++; *d++ = *s++;
} }
}
*str = s; *str = s;
if (*s == ',') { if (*s == ',') {
(*str)++; (*str)++;
......
...@@ -61,6 +61,7 @@ struct _snd_oss_mixer { ...@@ -61,6 +61,7 @@ struct _snd_oss_mixer {
void (*private_free_recsrc)(snd_mixer_oss_t *mixer); void (*private_free_recsrc)(snd_mixer_oss_t *mixer);
struct semaphore reg_mutex; struct semaphore reg_mutex;
snd_info_entry_t *proc_entry; snd_info_entry_t *proc_entry;
int oss_dev_alloc;
/* --- */ /* --- */
int oss_recsrc; int oss_recsrc;
}; };
......
...@@ -443,8 +443,9 @@ struct _snd_pcm { ...@@ -443,8 +443,9 @@ struct _snd_pcm {
}; };
typedef struct _snd_pcm_notify { typedef struct _snd_pcm_notify {
int (*n_register) (unsigned short minor, snd_pcm_t * pcm); int (*n_register) (snd_pcm_t * pcm);
int (*n_unregister) (unsigned short minor, snd_pcm_t * pcm); int (*n_disconnect) (snd_pcm_t * pcm);
int (*n_unregister) (snd_pcm_t * pcm);
struct list_head list; struct list_head list;
} snd_pcm_notify_t; } snd_pcm_notify_t;
......
...@@ -77,6 +77,7 @@ typedef struct _snd_pcm_oss_stream { ...@@ -77,6 +77,7 @@ typedef struct _snd_pcm_oss_stream {
typedef struct _snd_pcm_oss { typedef struct _snd_pcm_oss {
int reg; int reg;
unsigned int reg_mask;
} snd_pcm_oss_t; } snd_pcm_oss_t;
#endif /* __SOUND_PCM_OSS_H */ #endif /* __SOUND_PCM_OSS_H */
...@@ -62,9 +62,14 @@ static int snd_ctl_open(struct inode *inode, struct file *file) ...@@ -62,9 +62,14 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
err = -ENODEV; err = -ENODEV;
goto __error1; goto __error1;
} }
err = snd_card_file_add(card, file);
if (err < 0) {
err = -ENODEV;
goto __error1;
}
if (!try_inc_mod_count(card->module)) { if (!try_inc_mod_count(card->module)) {
err = -EFAULT; err = -EFAULT;
goto __error1; goto __error2;
} }
ctl = snd_magic_kcalloc(snd_ctl_file_t, 0, GFP_KERNEL); ctl = snd_magic_kcalloc(snd_ctl_file_t, 0, GFP_KERNEL);
if (ctl == NULL) { if (ctl == NULL) {
...@@ -84,6 +89,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) ...@@ -84,6 +89,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
__error: __error:
dec_mod_count(card->module); dec_mod_count(card->module);
__error2:
snd_card_file_remove(card, file);
__error1: __error1:
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
...@@ -118,7 +125,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file) ...@@ -118,7 +125,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
card = ctl->card; card = ctl->card;
write_lock_irqsave(&card->control_rwlock, flags); write_lock_irqsave(&card->control_rwlock, flags);
list_del(&ctl->list); list_del(&ctl->list);
write_unlock_irqrestore(&card->control_rwlock, flags);
write_lock(&card->control_owner_lock); write_lock(&card->control_owner_lock);
list_for_each(list, &card->controls) { list_for_each(list, &card->controls) {
control = snd_kcontrol(list); control = snd_kcontrol(list);
...@@ -126,9 +132,11 @@ static int snd_ctl_release(struct inode *inode, struct file *file) ...@@ -126,9 +132,11 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
control->owner = NULL; control->owner = NULL;
} }
write_unlock(&card->control_owner_lock); write_unlock(&card->control_owner_lock);
write_unlock_irqrestore(&card->control_rwlock, flags);
snd_ctl_empty_read_queue(ctl); snd_ctl_empty_read_queue(ctl);
snd_magic_kfree(ctl); snd_magic_kfree(ctl);
dec_mod_count(card->module); dec_mod_count(card->module);
snd_card_file_remove(card, file);
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
#endif #endif
...@@ -808,6 +816,21 @@ int snd_ctl_register(snd_card_t *card) ...@@ -808,6 +816,21 @@ int snd_ctl_register(snd_card_t *card)
return 0; 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 snd_ctl_unregister(snd_card_t *card)
{ {
int err, cardnum; int err, cardnum;
......
...@@ -56,7 +56,8 @@ int snd_device_free(snd_card_t *card, void *device_data) ...@@ -56,7 +56,8 @@ int snd_device_free(snd_card_t *card, void *device_data)
continue; continue;
/* unlink */ /* unlink */
list_del(&dev->list); 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)) if (dev->ops->dev_unregister(dev))
snd_printk(KERN_ERR "device unregister failure\n"); snd_printk(KERN_ERR "device unregister failure\n");
} else { } else {
...@@ -72,6 +73,28 @@ int snd_device_free(snd_card_t *card, void *device_data) ...@@ -72,6 +73,28 @@ int snd_device_free(snd_card_t *card, void *device_data)
return -ENXIO; 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) int snd_device_register(snd_card_t *card, void *device_data)
{ {
struct list_head *list; struct list_head *list;
...@@ -113,6 +136,21 @@ int snd_device_register_all(snd_card_t *card) ...@@ -113,6 +136,21 @@ int snd_device_register_all(snd_card_t *card)
return 0; 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) int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd)
{ {
snd_device_t *dev; snd_device_t *dev;
......
...@@ -933,11 +933,7 @@ snd_info_entry_t *snd_info_create_device(const char *name, unsigned int number, ...@@ -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); p = create_proc_entry(entry->name, entry->mode, snd_proc_dev);
if (p) { if (p) {
snd_info_device_entry_prepare(p, entry); snd_info_device_entry_prepare(p, entry);
#ifndef LINUX_2_2 #ifdef 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
p->ops = &snd_info_device_inode_operations; p->ops = &snd_info_device_inode_operations;
#endif #endif
} else { } else {
......
...@@ -21,15 +21,23 @@ ...@@ -21,15 +21,23 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/smp_lock.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
#include <sound/info.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; 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}; snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
rwlock_t snd_card_rwlock = RW_LOCK_UNLOCKED; 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 ...@@ -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_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, snd_card_t *snd_card_new(int idx, const char *xid,
struct module *module, int extra_size) struct module *module, int extra_size)
{ {
...@@ -85,6 +103,8 @@ snd_card_t *snd_card_new(int idx, const char *xid, ...@@ -85,6 +103,8 @@ snd_card_t *snd_card_new(int idx, const char *xid,
rwlock_init(&card->control_owner_lock); rwlock_init(&card->control_owner_lock);
INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files); INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
init_waitqueue_head(&card->shutdown_sleep);
#ifdef CONFIG_PM #ifdef CONFIG_PM
init_MUTEX(&card->power_lock); init_MUTEX(&card->power_lock);
init_waitqueue_head(&card->power_sleep); init_waitqueue_head(&card->power_sleep);
...@@ -110,17 +130,123 @@ snd_card_t *snd_card_new(int idx, const char *xid, ...@@ -110,17 +130,123 @@ snd_card_t *snd_card_new(int idx, const char *xid,
return NULL; 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) int snd_card_free(snd_card_t * card)
{ {
wait_queue_t wait;
struct snd_shutdown_f_ops *s_f_ops;
if (card == NULL) if (card == NULL)
return -EINVAL; return -EINVAL;
write_lock(&snd_card_rwlock); write_lock(&snd_card_rwlock);
snd_cards[card->number] = NULL; snd_cards[card->number] = NULL;
snd_cards_count--; snd_cards_count--;
write_unlock(&snd_card_rwlock); 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 defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback) 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 #endif
if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) { if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
snd_printk(KERN_ERR "unable to free all devices (pre)\n"); snd_printk(KERN_ERR "unable to free all devices (pre)\n");
...@@ -145,6 +271,11 @@ int snd_card_free(snd_card_t * card) ...@@ -145,6 +271,11 @@ int snd_card_free(snd_card_t * card)
snd_printk(KERN_WARNING "unable to free card info\n"); snd_printk(KERN_WARNING "unable to free card info\n");
/* Not fatal error */ /* 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); write_lock(&snd_card_rwlock);
snd_cards_lock &= ~(1 << card->number); snd_cards_lock &= ~(1 << card->number);
write_unlock(&snd_card_rwlock); write_unlock(&snd_card_rwlock);
...@@ -152,7 +283,65 @@ int snd_card_free(snd_card_t * card) ...@@ -152,7 +283,65 @@ int snd_card_free(snd_card_t * card)
return 0; 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; int i, len, idx_flag = 0, loops = 8;
char *id, *spos; char *id, *spos;
...@@ -246,7 +435,7 @@ int snd_card_register(snd_card_t * card) ...@@ -246,7 +435,7 @@ int snd_card_register(snd_card_t * card)
__skip_info: __skip_info:
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback) 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 #endif
return 0; return 0;
} }
...@@ -312,7 +501,6 @@ int __init snd_card_info_init(void) ...@@ -312,7 +501,6 @@ int __init snd_card_info_init(void)
return -ENOMEM; return -ENOMEM;
} }
snd_card_info_entry = entry; snd_card_info_entry = entry;
return 0; return 0;
} }
...@@ -343,6 +531,56 @@ int snd_component_add(snd_card_t *card, const char *component) ...@@ -343,6 +531,56 @@ int snd_component_add(snd_card_t *card, const char *component)
return 0; 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 #ifdef CONFIG_PM
/* the power lock must be active before call */ /* the power lock must be active before call */
void snd_power_wait(snd_card_t *card) void snd_power_wait(snd_card_t *card)
...@@ -352,6 +590,7 @@ 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); init_waitqueue_entry(&wait, current);
add_wait_queue(&card->power_sleep, &wait); add_wait_queue(&card->power_sleep, &wait);
snd_power_unlock(card); snd_power_unlock(card);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(30 * HZ); schedule_timeout(30 * HZ);
remove_wait_queue(&card->power_sleep, &wait); remove_wait_queue(&card->power_sleep, &wait);
snd_power_lock(card); snd_power_lock(card);
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/rawmidi.h> #include <sound/rawmidi.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/timer.h> #include <sound/timer.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/timer.h> #include <sound/timer.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
...@@ -45,14 +45,20 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) ...@@ -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)); int cardnum = SNDRV_MINOR_OSS_CARD(minor(inode->i_rdev));
snd_card_t *card; snd_card_t *card;
snd_mixer_oss_file_t *fmixer; snd_mixer_oss_file_t *fmixer;
int err;
if ((card = snd_cards[cardnum]) == NULL) if ((card = snd_cards[cardnum]) == NULL)
return -ENODEV; return -ENODEV;
if (card->mixer_oss == NULL) if (card->mixer_oss == NULL)
return -ENODEV; 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); 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; return -ENOMEM;
}
fmixer->card = card; fmixer->card = card;
fmixer->mixer = card->mixer_oss; fmixer->mixer = card->mixer_oss;
file->private_data = fmixer; file->private_data = fmixer;
...@@ -64,6 +70,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) ...@@ -64,6 +70,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
#endif #endif
snd_card_file_remove(card, file);
return -EFAULT; return -EFAULT;
} }
return 0; return 0;
...@@ -79,6 +86,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file) ...@@ -79,6 +86,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
#endif #endif
snd_card_file_remove(fmixer->card, file);
kfree(fmixer); kfree(fmixer);
} }
return 0; return 0;
...@@ -765,7 +773,7 @@ static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, int *active_i ...@@ -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++) { for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx))) if (!(mixer->mask_recsrc & (1 << idx)))
continue; continue;
pslot = &fmixer->mixer->slots[idx]; pslot = &mixer->slots[idx];
slot = (struct slot *)pslot->private_data; slot = (struct slot *)pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue; continue;
...@@ -812,7 +820,7 @@ static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, int active_in ...@@ -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++) { for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx))) if (!(mixer->mask_recsrc & (1 << idx)))
continue; continue;
pslot = &fmixer->mixer->slots[idx]; pslot = &mixer->slots[idx];
slot = (struct slot *)pslot->private_data; slot = (struct slot *)pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue; continue;
...@@ -1200,10 +1208,11 @@ static int snd_mixer_oss_free1(void *private) ...@@ -1200,10 +1208,11 @@ static int snd_mixer_oss_free1(void *private)
return 0; 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]; char name[128];
int idx, err; int idx, err;
...@@ -1220,6 +1229,7 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag) ...@@ -1220,6 +1229,7 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
snd_magic_kfree(mixer); snd_magic_kfree(mixer);
return err; return err;
} }
mixer->oss_dev_alloc = 1;
mixer->card = card; mixer->card = card;
if (*card->mixername) { if (*card->mixername) {
strncpy(mixer->name, card->mixername, sizeof(mixer->name) - 1); strncpy(mixer->name, card->mixername, sizeof(mixer->name) - 1);
...@@ -1236,13 +1246,20 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag) ...@@ -1236,13 +1246,20 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
card->mixer_oss = mixer; card->mixer_oss = mixer;
snd_mixer_oss_build(mixer); snd_mixer_oss_build(mixer);
snd_mixer_oss_proc_init(mixer); snd_mixer_oss_proc_init(mixer);
} else { } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
snd_mixer_oss_t *mixer = card->mixer_oss; 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) if (mixer == NULL)
return 0; return 0;
#ifdef SNDRV_OSS_INFO_DEV_MIXERS #ifdef SNDRV_OSS_INFO_DEV_MIXERS
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
#endif #endif
if (mixer->oss_dev_alloc)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
snd_mixer_oss_proc_done(mixer); snd_mixer_oss_proc_done(mixer);
return snd_mixer_oss_free1(mixer); return snd_mixer_oss_free1(mixer);
...@@ -1257,7 +1274,7 @@ static int __init alsa_mixer_oss_init(void) ...@@ -1257,7 +1274,7 @@ static int __init alsa_mixer_oss_init(void)
snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
for (idx = 0; idx < SNDRV_CARDS; idx++) { for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_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; return 0;
} }
...@@ -1269,7 +1286,7 @@ static void __exit alsa_mixer_oss_exit(void) ...@@ -1269,7 +1286,7 @@ static void __exit alsa_mixer_oss_exit(void)
snd_mixer_oss_notify_callback = NULL; snd_mixer_oss_notify_callback = NULL;
for (idx = 0; idx < SNDRV_CARDS; idx++) { for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_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) ...@@ -1554,13 +1554,16 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
err = -ENODEV; err = -ENODEV;
goto __error1; goto __error1;
} }
err = snd_card_file_add(pcm->card, file);
if (err < 0)
goto __error1;
if (!try_inc_mod_count(pcm->card->module)) { if (!try_inc_mod_count(pcm->card->module)) {
err = -EFAULT; err = -EFAULT;
goto __error1; goto __error2;
} }
if (snd_task_name(current, task_name, sizeof(task_name)) < 0) { if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
err = -EFAULT; err = -EFAULT;
goto __error1; goto __error;
} }
if (file->f_mode & FMODE_WRITE) if (file->f_mode & FMODE_WRITE)
psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name); 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) ...@@ -1584,13 +1587,12 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(&pcm->open_wait, &wait); add_wait_queue(&pcm->open_wait, &wait);
while (1) {
down(&pcm->open_mutex); down(&pcm->open_mutex);
while (1) {
err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file, err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
minor, psetup, csetup); minor, psetup, csetup);
if (err >= 0) if (err >= 0)
break; break;
up(&pcm->open_mutex);
if (err == -EAGAIN) { if (err == -EAGAIN) {
if (nonblock) { if (nonblock) {
err = -EBUSY; err = -EBUSY;
...@@ -1599,7 +1601,9 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) ...@@ -1599,7 +1601,9 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
} else } else
break; break;
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
up(&pcm->open_mutex);
schedule(); schedule();
down(&pcm->open_mutex);
if (signal_pending(current)) { if (signal_pending(current)) {
err = -ERESTARTSYS; err = -ERESTARTSYS;
break; break;
...@@ -1607,13 +1611,15 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) ...@@ -1607,13 +1611,15 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&pcm->open_wait, &wait); remove_wait_queue(&pcm->open_wait, &wait);
up(&pcm->open_mutex);
if (err < 0) if (err < 0)
goto __error; goto __error;
up(&pcm->open_mutex);
return err; return err;
__error: __error:
dec_mod_count(pcm->card->module); dec_mod_count(pcm->card->module);
__error2:
snd_card_file_remove(pcm->card, file);
__error1: __error1:
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
...@@ -1639,6 +1645,7 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file) ...@@ -1639,6 +1645,7 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file)
up(&pcm->open_mutex); up(&pcm->open_mutex);
wake_up(&pcm->open_wait); wake_up(&pcm->open_wait);
dec_mod_count(pcm->card->module); dec_mod_count(pcm->card->module);
snd_card_file_remove(pcm->card, file);
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
#endif #endif
...@@ -2108,7 +2115,7 @@ static snd_minor_t snd_pcm_oss_reg = ...@@ -2108,7 +2115,7 @@ static snd_minor_t snd_pcm_oss_reg =
.f_ops = &snd_pcm_oss_f_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]; char name[128];
sprintf(name, "dsp%i%i", pcm->card->number, pcm->device); 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 ...@@ -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, static int snd_pcm_oss_register_minor(snd_pcm_t * pcm)
snd_pcm_t * pcm)
{ {
pcm->oss.reg = 0; pcm->oss.reg = 0;
if (dsp_map[pcm->card->number] == pcm->device) { if (dsp_map[pcm->card->number] == pcm->device) {
char name[128]; char name[128];
int duplex; int duplex;
register_oss_dsp(native_minor, pcm, 0); register_oss_dsp(pcm, 0);
duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 && duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 &&
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count && pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count &&
!(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)); !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX));
...@@ -2137,10 +2143,12 @@ static int snd_pcm_oss_register_minor(unsigned short native_minor, ...@@ -2137,10 +2143,12 @@ static int snd_pcm_oss_register_minor(unsigned short native_minor,
name); name);
#endif #endif
pcm->oss.reg++; pcm->oss.reg++;
pcm->oss.reg_mask |= 1;
} }
if (adsp_map[pcm->card->number] == pcm->device) { 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++;
pcm->oss.reg_mask |= 2;
} }
if (pcm->oss.reg) if (pcm->oss.reg)
...@@ -2149,20 +2157,32 @@ static int snd_pcm_oss_register_minor(unsigned short native_minor, ...@@ -2149,20 +2157,32 @@ static int snd_pcm_oss_register_minor(unsigned short native_minor,
return 0; return 0;
} }
static int snd_pcm_oss_unregister_minor(unsigned short native_minor, static int snd_pcm_oss_disconnect_minor(snd_pcm_t * pcm)
snd_pcm_t * pcm)
{ {
if (pcm->oss.reg) { 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, snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, 0); 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 #ifdef SNDRV_OSS_INFO_DEV_AUDIO
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
#endif #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; pcm->oss.reg = 0;
snd_pcm_oss_proc_done(pcm); snd_pcm_oss_proc_done(pcm);
} }
...@@ -2172,6 +2192,7 @@ static int snd_pcm_oss_unregister_minor(unsigned short native_minor, ...@@ -2172,6 +2192,7 @@ static int snd_pcm_oss_unregister_minor(unsigned short native_minor,
static snd_pcm_notify_t snd_pcm_oss_notify = static snd_pcm_notify_t snd_pcm_oss_notify =
{ {
.n_register = snd_pcm_oss_register_minor, .n_register = snd_pcm_oss_register_minor,
.n_disconnect = snd_pcm_oss_disconnect_minor,
.n_unregister = snd_pcm_oss_unregister_minor, .n_unregister = snd_pcm_oss_unregister_minor,
}; };
...@@ -2180,8 +2201,6 @@ static int __init alsa_pcm_oss_init(void) ...@@ -2180,8 +2201,6 @@ static int __init alsa_pcm_oss_init(void)
int i; int i;
int err; int err;
if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
return err;
/* check device map table */ /* check device map table */
for (i = 0; i < SNDRV_CARDS; i++) { for (i = 0; i < SNDRV_CARDS; i++) {
if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) { if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
...@@ -2193,6 +2212,8 @@ static int __init alsa_pcm_oss_init(void) ...@@ -2193,6 +2212,8 @@ static int __init alsa_pcm_oss_init(void)
adsp_map[i] = 1; adsp_map[i] = 1;
} }
} }
if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
return err;
return 0; return 0;
} }
......
...@@ -37,9 +37,10 @@ snd_pcm_t *snd_pcm_devices[SNDRV_CARDS * SNDRV_PCM_DEVICES]; ...@@ -37,9 +37,10 @@ snd_pcm_t *snd_pcm_devices[SNDRV_CARDS * SNDRV_PCM_DEVICES];
static LIST_HEAD(snd_pcm_notify_list); static LIST_HEAD(snd_pcm_notify_list);
static DECLARE_MUTEX(register_mutex); 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_free(snd_device_t *device);
static int snd_pcm_dev_register(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); static int snd_pcm_dev_unregister(snd_device_t *device);
void snd_pcm_lock(int xup) void snd_pcm_lock(int xup)
...@@ -598,6 +599,7 @@ int snd_pcm_new(snd_card_t * card, char *id, int device, ...@@ -598,6 +599,7 @@ int snd_pcm_new(snd_card_t * card, char *id, int device,
static snd_device_ops_t ops = { static snd_device_ops_t ops = {
.dev_free = snd_pcm_dev_free, .dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register, .dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
.dev_unregister = snd_pcm_dev_unregister .dev_unregister = snd_pcm_dev_unregister
}; };
...@@ -653,7 +655,7 @@ static void snd_pcm_free_stream(snd_pcm_str_t * pstr) ...@@ -653,7 +655,7 @@ static void snd_pcm_free_stream(snd_pcm_str_t * pstr)
#endif #endif
} }
int snd_pcm_free(snd_pcm_t *pcm) static int snd_pcm_free(snd_pcm_t *pcm)
{ {
snd_assert(pcm != NULL, return -ENXIO); snd_assert(pcm != NULL, return -ENXIO);
if (pcm->private_free) if (pcm->private_free)
...@@ -664,7 +666,7 @@ int snd_pcm_free(snd_pcm_t *pcm) ...@@ -664,7 +666,7 @@ int snd_pcm_free(snd_pcm_t *pcm)
return 0; 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); snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO);
return snd_pcm_free(pcm); return snd_pcm_free(pcm);
...@@ -793,7 +795,7 @@ void snd_pcm_release_substream(snd_pcm_substream_t *substream) ...@@ -793,7 +795,7 @@ void snd_pcm_release_substream(snd_pcm_substream_t *substream)
substream->pstr->substream_opened--; 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; int idx, cidx, err;
unsigned short minor; unsigned short minor;
...@@ -837,7 +839,25 @@ int snd_pcm_dev_register(snd_device_t *device) ...@@ -837,7 +839,25 @@ int snd_pcm_dev_register(snd_device_t *device)
list_for_each(list, &snd_pcm_notify_list) { list_for_each(list, &snd_pcm_notify_list) {
snd_pcm_notify_t *notify; snd_pcm_notify_t *notify;
notify = list_entry(list, snd_pcm_notify_t, list); 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); snd_pcm_lock(1);
return 0; return 0;
...@@ -853,10 +873,7 @@ static int snd_pcm_dev_unregister(snd_device_t *device) ...@@ -853,10 +873,7 @@ static int snd_pcm_dev_unregister(snd_device_t *device)
snd_assert(pcm != NULL, return -ENXIO); snd_assert(pcm != NULL, return -ENXIO);
snd_pcm_lock(0); snd_pcm_lock(0);
idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
if (snd_pcm_devices[idx] != pcm) { snd_pcm_devices[idx] = NULL;
snd_pcm_lock(1);
return -EINVAL;
}
for (cidx = 0; cidx < 2; cidx++) { for (cidx = 0; cidx < 2; cidx++) {
devtype = -1; devtype = -1;
switch (cidx) { switch (cidx) {
...@@ -874,9 +891,8 @@ static int snd_pcm_dev_unregister(snd_device_t *device) ...@@ -874,9 +891,8 @@ static int snd_pcm_dev_unregister(snd_device_t *device)
list_for_each(list, &snd_pcm_notify_list) { list_for_each(list, &snd_pcm_notify_list) {
snd_pcm_notify_t *notify; snd_pcm_notify_t *notify;
notify = list_entry(list, snd_pcm_notify_t, list); 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); snd_pcm_lock(1);
return snd_pcm_free(pcm); return snd_pcm_free(pcm);
} }
...@@ -892,16 +908,14 @@ int snd_pcm_notify(snd_pcm_notify_t *notify, int nfree) ...@@ -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++) { for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
if (snd_pcm_devices[idx] == NULL) if (snd_pcm_devices[idx] == NULL)
continue; continue;
notify->n_unregister(-1 /* idx + SNDRV_MINOR_PCM */, notify->n_unregister(snd_pcm_devices[idx]);
snd_pcm_devices[idx]);
} }
} else { } else {
list_add_tail(&notify->list, &snd_pcm_notify_list); list_add_tail(&notify->list, &snd_pcm_notify_list);
for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) { for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
if (snd_pcm_devices[idx] == NULL) if (snd_pcm_devices[idx] == NULL)
continue; continue;
notify->n_register(-1 /* idx + SNDRV_MINOR_PCM */, notify->n_register(snd_pcm_devices[idx]);
snd_pcm_devices[idx]);
} }
} }
snd_pcm_lock(1); snd_pcm_lock(1);
......
...@@ -1796,9 +1796,12 @@ int snd_pcm_open(struct inode *inode, struct file *file) ...@@ -1796,9 +1796,12 @@ int snd_pcm_open(struct inode *inode, struct file *file)
err = -ENODEV; err = -ENODEV;
goto __error1; goto __error1;
} }
err = snd_card_file_add(pcm->card, file);
if (err < 0)
goto __error1;
if (!try_inc_mod_count(pcm->card->module)) { if (!try_inc_mod_count(pcm->card->module)) {
err = -EFAULT; err = -EFAULT;
goto __error1; goto __error2;
} }
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(&pcm->open_wait, &wait); add_wait_queue(&pcm->open_wait, &wait);
...@@ -1831,6 +1834,8 @@ int snd_pcm_open(struct inode *inode, struct file *file) ...@@ -1831,6 +1834,8 @@ int snd_pcm_open(struct inode *inode, struct file *file)
__error: __error:
dec_mod_count(pcm->card->module); dec_mod_count(pcm->card->module);
__error2:
snd_card_file_remove(pcm->card, file);
__error1: __error1:
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
...@@ -1859,6 +1864,7 @@ int snd_pcm_release(struct inode *inode, struct file *file) ...@@ -1859,6 +1864,7 @@ int snd_pcm_release(struct inode *inode, struct file *file)
up(&pcm->open_mutex); up(&pcm->open_mutex);
wake_up(&pcm->open_wait); wake_up(&pcm->open_wait);
dec_mod_count(pcm->card->module); dec_mod_count(pcm->card->module);
snd_card_file_remove(pcm->card, file);
#ifdef LINUX_2_2 #ifdef LINUX_2_2
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
#endif #endif
......
...@@ -51,6 +51,7 @@ MODULE_PARM_SYNTAX(amidi_map, "default:1,skill:advanced"); ...@@ -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_free(snd_rawmidi_t *rawmidi);
static int snd_rawmidi_dev_free(snd_device_t *device); 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_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); static int snd_rawmidi_dev_unregister(snd_device_t *device);
snd_rawmidi_t *snd_rawmidi_devices[SNDRV_CARDS * SNDRV_RAWMIDI_DEVICES]; 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) ...@@ -389,19 +390,24 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device]; rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device];
if (rmidi == NULL) if (rmidi == NULL)
return -ENODEV; return -ENODEV;
card = rmidi->card;
#ifdef CONFIG_SND_OSSEMUL #ifdef CONFIG_SND_OSSEMUL
if (maj == SOUND_MAJOR && !rmidi->ossreg) if (maj == SOUND_MAJOR && !rmidi->ossreg)
return -ENXIO; return -ENXIO;
#endif #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 */ 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? */ if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */
fflags |= SNDRV_RAWMIDI_LFLG_APPEND; fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
rawmidi_file = snd_magic_kmalloc(snd_rawmidi_file_t, 0, GFP_KERNEL); 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; return -ENOMEM;
}
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(&rmidi->open_wait, &wait); add_wait_queue(&rmidi->open_wait, &wait);
while (1) { while (1) {
...@@ -443,6 +449,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) ...@@ -443,6 +449,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if (err >= 0) { if (err >= 0) {
file->private_data = rawmidi_file; file->private_data = rawmidi_file;
} else { } else {
snd_card_file_remove(card, file);
snd_magic_kfree(rawmidi_file); snd_magic_kfree(rawmidi_file);
} }
return err; return err;
...@@ -507,12 +514,15 @@ int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile) ...@@ -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) static int snd_rawmidi_release(struct inode *inode, struct file *file)
{ {
snd_rawmidi_file_t *rfile; snd_rawmidi_file_t *rfile;
snd_rawmidi_t *rmidi;
int err; int err;
rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO); rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO);
err = snd_rawmidi_kernel_release(rfile); 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_magic_kfree(rfile);
snd_card_file_remove(rmidi->card, file);
return err; return err;
} }
...@@ -1318,6 +1328,7 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device, ...@@ -1318,6 +1328,7 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device,
static snd_device_ops_t ops = { static snd_device_ops_t ops = {
.dev_free = snd_rawmidi_dev_free, .dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register, .dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect,
.dev_unregister = snd_rawmidi_dev_unregister .dev_unregister = snd_rawmidi_dev_unregister
}; };
...@@ -1466,6 +1477,18 @@ static int snd_rawmidi_dev_register(snd_device_t *device) ...@@ -1466,6 +1477,18 @@ static int snd_rawmidi_dev_register(snd_device_t *device)
return 0; 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) static int snd_rawmidi_dev_unregister(snd_device_t *device)
{ {
int idx; int idx;
...@@ -1474,10 +1497,7 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device) ...@@ -1474,10 +1497,7 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device)
snd_assert(rmidi != NULL, return -ENXIO); snd_assert(rmidi != NULL, return -ENXIO);
down(&register_mutex); down(&register_mutex);
idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device; idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
if (snd_rawmidi_devices[idx] != rmidi) { snd_rawmidi_devices[idx] = NULL;
up(&register_mutex);
return -EINVAL;
}
if (rmidi->proc_entry) { if (rmidi->proc_entry) {
snd_info_unregister(rmidi->proc_entry); snd_info_unregister(rmidi->proc_entry);
rmidi->proc_entry = NULL; rmidi->proc_entry = NULL;
...@@ -1498,7 +1518,6 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device) ...@@ -1498,7 +1518,6 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device)
if (rmidi->ops && rmidi->ops->dev_unregister) if (rmidi->ops && rmidi->ops->dev_unregister)
rmidi->ops->dev_unregister(rmidi); rmidi->ops->dev_unregister(rmidi);
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
snd_rawmidi_devices[idx] = NULL;
up(&register_mutex); up(&register_mutex);
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
if (rmidi->seq_dev) { if (rmidi->seq_dev) {
......
...@@ -29,51 +29,53 @@ endif ...@@ -29,51 +29,53 @@ endif
obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
# Toplevel Module Dependency # Toplevel Module Dependency
obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o RAWMIDI_OBJS = snd-seq-midi.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 OPL3_OBJS = snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_MTPAV) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.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_SERIAL_U16550) += $(RAWMIDI_OBJS)
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_MTPAV) += $(RAWMIDI_OBJS)
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_MPU401) += $(RAWMIDI_OBJS)
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_ALS100) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_AZT2320) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_DT019X) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_ES18XX) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_CS4231) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_OPL3SA2) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_AD1816A) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_CS4231) += $(RAWMIDI_OBJS)
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_CS4232) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_CS4236) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_ES1688) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_GUSCLASSIC) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_GUSMAX) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_GUSEXTREME) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_INTERWAVE) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_INTERWAVE_STB) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_OPTI92X_AD1848) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_OPTI92X_CS4231) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_OPTI93X) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_SB8) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ES968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_SB16) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_SBAWE) += $(RAWMIDI_OBJS) $(OPL3_OBJS) snd-seq-virmidi.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_ES968) += $(RAWMIDI_OBJS)
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_WAVEFRONT) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_ALS4000) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ENS1370) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_CMIPCI) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ENS1371) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_CS4281) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_ENS1370) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_ES1968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_ENS1371) += $(RAWMIDI_OBJS)
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_ES1938) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_ES1968) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_INTEL8X0) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_FM801) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
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_ICE1712) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_VIA82XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_INTEL8X0) += $(RAWMIDI_OBJS)
obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_SONICVIBES) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
obj-$(CONFIG_SND_CS46XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_VIA82XX) += $(RAWMIDI_OBJS)
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_ALI5451) += $(RAWMIDI_OBJS)
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_CS46XX) += $(RAWMIDI_OBJS)
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_EMU10K1) += $(RAWMIDI_OBJS) snd-seq-midi-emul.o snd-seq-virmidi.o
obj-$(CONFIG_SND_USB_AUDIO) += snd-seq.o snd-seq-device.o snd-seq-midi-event.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)) obj-m := $(sort $(obj-m))
......
...@@ -92,6 +92,7 @@ static snd_info_entry_t *info_entry = NULL; ...@@ -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_free(snd_seq_device_t *dev);
static int snd_seq_device_dev_free(snd_device_t *device); 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_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 snd_seq_device_dev_unregister(snd_device_t *device);
static int init_device(snd_seq_device_t *dev, ops_list_t *ops); 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, ...@@ -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 = { static snd_device_ops_t dops = {
.dev_free = snd_seq_device_dev_free, .dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register, .dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect,
.dev_unregister = snd_seq_device_dev_unregister .dev_unregister = snd_seq_device_dev_unregister
}; };
...@@ -268,6 +270,22 @@ static int snd_seq_device_dev_register(snd_device_t *device) ...@@ -268,6 +270,22 @@ static int snd_seq_device_dev_register(snd_device_t *device)
return 0; 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 * unregister the existing device
*/ */
......
...@@ -76,8 +76,12 @@ static devfs_handle_t devfs_handle = NULL; ...@@ -76,8 +76,12 @@ static devfs_handle_t devfs_handle = NULL;
void snd_request_card(int card) void snd_request_card(int card)
{ {
char str[32]; 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; return;
if (card < 0 || card >= snd_ecards_limit) if (card < 0 || card >= snd_ecards_limit)
return; return;
...@@ -423,9 +427,13 @@ EXPORT_SYMBOL(snd_cards); ...@@ -423,9 +427,13 @@ EXPORT_SYMBOL(snd_cards);
EXPORT_SYMBOL(snd_mixer_oss_notify_callback); EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
#endif #endif
EXPORT_SYMBOL(snd_card_new); EXPORT_SYMBOL(snd_card_new);
EXPORT_SYMBOL(snd_card_disconnect);
EXPORT_SYMBOL(snd_card_free); EXPORT_SYMBOL(snd_card_free);
EXPORT_SYMBOL(snd_card_free_in_thread);
EXPORT_SYMBOL(snd_card_register); EXPORT_SYMBOL(snd_card_register);
EXPORT_SYMBOL(snd_component_add); EXPORT_SYMBOL(snd_component_add);
EXPORT_SYMBOL(snd_card_file_add);
EXPORT_SYMBOL(snd_card_file_remove);
#ifdef CONFIG_PM #ifdef CONFIG_PM
EXPORT_SYMBOL(snd_power_wait); EXPORT_SYMBOL(snd_power_wait);
#endif #endif
......
...@@ -13,58 +13,37 @@ snd-opl3-synth-objs += opl3_oss.o ...@@ -13,58 +13,37 @@ snd-opl3-synth-objs += opl3_oss.o
endif endif
endif endif
# Toplevel Module Dependency OPL3_OBJS = snd-opl3-lib.o
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
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_ALS100) += snd-opl3-synth.o OPL3_OBJS += 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
endif 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)) obj-m := $(sort $(obj-m))
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -263,6 +263,8 @@ static struct isapnp_card_id snd_card_pnpids[] __devinitdata = { ...@@ -263,6 +263,8 @@ static struct isapnp_card_id snd_card_pnpids[] __devinitdata = {
ISAPNP_CS4232('C','S','C',0xd937,0x0000,0x0010,0x0003), ISAPNP_CS4232('C','S','C',0xd937,0x0000,0x0010,0x0003),
/* CS4235 without MPU401 */ /* CS4235 without MPU401 */
ISAPNP_CS4232_WOMPU('C','S','C',0xe825,0x0100,0x0110), 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 */ /* Some noname CS4236 based card */
ISAPNP_CS4232('C','S','C',0xe936,0x0000,0x0010,0x0003), ISAPNP_CS4232('C','S','C',0xe936,0x0000,0x0010,0x0003),
/* CS4236B */ /* CS4236B */
...@@ -609,12 +611,10 @@ module_exit(alsa_card_cs423x_exit) ...@@ -609,12 +611,10 @@ module_exit(alsa_card_cs423x_exit)
/* format is: snd-cs4232=enable,index,id,isapnp,port, /* format is: snd-cs4232=enable,index,id,isapnp,port,
cport,mpu_port,fm_port,sb_port, cport,mpu_port,fm_port,sb_port,
irq,mpu_irq,dma1,dma1_size, irq,mpu_irq,dma1,dma2 */
dma2,dma2_size */
/* format is: snd-cs4236=enable,index,id,isapnp,port, /* format is: snd-cs4236=enable,index,id,isapnp,port,
cport,mpu_port,fm_port,sb_port, cport,mpu_port,fm_port,sb_port,
irq,mpu_irq,dma1,dma1_size, irq,mpu_irq,dma1,dma2 */
dma2,dma2_size */
static int __init alsa_card_cs423x_setup(char *str) static int __init alsa_card_cs423x_setup(char *str)
{ {
......
...@@ -182,6 +182,8 @@ static struct isapnp_card_id snd_sb16_pnpids[] __devinitdata = { ...@@ -182,6 +182,8 @@ static struct isapnp_card_id snd_sb16_pnpids[] __devinitdata = {
/* Sound Blaster 16 PnP */ /* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0024,0x0031), ISAPNP_SB16('C','T','L',0x0024,0x0031),
/* Sound Blaster 16 PnP */ /* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0025,0x0031),
/* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0026,0x0031), ISAPNP_SB16('C','T','L',0x0026,0x0031),
/* Sound Blaster 16 PnP */ /* Sound Blaster 16 PnP */
ISAPNP_SB16('C','T','L',0x0027,0x0031), ISAPNP_SB16('C','T','L',0x0027,0x0031),
......
This diff is collapsed.
...@@ -43,4 +43,6 @@ ...@@ -43,4 +43,6 @@
#define AC97_ID_CS4299 0x43525930 #define AC97_ID_CS4299 0x43525930
#define AC97_ID_CS4201 0x43525948 #define AC97_ID_CS4201 0x43525948
#define AC97_ID_CS4205 0x43525958 #define AC97_ID_CS4205 0x43525958
#define AC97_ID_CS_MASK 0xfffffff8 /* bit 0-2: rev */
#define AC97_ID_ALC650 0x414c4720 #define AC97_ID_ALC650 0x414c4720
#define AC97_ID_YMF753 0x594d4803
...@@ -37,6 +37,20 @@ ...@@ -37,6 +37,20 @@
* Chip specific initialization * 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) int patch_wolfson00(ac97_t * ac97)
{ {
/* This sequence is suspect because it was designed for /* This sequence is suspect because it was designed for
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
* *
*/ */
int patch_yamaha_ymf753(ac97_t * ac97);
int patch_wolfson00(ac97_t * ac97); int patch_wolfson00(ac97_t * ac97);
int patch_wolfson03(ac97_t * ac97); int patch_wolfson03(ac97_t * ac97);
int patch_wolfson04(ac97_t * ac97); int patch_wolfson04(ac97_t * ac97);
......
...@@ -529,7 +529,8 @@ static int snd_ali_reset_5451(ali_t *codec) ...@@ -529,7 +529,8 @@ static int snd_ali_reset_5451(ali_t *codec)
udelay(5000); udelay(5000);
} }
return -1; snd_printk(KERN_WARNING "ali5451: reset time out\n");
return 0;
} }
#ifdef CODEC_RESET #ifdef CODEC_RESET
...@@ -1999,14 +2000,10 @@ static int snd_ali_chip_init(ali_t *codec) ...@@ -1999,14 +2000,10 @@ static int snd_ali_chip_init(ali_t *codec)
if (codec->revision == ALI_5451_V02) { if (codec->revision == ALI_5451_V02) {
pci_dev = codec->pci_m1533; pci_dev = codec->pci_m1533;
if (pci_dev == NULL)
return -1;
pci_read_config_byte(pci_dev, 0x59, &temp); pci_read_config_byte(pci_dev, 0x59, &temp);
pci_dev = pci_find_device(0x10b9,0x7101, pci_dev); pci_dev = codec->pci_m7101;
if (pci_dev == NULL) pci_read_config_byte(pci_dev, 0xb8, &temp);
return -1;
pci_read_config_byte(pci_dev,0xb8,&temp);
temp |= 1 << 6; temp |= 1 << 6;
pci_write_config_byte(pci_dev, 0xB8, temp); pci_write_config_byte(pci_dev, 0xB8, temp);
} }
...@@ -2139,10 +2136,22 @@ static int __devinit snd_ali_create(snd_card_t * card, ...@@ -2139,10 +2136,22 @@ static int __devinit snd_ali_create(snd_card_t * card,
codec->chregs.data.aint = 0x00; codec->chregs.data.aint = 0x00;
codec->chregs.data.ainten = 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; 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; 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"); snd_ali_printk("snd_device_new is called.\n");
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) { 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) ...@@ -1804,7 +1804,7 @@ static int snd_cs4281_midi_output_open(snd_rawmidi_substream_t * substream)
spin_lock_irqsave(&chip->reg_lock, flags); spin_lock_irqsave(&chip->reg_lock, flags);
chip->uartm |= CS4281_MODE_OUTPUT; chip->uartm |= CS4281_MODE_OUTPUT;
chip->midcr |= BA0_MIDCR_TXE; chip->midcr |= BA0_MIDCR_TXE;
chip->midi_input = substream; chip->midi_output = substream;
if (!(chip->uartm & CS4281_MODE_INPUT)) { if (!(chip->uartm & CS4281_MODE_INPUT)) {
snd_cs4281_midi_reset(chip); snd_cs4281_midi_reset(chip);
} else { } else {
......
...@@ -81,7 +81,7 @@ void snd_ice1712_ak4524_write(ice1712_t *ice, int chip, ...@@ -81,7 +81,7 @@ void snd_ice1712_ak4524_write(ice1712_t *ice, int chip,
udelay(1); udelay(1);
} }
if (ak->type == SND_AK4524) { if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0) if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0)
ak->images[chip][addr] = data; ak->images[chip][addr] = data;
else else
......
...@@ -189,19 +189,18 @@ static void delta_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucont ...@@ -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) static int delta_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{ {
unsigned long flags;
unsigned int val; unsigned int val;
int change; int change;
val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958); 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; change = ice->spdif.cs8403_bits != val;
ice->spdif.cs8403_bits = val; ice->spdif.cs8403_bits = val;
if (change && ice->playback_pro_substream == NULL) { 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); snd_ice1712_delta_cs8403_spdif_write(ice, val);
} else { } else {
spin_unlock_irqrestore(&ice->reg_lock, flags); spin_unlock_irq(&ice->reg_lock);
} }
return change; return change;
} }
...@@ -213,19 +212,18 @@ static void delta_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontr ...@@ -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) static int delta_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{ {
unsigned long flags;
unsigned int val; unsigned int val;
int change; int change;
val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958); 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; change = ice->spdif.cs8403_stream_bits != val;
ice->spdif.cs8403_stream_bits = val; ice->spdif.cs8403_stream_bits = val;
if (change && ice->playback_pro_substream != NULL) { 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); snd_ice1712_delta_cs8403_spdif_write(ice, val);
} else { } else {
spin_unlock_irqrestore(&ice->reg_lock, flags); spin_unlock_irq(&ice->reg_lock);
} }
return change; return change;
} }
......
...@@ -245,19 +245,18 @@ static void ews88_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucont ...@@ -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) static int ews88_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{ {
unsigned long flags;
unsigned int val; unsigned int val;
int change; int change;
val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958); 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; change = ice->spdif.cs8403_bits != val;
ice->spdif.cs8403_bits = val; ice->spdif.cs8403_bits = val;
if (change && ice->playback_pro_substream == NULL) { 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); snd_ice1712_ews_cs8404_spdif_write(ice, val);
} else { } else {
spin_unlock_irqrestore(&ice->reg_lock, flags); spin_unlock_irq(&ice->reg_lock);
} }
return change; return change;
} }
...@@ -269,19 +268,18 @@ static void ews88_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontr ...@@ -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) static int ews88_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
{ {
unsigned long flags;
unsigned int val; unsigned int val;
int change; int change;
val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958); 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; change = ice->spdif.cs8403_stream_bits != val;
ice->spdif.cs8403_stream_bits = val; ice->spdif.cs8403_stream_bits = val;
if (change && ice->playback_pro_substream != NULL) { 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); snd_ice1712_ews_cs8404_spdif_write(ice, val);
} else { } else {
spin_unlock_irqrestore(&ice->reg_lock, flags); spin_unlock_irq(&ice->reg_lock);
} }
return change; return change;
} }
......
This diff is collapsed.
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* ALSA driver for RME Hammerfall DSP audio interface(s) * ALSA driver for RME Hammerfall DSP audio interface(s)
* *
* Copyright (c) 2002 Paul Davis * Copyright (c) 2002 Paul Davis
* Marcus Andersson
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -81,7 +82,7 @@ typedef enum { ...@@ -81,7 +82,7 @@ typedef enum {
#define DIGIFACE_SS_CHANNELS 26 #define DIGIFACE_SS_CHANNELS 26
#define DIGIFACE_DS_CHANNELS 14 #define DIGIFACE_DS_CHANNELS 14
#define MULTIFACE_SS_CHANNELS 18 #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. /* 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) ...@@ -687,6 +688,7 @@ static int hdsp_set_rate(hdsp_t *hdsp, int rate)
rate = HDSP_Frequency96KHz; rate = HDSP_Frequency96KHz;
break; break;
default: default:
spin_unlock_irq(&hdsp->lock);
return -EINVAL; return -EINVAL;
} }
...@@ -747,10 +749,12 @@ static void hdsp_set_thru(hdsp_t *hdsp, int channel, int enable) ...@@ -747,10 +749,12 @@ static void hdsp_set_thru(hdsp_t *hdsp, int channel, int enable)
mapped_channel = hdsp->channel_map[channel]; mapped_channel = hdsp->channel_map[channel];
snd_assert(mapped_channel > -1, return);
if (enable) { 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 { } 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 ...@@ -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); hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol);
unsigned long flags; unsigned long flags;
int addr; int addr;
int chn; int channel;
int mapped_channel;
channel = ucontrol->id.index - 1;
snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return -EINVAL);
chn = ucontrol->id.index - 1; if ((mapped_channel = hdsp->channel_map[channel]) < 0) {
addr = PLAYBACK_TO_OUTPUT_KEY(chn, chn); return -EINVAL;
}
addr = PLAYBACK_TO_OUTPUT_KEY(mapped_channel, mapped_channel);
spin_lock_irqsave(&hdsp->lock, flags); spin_lock_irqsave(&hdsp->lock, flags);
ucontrol->value.integer.value[0] = hdsp_read_gain (hdsp, addr); 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 ...@@ -1622,14 +1634,22 @@ static int snd_hdsp_put_playback_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
unsigned long flags; unsigned long flags;
int change; int change;
int addr; int addr;
int chn; int channel;
int mapped_channel;
int gain; int gain;
if (!snd_hdsp_use_is_exclusive(hdsp)) if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY; return -EBUSY;
chn = ucontrol->id.index - 1; channel = ucontrol->id.index - 1;
addr = PLAYBACK_TO_OUTPUT_KEY(chn, chn);
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]; gain = ucontrol->value.integer.value[0];
...@@ -2434,15 +2454,15 @@ static int snd_hdsp_channel_info(snd_pcm_substream_t *substream, ...@@ -2434,15 +2454,15 @@ static int snd_hdsp_channel_info(snd_pcm_substream_t *substream,
snd_pcm_channel_info_t *info) snd_pcm_channel_info_t *info)
{ {
hdsp_t *hdsp = _snd_pcm_substream_chip(substream); hdsp_t *hdsp = _snd_pcm_substream_chip(substream);
int chn; int mapped_channel;
snd_assert(info->channel < HDSP_MAX_CHANNELS, return -EINVAL); 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; return -EINVAL;
} }
info->offset = chn * HDSP_CHANNEL_BUFFER_BYTES; info->offset = mapped_channel * HDSP_CHANNEL_BUFFER_BYTES;
info->first = 0; info->first = 0;
info->step = 32; info->step = 32;
return 0; return 0;
...@@ -2567,7 +2587,7 @@ static snd_pcm_hardware_t snd_hdsp_playback_subinfo = ...@@ -2567,7 +2587,7 @@ static snd_pcm_hardware_t snd_hdsp_playback_subinfo =
SNDRV_PCM_RATE_96000), SNDRV_PCM_RATE_96000),
.rate_min = 32000, .rate_min = 32000,
.rate_max = 96000, .rate_max = 96000,
.channels_min = 10, .channels_min = 14,
.channels_max = HDSP_MAX_CHANNELS, .channels_max = HDSP_MAX_CHANNELS,
.buffer_bytes_max = 1024*1024, .buffer_bytes_max = 1024*1024,
.period_bytes_min = 1, .period_bytes_min = 1,
...@@ -2592,7 +2612,7 @@ static snd_pcm_hardware_t snd_hdsp_capture_subinfo = ...@@ -2592,7 +2612,7 @@ static snd_pcm_hardware_t snd_hdsp_capture_subinfo =
SNDRV_PCM_RATE_96000), SNDRV_PCM_RATE_96000),
.rate_min = 32000, .rate_min = 32000,
.rate_max = 96000, .rate_max = 96000,
.channels_min = 10, .channels_min = 14,
.channels_max = HDSP_MAX_CHANNELS, .channels_max = HDSP_MAX_CHANNELS,
.buffer_bytes_max = 1024*1024, .buffer_bytes_max = 1024*1024,
.period_bytes_min = 1, .period_bytes_min = 1,
...@@ -2902,11 +2922,15 @@ static int __devinit snd_hdsp_initialize_firmware (hdsp_t *hdsp) ...@@ -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"); snd_printk ("timeout at end of firmware loading\n");
return -EIO; return -EIO;
} }
hdsp_write (hdsp, HDSP_jtagReg, 0);
snd_printk ("finished firmware loading\n");
mdelay(3000);
} else { } else {
/* firmware already loaded, but we need to know what type /* 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) ...@@ -613,6 +613,9 @@ static int snd_via82xx_playback_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime; 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_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 && if (chip->chip_type == TYPE_VIA8233 &&
chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) { chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
unsigned int tmp; unsigned int tmp;
......
...@@ -1181,7 +1181,6 @@ static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction, ...@@ -1181,7 +1181,6 @@ static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction,
runtime->private_data = subs; runtime->private_data = subs;
subs->pcm_substream = substream; subs->pcm_substream = substream;
setup_hw_info(runtime, subs); setup_hw_info(runtime, subs);
return 0; return 0;
} }
...@@ -1189,6 +1188,7 @@ static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction) ...@@ -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_stream_t *as = snd_pcm_substream_chip(substream);
snd_usb_substream_t *subs = &as->substream[direction]; snd_usb_substream_t *subs = &as->substream[direction];
release_substream_urbs(subs); release_substream_urbs(subs);
if (subs->interface >= 0) if (subs->interface >= 0)
usb_set_interface(subs->dev, 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, ...@@ -2171,6 +2171,10 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
for (i = 0; i < SNDRV_CARDS; i++) { for (i = 0; i < SNDRV_CARDS; i++) {
if (usb_chip[i] && usb_chip[i]->dev == dev) { if (usb_chip[i] && usb_chip[i]->dev == dev) {
chip = usb_chip[i]; 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; break;
} }
} }
...@@ -2247,14 +2251,41 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -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) static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
{ {
snd_usb_audio_t *chip; 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) if (ptr == (void *)-1)
return; return;
chip = snd_magic_cast(snd_usb_audio_t, ptr, return); chip = snd_magic_cast(snd_usb_audio_t, ptr, return);
card = chip->card;
down(&register_mutex);
chip->shutdown = 1;
chip->num_interfaces--; chip->num_interfaces--;
if (chip->num_interfaces <= 0) 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); ...@@ -2317,7 +2348,7 @@ module_exit(snd_usb_audio_cleanup);
#ifndef MODULE #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) static int __init snd_usb_audio_module_setup(char* str)
{ {
...@@ -2327,7 +2358,9 @@ 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; return 0;
(void)(get_option(&str, &enable[nr_dev]) == 2 && (void)(get_option(&str, &enable[nr_dev]) == 2 &&
get_option(&str, &index[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; ++nr_dev;
return 1; return 1;
} }
......
...@@ -133,6 +133,7 @@ struct snd_usb_audio { ...@@ -133,6 +133,7 @@ struct snd_usb_audio {
int index; int index;
struct usb_device *dev; struct usb_device *dev;
snd_card_t *card; snd_card_t *card;
int shutdown;
int num_interfaces; int num_interfaces;
struct list_head pcm_list; /* list of pcm streams */ struct list_head pcm_list; /* list of pcm streams */
......
...@@ -65,6 +65,8 @@ struct usb_mixer_build { ...@@ -65,6 +65,8 @@ struct usb_mixer_build {
unsigned char *buffer; unsigned char *buffer;
unsigned int buflen; unsigned int buflen;
unsigned int ctrlif; unsigned int ctrlif;
unsigned short vendor;
unsigned short product;
DECLARE_BITMAP(unitbitmap, 32*32); DECLARE_BITMAP(unitbitmap, 32*32);
usb_audio_term_t oterm; usb_audio_term_t oterm;
const struct usbmix_name_map *map; const struct usbmix_name_map *map;
...@@ -78,8 +80,9 @@ struct usb_mixer_elem_info { ...@@ -78,8 +80,9 @@ struct usb_mixer_elem_info {
unsigned int cmask; /* channel mask bitmap: 0 = master */ unsigned int cmask; /* channel mask bitmap: 0 = master */
int channels; int channels;
int val_type; int val_type;
int min, max; int min, max, res;
unsigned int initialized: 1; 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) ...@@ -253,15 +256,16 @@ static int get_relative_value(usb_mixer_elem_info_t *cval, int val)
if (val < cval->min) if (val < cval->min)
return 0; return 0;
else if (val > cval->max) else if (val > cval->max)
return cval->max - cval->min; return (cval->max - cval->min) / cval->res;
else else
return val - cval->min; return (val - cval->min) / cval->res;
} }
static int get_abs_value(usb_mixer_elem_info_t *cval, int val) static int get_abs_value(usb_mixer_elem_info_t *cval, int val)
{ {
if (val < 0) if (val < 0)
return cval->min; return cval->min;
val *= cval->res;
val += cval->min; val += cval->min;
if (val > cval->max) if (val > cval->max)
return cval->max; return cval->max;
...@@ -562,6 +566,7 @@ static int get_min_max(usb_mixer_elem_info_t *cval) ...@@ -562,6 +566,7 @@ static int get_min_max(usb_mixer_elem_info_t *cval)
/* for failsafe */ /* for failsafe */
cval->min = 0; cval->min = 0;
cval->max = 1; cval->max = 1;
cval->res = 1;
if (cval->val_type == USB_MIXER_BOOLEAN || if (cval->val_type == USB_MIXER_BOOLEAN ||
cval->val_type == USB_MIXER_INV_BOOLEAN) { cval->val_type == USB_MIXER_INV_BOOLEAN) {
...@@ -581,6 +586,21 @@ static int get_min_max(usb_mixer_elem_info_t *cval) ...@@ -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); 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; 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; cval->initialized = 1;
} }
return 0; return 0;
...@@ -606,7 +626,7 @@ static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t ...@@ -606,7 +626,7 @@ static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t
if (! cval->initialized) if (! cval->initialized)
get_min_max(cval); get_min_max(cval);
uinfo->value.integer.min = 0; 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; return 0;
} }
...@@ -680,6 +700,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t ...@@ -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); set_cur_mix_value(cval, c + 1, val);
changed = 1; changed = 1;
} }
get_cur_mix_value(cval, c + 1, &val);
cnt++; cnt++;
} }
} }
...@@ -812,8 +833,19 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, ...@@ -812,8 +833,19 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
break; break;
} }
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d\n", /* quirk for UDA1321/N101 */
cval->id, kctl->id.name, cval->channels, cval->min, cval->max); /* 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); 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 ...@@ -1430,6 +1462,8 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffe
state.buffer = buffer; state.buffer = buffer;
state.buflen = buflen; state.buflen = buflen;
state.ctrlif = ctrlif; state.ctrlif = ctrlif;
state.vendor = dev->idVendor;
state.product = dev->idProduct;
/* check the mapping table */ /* check the mapping table */
for (map = usbmix_ctl_maps; map->vendor; map++) { 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