diff options
Diffstat (limited to 'sound')
296 files changed, 7210 insertions, 2400 deletions
diff --git a/sound/aoa/soundbus/i2sbus/control.c b/sound/aoa/soundbus/i2sbus/control.c index 4dc9b49c02cf..f4495decc699 100644 --- a/sound/aoa/soundbus/i2sbus/control.c +++ b/sound/aoa/soundbus/i2sbus/control.c @@ -9,8 +9,8 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/prom.h> #include <asm/macio.h> #include <asm/pmac_feature.h> diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 4e2b4fbf2496..b9737fae656a 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -74,10 +74,9 @@ static void i2sbus_release_dev(struct device *dev) int i; i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev); - - if (i2sdev->intfregs) iounmap(i2sdev->intfregs); - if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); - if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); + iounmap(i2sdev->intfregs); + iounmap(i2sdev->out.dbdma); + iounmap(i2sdev->in.dbdma); for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) release_and_free_resource(i2sdev->allocated_resource[i]); free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); @@ -318,9 +317,9 @@ static int i2sbus_add_dev(struct macio_dev *macio, free_irq(dev->interrupts[i], dev); free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring); free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring); - if (dev->intfregs) iounmap(dev->intfregs); - if (dev->out.dbdma) iounmap(dev->out.dbdma); - if (dev->in.dbdma) iounmap(dev->in.dbdma); + iounmap(dev->intfregs); + iounmap(dev->out.dbdma); + iounmap(dev->in.dbdma); for (i=0;i<3;i++) release_and_free_resource(dev->allocated_resource[i]); mutex_destroy(&dev->lock); @@ -381,10 +380,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) list_for_each_entry(i2sdev, &control->list, item) { /* Notify Alsa */ - if (i2sdev->sound.pcm) { - /* Suspend PCM streams */ - snd_pcm_suspend_all(i2sdev->sound.pcm); - } + /* Suspend PCM streams */ + snd_pcm_suspend_all(i2sdev->sound.pcm); /* Notify codecs */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 7b74a4ba75f8..053b09c79053 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -6,7 +6,7 @@ * GPL v2, can be found in COPYING. */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/slab.h> #include <sound/core.h> @@ -968,7 +968,6 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); goto out_put_ci_module; } - dev->pcm->dev = &dev->ofdev.dev; } /* ALSA yet again sucks. @@ -988,6 +987,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &i2sbus_playback_ops); + dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev.parent = + &dev->ofdev.dev; i2sdev->out.created = 1; } @@ -1003,6 +1004,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &i2sbus_record_ops); + dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev.parent = + &dev->ofdev.dev; i2sdev->in.created = 1; } diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 0e83a73efb16..4140b1b95054 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -889,8 +889,8 @@ static int aaci_probe_ac97(struct aaci *aaci) static void aaci_free_card(struct snd_card *card) { struct aaci *aaci = card->private_data; - if (aaci->base) - iounmap(aaci->base); + + iounmap(aaci->base); } static struct aaci *aaci_init_card(struct amba_device *dev) diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 4f6b14d704f3..cf4cedf2b420 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -22,6 +22,9 @@ #include <linux/gpio.h> #include <linux/types.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> #include <sound/core.h> #include <sound/initval.h> @@ -34,10 +37,10 @@ #include <linux/platform_data/dma-dw.h> #include <linux/dma/dw.h> +#ifdef CONFIG_AVR32 #include <mach/cpu.h> - -#ifdef CONFIG_ARCH_AT91 -#include <mach/hardware.h> +#else +#define cpu_is_at32ap7000() 0 #endif #include "ac97c.h" @@ -902,6 +905,40 @@ static void atmel_ac97c_reset(struct atmel_ac97c *chip) } } +#ifdef CONFIG_OF +static const struct of_device_id atmel_ac97c_dt_ids[] = { + { .compatible = "atmel,at91sam9263-ac97c", }, + { } +}; +MODULE_DEVICE_TABLE(of, atmel_ac97c_dt_ids); + +static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev) +{ + struct ac97c_platform_data *pdata; + struct device_node *node = dev->of_node; + const struct of_device_id *match; + + if (!node) { + dev_err(dev, "Device does not have associated DT data\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->reset_pin = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); + + return pdata; +} +#else +static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev) +{ + dev_err(dev, "no platform data defined\n"); + return ERR_PTR(-ENXIO); +} +#endif + static int atmel_ac97c_probe(struct platform_device *pdev) { struct snd_card *card; @@ -922,10 +959,11 @@ static int atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; } - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { - dev_dbg(&pdev->dev, "no platform data\n"); - return -ENXIO; + pdata = atmel_ac97c_probe_dt(&pdev->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } irq = platform_get_irq(pdev, 0); @@ -1204,6 +1242,7 @@ static struct platform_driver atmel_ac97c_driver = { .driver = { .name = "atmel_ac97c", .pm = ATMEL_AC97C_PM_OPS, + .of_match_table = of_match_ptr(atmel_ac97c_dt_ids), }, }; module_platform_driver(atmel_ac97c_driver); diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 89028fab64fd..b123c42e7dc8 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -868,12 +868,12 @@ static int snd_compress_dev_register(struct snd_device *device) return -EBADFD; compr = device->device_data; - sprintf(str, "comprC%iD%i", compr->card->number, compr->device); pr_debug("reg %s for device %s, direction %d\n", str, compr->name, compr->direction); /* register compressed device */ - ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card, - compr->device, &snd_compr_file_ops, compr, str); + ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, + compr->card, compr->device, + &snd_compr_file_ops, compr, &compr->dev); if (ret < 0) { pr_err("snd_register_device failed\n %d", ret); return ret; @@ -887,8 +887,16 @@ static int snd_compress_dev_disconnect(struct snd_device *device) struct snd_compr *compr; compr = device->device_data; - snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card, - compr->device); + snd_unregister_device(&compr->dev); + return 0; +} + +static int snd_compress_dev_free(struct snd_device *device) +{ + struct snd_compr *compr; + + compr = device->device_data; + put_device(&compr->dev); return 0; } @@ -903,7 +911,7 @@ int snd_compress_new(struct snd_card *card, int device, int dirn, struct snd_compr *compr) { static struct snd_device_ops ops = { - .dev_free = NULL, + .dev_free = snd_compress_dev_free, .dev_register = snd_compress_dev_register, .dev_disconnect = snd_compress_dev_disconnect, }; @@ -911,6 +919,10 @@ int snd_compress_new(struct snd_card *card, int device, compr->card = card; compr->device = device; compr->direction = dirn; + + snd_device_initialize(&compr->dev, card); + dev_set_name(&compr->dev, "comprC%iD%i", card->number, device); + return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); } EXPORT_SYMBOL_GPL(snd_compress_new); @@ -948,7 +960,7 @@ int snd_compress_register(struct snd_compr *device) { int retval; - if (device->name == NULL || device->dev == NULL || device->ops == NULL) + if (device->name == NULL || device->ops == NULL) return -EINVAL; pr_debug("Registering compressed device %s\n", device->name); diff --git a/sound/core/control.c b/sound/core/control.c index bb96a467e88d..35324a8e83c8 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -50,7 +50,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) unsigned long flags; struct snd_card *card; struct snd_ctl_file *ctl; - int err; + int i, err; err = nonseekable_open(inode, file); if (err < 0) @@ -79,8 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) init_waitqueue_head(&ctl->change_sleep); spin_lock_init(&ctl->read_lock); ctl->card = card; - ctl->prefer_pcm_subdevice = -1; - ctl->prefer_rawmidi_subdevice = -1; + for (i = 0; i < SND_CTL_SUBDEV_ITEMS; i++) + ctl->preferred_subdevice[i] = -1; ctl->pid = get_pid(task_pid(current)); file->private_data = ctl; write_lock_irqsave(&card->ctl_files_rwlock, flags); @@ -373,6 +373,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) card->controls_count += kcontrol->count; kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; + id = kcontrol->id; count = kcontrol->count; up_write(&card->controls_rwsem); for (idx = 0; idx < count; idx++, id.index++, id.numid++) @@ -439,6 +440,7 @@ add: card->controls_count += kcontrol->count; kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; + id = kcontrol->id; count = kcontrol->count; up_write(&card->controls_rwsem); for (idx = 0; idx < count; idx++, id.index++, id.numid++) @@ -1607,6 +1609,27 @@ static int snd_ctl_fasync(int fd, struct file * file, int on) return fasync_helper(fd, file, on, &ctl->fasync); } +/* return the preferred subdevice number if already assigned; + * otherwise return -1 + */ +int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type) +{ + struct snd_ctl_file *kctl; + int subdevice = -1; + + read_lock(&card->ctl_files_rwlock); + list_for_each_entry(kctl, &card->ctl_files, list) { + if (kctl->pid == task_pid(current)) { + subdevice = kctl->preferred_subdevice[type]; + if (subdevice != -1) + break; + } + } + read_unlock(&card->ctl_files_rwlock); + return subdevice; +} +EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice); + /* * ioctl32 compat */ @@ -1639,19 +1662,9 @@ static const struct file_operations snd_ctl_f_ops = static int snd_ctl_dev_register(struct snd_device *device) { struct snd_card *card = device->device_data; - int err, cardnum; - char name[16]; - if (snd_BUG_ON(!card)) - return -ENXIO; - cardnum = card->number; - if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS)) - return -ENXIO; - sprintf(name, "controlC%i", cardnum); - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, - &snd_ctl_f_ops, card, name)) < 0) - return err; - return 0; + return snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, + &snd_ctl_f_ops, card, &card->ctl_dev); } /* @@ -1661,13 +1674,6 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) { struct snd_card *card = device->device_data; struct snd_ctl_file *ctl; - int err, cardnum; - - if (snd_BUG_ON(!card)) - return -ENXIO; - cardnum = card->number; - if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS)) - return -ENXIO; read_lock(&card->ctl_files_rwlock); list_for_each_entry(ctl, &card->ctl_files, list) { @@ -1676,10 +1682,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) } read_unlock(&card->ctl_files_rwlock); - if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, - card, -1)) < 0) - return err; - return 0; + return snd_unregister_device(&card->ctl_dev); } /* @@ -1696,6 +1699,7 @@ static int snd_ctl_dev_free(struct snd_device *device) snd_ctl_remove(card, control); } up_write(&card->controls_rwsem); + put_device(&card->ctl_dev); return 0; } @@ -1710,10 +1714,20 @@ int snd_ctl_create(struct snd_card *card) .dev_register = snd_ctl_dev_register, .dev_disconnect = snd_ctl_dev_disconnect, }; + int err; if (snd_BUG_ON(!card)) return -ENXIO; - return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); + if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS)) + return -ENXIO; + + snd_device_initialize(&card->ctl_dev, card); + dev_set_name(&card->ctl_dev, "controlC%d", card->number); + + err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); + if (err < 0) + put_device(&card->ctl_dev); + return err; } /* diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 69459e5f712e..84244a5143cf 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -38,7 +38,6 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(snd_hwdep_devices); static DEFINE_MUTEX(register_mutex); -static int snd_hwdep_free(struct snd_hwdep *hwdep); static int snd_hwdep_dev_free(struct snd_device *device); static int snd_hwdep_dev_register(struct snd_device *device); static int snd_hwdep_dev_disconnect(struct snd_device *device); @@ -345,6 +344,11 @@ static const struct file_operations snd_hwdep_f_ops = .mmap = snd_hwdep_mmap, }; +static void release_hwdep_device(struct device *dev) +{ + kfree(container_of(dev, struct snd_hwdep, dev)); +} + /** * snd_hwdep_new - create a new hwdep instance * @card: the card instance @@ -378,48 +382,49 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, dev_err(card->dev, "hwdep: cannot allocate\n"); return -ENOMEM; } + + init_waitqueue_head(&hwdep->open_wait); + mutex_init(&hwdep->open_mutex); hwdep->card = card; hwdep->device = device; if (id) strlcpy(hwdep->id, id, sizeof(hwdep->id)); + + snd_device_initialize(&hwdep->dev, card); + hwdep->dev.release = release_hwdep_device; + dev_set_name(&hwdep->dev, "hwC%iD%i", card->number, device); #ifdef CONFIG_SND_OSSEMUL hwdep->oss_type = -1; #endif - if ((err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)) < 0) { - snd_hwdep_free(hwdep); + + err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops); + if (err < 0) { + put_device(&hwdep->dev); return err; } - init_waitqueue_head(&hwdep->open_wait); - mutex_init(&hwdep->open_mutex); + if (rhwdep) *rhwdep = hwdep; return 0; } EXPORT_SYMBOL(snd_hwdep_new); -static int snd_hwdep_free(struct snd_hwdep *hwdep) +static int snd_hwdep_dev_free(struct snd_device *device) { + struct snd_hwdep *hwdep = device->device_data; if (!hwdep) return 0; if (hwdep->private_free) hwdep->private_free(hwdep); - kfree(hwdep); + put_device(&hwdep->dev); return 0; } -static int snd_hwdep_dev_free(struct snd_device *device) -{ - struct snd_hwdep *hwdep = device->device_data; - return snd_hwdep_free(hwdep); -} - static int snd_hwdep_dev_register(struct snd_device *device) { struct snd_hwdep *hwdep = device->device_data; struct snd_card *card = hwdep->card; - struct device *dev; int err; - char name[32]; mutex_lock(®ister_mutex); if (snd_hwdep_search(card, hwdep->device)) { @@ -427,53 +432,30 @@ static int snd_hwdep_dev_register(struct snd_device *device) return -EBUSY; } list_add_tail(&hwdep->list, &snd_hwdep_devices); - sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device); - dev = hwdep->dev; - if (!dev) - dev = snd_card_get_device_link(hwdep->card); - err = snd_register_device_for_dev(SNDRV_DEVICE_TYPE_HWDEP, - hwdep->card, hwdep->device, - &snd_hwdep_f_ops, hwdep, name, dev); + err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, + hwdep->card, hwdep->device, + &snd_hwdep_f_ops, hwdep, &hwdep->dev); if (err < 0) { - dev_err(dev, - "unable to register hardware dependent device %i:%i\n", - card->number, hwdep->device); + dev_err(&hwdep->dev, "unable to register\n"); list_del(&hwdep->list); mutex_unlock(®ister_mutex); return err; } - if (hwdep->groups) { - struct device *d = snd_get_device(SNDRV_DEVICE_TYPE_HWDEP, - hwdep->card, hwdep->device); - if (d) { - if (hwdep->private_data) - dev_set_drvdata(d, hwdep->private_data); - err = sysfs_create_groups(&d->kobj, hwdep->groups); - if (err < 0) - dev_warn(dev, - "hwdep %d:%d: cannot create sysfs groups\n", - card->number, hwdep->device); - put_device(d); - } - } - #ifdef CONFIG_SND_OSSEMUL hwdep->ossreg = 0; if (hwdep->oss_type >= 0) { - if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) { - dev_warn(dev, + if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM && + hwdep->device) + dev_warn(&hwdep->dev, "only hwdep device 0 can be registered as OSS direct FM device!\n"); - } else { - if (snd_register_oss_device(hwdep->oss_type, - card, hwdep->device, - &snd_hwdep_f_ops, hwdep) < 0) { - dev_err(dev, - "unable to register OSS compatibility device %i:%i\n", - card->number, hwdep->device); - } else - hwdep->ossreg = 1; - } + else if (snd_register_oss_device(hwdep->oss_type, + card, hwdep->device, + &snd_hwdep_f_ops, hwdep) < 0) + dev_warn(&hwdep->dev, + "unable to register OSS compatibility device\n"); + else + hwdep->ossreg = 1; } #endif mutex_unlock(®ister_mutex); @@ -497,7 +479,7 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) if (hwdep->ossreg) snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); #endif - snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); + snd_unregister_device(&hwdep->dev); list_del_init(&hwdep->list); mutex_unlock(&hwdep->open_mutex); mutex_unlock(®ister_mutex); diff --git a/sound/core/init.c b/sound/core/init.c index 074875d68c15..35419054821c 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -157,8 +157,31 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int), return mask; /* unchanged */ } +/* the default release callback set in snd_device_initialize() below; + * this is just NOP for now, as almost all jobs are already done in + * dev_free callback of snd_device chain instead. + */ +static void default_release(struct device *dev) +{ +} + +/** + * snd_device_initialize - Initialize struct device for sound devices + * @dev: device to initialize + * @card: card to assign, optional + */ +void snd_device_initialize(struct device *dev, struct snd_card *card) +{ + device_initialize(dev); + if (card) + dev->parent = &card->card_dev; + dev->class = sound_class; + dev->release = default_release; +} +EXPORT_SYMBOL_GPL(snd_device_initialize); + static int snd_card_do_free(struct snd_card *card); -static const struct attribute_group *card_dev_attr_groups[]; +static const struct attribute_group card_dev_attr_group; static void release_card_device(struct device *dev) { @@ -246,7 +269,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid, card->card_dev.parent = parent; card->card_dev.class = sound_class; card->card_dev.release = release_card_device; - card->card_dev.groups = card_dev_attr_groups; + card->card_dev.groups = card->dev_groups; + card->dev_groups[0] = &card_dev_attr_group; err = kobject_set_name(&card->card_dev.kobj, "card%d", idx); if (err < 0) goto __error; @@ -677,14 +701,32 @@ static struct attribute *card_dev_attrs[] = { NULL }; -static struct attribute_group card_dev_attr_group = { +static const struct attribute_group card_dev_attr_group = { .attrs = card_dev_attrs, }; -static const struct attribute_group *card_dev_attr_groups[] = { - &card_dev_attr_group, - NULL +/** + * snd_card_add_dev_attr - Append a new sysfs attribute group to card + * @card: card instance + * @group: attribute group to append + */ +int snd_card_add_dev_attr(struct snd_card *card, + const struct attribute_group *group) +{ + int i; + + /* loop for (arraysize-1) here to keep NULL at the last entry */ + for (i = 0; i < ARRAY_SIZE(card->dev_groups) - 1; i++) { + if (!card->dev_groups[i]) { + card->dev_groups[i] = group; + return 0; + } + } + + dev_err(card->dev, "Too many groups assigned\n"); + return -ENOSPC; }; +EXPORT_SYMBOL_GPL(snd_card_add_dev_attr); /** * snd_card_register - register the soundcard diff --git a/sound/core/memory.c b/sound/core/memory.c index 36c0f1a2e189..4cd664efad77 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -21,8 +21,8 @@ */ #include <linux/export.h> -#include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/io.h> +#include <linux/uaccess.h> #include <sound/core.h> /** diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index ada69d7a8d70..80423a4ccab6 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -719,7 +719,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, oss_buffer_size = snd_pcm_plug_client_size(substream, snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size; - oss_buffer_size = 1 << ld2(oss_buffer_size); + oss_buffer_size = rounddown_pow_of_two(oss_buffer_size); if (atomic_read(&substream->mmap_count)) { if (oss_buffer_size > runtime->oss.mmap_bytes) oss_buffer_size = runtime->oss.mmap_bytes; @@ -755,14 +755,14 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, min_period_size = snd_pcm_plug_client_size(substream, snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL)); min_period_size *= oss_frame_size; - min_period_size = 1 << (ld2(min_period_size - 1) + 1); + min_period_size = roundup_pow_of_two(min_period_size); if (oss_period_size < min_period_size) oss_period_size = min_period_size; max_period_size = snd_pcm_plug_client_size(substream, snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL)); max_period_size *= oss_frame_size; - max_period_size = 1 << ld2(max_period_size); + max_period_size = rounddown_pow_of_two(max_period_size); if (oss_period_size > max_period_size) oss_period_size = max_period_size; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index cfc56c806964..0345e53a340c 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -161,7 +161,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, if (get_user(val, (int __user *)arg)) return -EFAULT; - control->prefer_pcm_subdevice = val; + control->preferred_subdevice[SND_CTL_SUBDEV_PCM] = val; return 0; } } @@ -673,6 +673,8 @@ static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substrea static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; } #endif /* CONFIG_SND_VERBOSE_PROCFS */ +static const struct attribute_group *pcm_dev_attr_groups[]; + /** * snd_pcm_new_stream - create a new PCM stream * @pcm: the pcm instance @@ -698,7 +700,15 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) pstr->stream = stream; pstr->pcm = pcm; pstr->substream_count = substream_count; - if (substream_count > 0 && !pcm->internal) { + if (!substream_count) + return 0; + + snd_device_initialize(&pstr->dev, pcm->card); + pstr->dev.groups = pcm_dev_attr_groups; + dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device, + stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); + + if (!pcm->internal) { err = snd_pcm_stream_proc_init(pstr); if (err < 0) { pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n"); @@ -868,6 +878,8 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) kfree(setup); } #endif + if (pstr->substream_count) + put_device(&pstr->dev); } static int snd_pcm_free(struct snd_pcm *pcm) @@ -901,9 +913,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct snd_pcm_str * pstr; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; - struct snd_ctl_file *kctl; struct snd_card *card; - int prefer_subdevice = -1; + int prefer_subdevice; size_t size; if (snd_BUG_ON(!pcm || !rsubstream)) @@ -914,15 +925,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, return -ENODEV; card = pcm->card; - read_lock(&card->ctl_files_rwlock); - list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == task_pid(current)) { - prefer_subdevice = kctl->prefer_pcm_subdevice; - if (prefer_subdevice != -1) - break; - } - } - read_unlock(&card->ctl_files_rwlock); + prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM); switch (stream) { case SNDRV_PCM_STREAM_PLAYBACK: @@ -1078,9 +1081,7 @@ static int snd_pcm_dev_register(struct snd_device *device) int cidx, err; struct snd_pcm_substream *substream; struct snd_pcm_notify *notify; - char str[16]; struct snd_pcm *pcm; - struct device *dev; if (snd_BUG_ON(!device || !device->device_data)) return -ENXIO; @@ -1097,42 +1098,22 @@ static int snd_pcm_dev_register(struct snd_device *device) continue; switch (cidx) { case SNDRV_PCM_STREAM_PLAYBACK: - sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device); devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK; break; case SNDRV_PCM_STREAM_CAPTURE: - sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device); devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; break; } - /* device pointer to use, pcm->dev takes precedence if - * it is assigned, otherwise fall back to card's device - * if possible */ - dev = pcm->dev; - if (!dev) - dev = snd_card_get_device_link(pcm->card); /* register pcm */ - err = snd_register_device_for_dev(devtype, pcm->card, - pcm->device, - &snd_pcm_f_ops[cidx], - pcm, str, dev); + err = snd_register_device(devtype, pcm->card, pcm->device, + &snd_pcm_f_ops[cidx], pcm, + &pcm->streams[cidx].dev); if (err < 0) { list_del(&pcm->list); mutex_unlock(®ister_mutex); return err; } - dev = snd_get_device(devtype, pcm->card, pcm->device); - if (dev) { - err = sysfs_create_groups(&dev->kobj, - pcm_dev_attr_groups); - if (err < 0) - dev_warn(dev, - "pcm %d:%d: cannot create sysfs groups\n", - pcm->card->number, pcm->device); - put_device(dev); - } - for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) snd_pcm_timer_init(substream); } @@ -1149,7 +1130,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) struct snd_pcm *pcm = device->device_data; struct snd_pcm_notify *notify; struct snd_pcm_substream *substream; - int cidx, devtype; + int cidx; mutex_lock(®ister_mutex); if (list_empty(&pcm->list)) @@ -1172,16 +1153,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) notify->n_disconnect(pcm); } for (cidx = 0; cidx < 2; cidx++) { - devtype = -1; - switch (cidx) { - case SNDRV_PCM_STREAM_PLAYBACK: - devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK; - break; - case SNDRV_PCM_STREAM_CAPTURE: - devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; - break; - } - snd_unregister_device(devtype, pcm->card, pcm->device); + snd_unregister_device(&pcm->streams[cidx].dev); if (pcm->streams[cidx].chmap_kctl) { snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); pcm->streams[cidx].chmap_kctl = NULL; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 446c00bd908b..ffd656012ab8 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1384,8 +1384,14 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, int width = l & 0xffff; unsigned int msbits = l >> 16; struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - if (snd_interval_single(i) && snd_interval_value(i) == width) - params->msbits = msbits; + + if (!snd_interval_single(i)) + return 0; + + if ((snd_interval_value(i) == width) || + (width == 0 && snd_interval_value(i) > msbits)) + params->msbits = min_not_zero(params->msbits, msbits); + return 0; } @@ -1396,6 +1402,11 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, * @width: sample bits width * @msbits: msbits width * + * This constraint will set the number of most significant bits (msbits) if a + * sample format with the specified width has been select. If width is set to 0 + * the msbits will be set for any sample format with a width larger than the + * specified msbits. + * * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 54debc07f5cb..b45f6aa32264 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -19,7 +19,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/time.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 095d9572ad2b..279e24f61305 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -26,6 +26,7 @@ #include <linux/time.h> #include <linux/pm_qos.h> #include <linux/aio.h> +#include <linux/io.h> #include <linux/dma-mapping.h> #include <sound/core.h> #include <sound/control.h> @@ -34,7 +35,6 @@ #include <sound/pcm_params.h> #include <sound/timer.h> #include <sound/minors.h> -#include <asm/io.h> /* * Compatibility @@ -420,7 +420,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, hw = &substream->runtime->hw; if (!params->info) { - params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; + params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | + SNDRV_PCM_INFO_DRAIN_TRIGGER); if (!hw_support_mmap(substream)) params->info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); @@ -719,8 +720,11 @@ int snd_pcm_status(struct snd_pcm_substream *substream, runtime->status->audio_tstamp; goto _tstamp_end; } + } else { + /* get tstamp only in fallback mode and only if enabled */ + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, &status->tstamp); } - snd_pcm_gettime(runtime, &status->tstamp); _tstamp_end: status->appl_ptr = runtime->control->appl_ptr; status->hw_ptr = runtime->status->hw_ptr; @@ -806,7 +810,8 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream) if (runtime->trigger_master == NULL) return; if (runtime->trigger_master == substream) { - snd_pcm_gettime(runtime, &runtime->trigger_tstamp); + if (!runtime->trigger_tstamp_latched) + snd_pcm_gettime(runtime, &runtime->trigger_tstamp); } else { snd_pcm_trigger_tstamp(runtime->trigger_master); runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; @@ -975,6 +980,7 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !snd_pcm_playback_data(substream)) return -EPIPE; + runtime->trigger_tstamp_latched = false; runtime->trigger_master = substream; return 0; } @@ -1546,6 +1552,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) if (! snd_pcm_playback_empty(substream)) { snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); + } else { + runtime->status->state = SNDRV_PCM_STATE_SETUP; } break; case SNDRV_PCM_STATE_RUNNING: @@ -1566,6 +1574,13 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) snd_pcm_post_stop(substream, new_state); } } + + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && + runtime->trigger_master == substream && + (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER)) + return substream->ops->trigger(substream, + SNDRV_PCM_TRIGGER_DRAIN); + return 0; } diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 6fc71a4c8a51..b5a748596fc4 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -57,11 +57,11 @@ static LIST_HEAD(snd_rawmidi_devices); static DEFINE_MUTEX(register_mutex); #define rmidi_err(rmidi, fmt, args...) \ - dev_err((rmidi)->card->dev, fmt, ##args) + dev_err(&(rmidi)->dev, fmt, ##args) #define rmidi_warn(rmidi, fmt, args...) \ - dev_warn((rmidi)->card->dev, fmt, ##args) + dev_warn(&(rmidi)->dev, fmt, ##args) #define rmidi_dbg(rmidi, fmt, args...) \ - dev_dbg((rmidi)->card->dev, fmt, ##args) + dev_dbg(&(rmidi)->dev, fmt, ##args) static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) { @@ -369,7 +369,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) struct snd_rawmidi *rmidi; struct snd_rawmidi_file *rawmidi_file = NULL; wait_queue_t wait; - struct snd_ctl_file *kctl; if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) return -EINVAL; /* invalid combination */ @@ -413,16 +412,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) init_waitqueue_entry(&wait, current); add_wait_queue(&rmidi->open_wait, &wait); while (1) { - subdevice = -1; - read_lock(&card->ctl_files_rwlock); - list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == task_pid(current)) { - subdevice = kctl->prefer_rawmidi_subdevice; - if (subdevice != -1) - break; - } - } - read_unlock(&card->ctl_files_rwlock); + subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_RAWMIDI); err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file); if (err >= 0) break; @@ -862,7 +852,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, if (get_user(val, (int __user *)argp)) return -EFAULT; - control->prefer_rawmidi_subdevice = val; + control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val; return 0; } case SNDRV_CTL_IOCTL_RAWMIDI_INFO: @@ -1453,6 +1443,11 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, return 0; } +static void release_rawmidi_device(struct device *dev) +{ + kfree(container_of(dev, struct snd_rawmidi, dev)); +} + /** * snd_rawmidi_new - create a rawmidi instance * @card: the card instance @@ -1497,6 +1492,11 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, if (id != NULL) strlcpy(rmidi->id, id, sizeof(rmidi->id)); + + snd_device_initialize(&rmidi->dev, card); + rmidi->dev.release = release_rawmidi_device; + dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device); + if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, @@ -1548,7 +1548,7 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi) snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); if (rmidi->private_free) rmidi->private_free(rmidi); - kfree(rmidi); + put_device(&rmidi->dev); return 0; } @@ -1581,19 +1581,18 @@ static int snd_rawmidi_dev_register(struct snd_device *device) return -EBUSY; } list_add_tail(&rmidi->list, &snd_rawmidi_devices); - sprintf(name, "midiC%iD%i", rmidi->card->number, rmidi->device); - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, - rmidi->card, rmidi->device, - &snd_rawmidi_f_ops, rmidi, name)) < 0) { - rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n", - rmidi->card->number, rmidi->device); + err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, + rmidi->card, rmidi->device, + &snd_rawmidi_f_ops, rmidi, &rmidi->dev); + if (err < 0) { + rmidi_err(rmidi, "unable to register\n"); list_del(&rmidi->list); mutex_unlock(®ister_mutex); return err; } if (rmidi->ops && rmidi->ops->dev_register && (err = rmidi->ops->dev_register(rmidi)) < 0) { - snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); + snd_unregister_device(&rmidi->dev); list_del(&rmidi->list); mutex_unlock(®ister_mutex); return err; @@ -1681,7 +1680,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) rmidi->ossreg = 0; } #endif /* CONFIG_SND_OSSEMUL */ - snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); + snd_unregister_device(&rmidi->dev); mutex_unlock(&rmidi->open_mutex); mutex_unlock(®ister_mutex); return 0; diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 3a4569669efa..e79cc44b1394 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -237,8 +237,7 @@ snd_seq_oss_midi_check_exit_port(int client, int port) spin_unlock_irqrestore(®ister_lock, flags); snd_use_lock_free(&mdev->use_lock); snd_use_lock_sync(&mdev->use_lock); - if (mdev->coder) - snd_midi_event_free(mdev->coder); + snd_midi_event_free(mdev->coder); kfree(mdev); } spin_lock_irqsave(®ister_lock, flags); @@ -265,8 +264,7 @@ snd_seq_oss_midi_clear_all(void) spin_lock_irqsave(®ister_lock, flags); for (i = 0; i < max_midi_devs; i++) { if ((mdev = midi_devs[i]) != NULL) { - if (mdev->coder) - snd_midi_event_free(mdev->coder); + snd_midi_event_free(mdev->coder); kfree(mdev); midi_devs[i] = NULL; } diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 225c73152ee9..48287651ac77 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1133,7 +1133,7 @@ static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void __user /* fill the info fields */ info.queues = SNDRV_SEQ_MAX_QUEUES; info.clients = SNDRV_SEQ_MAX_CLIENTS; - info.ports = 256; /* fixed limit */ + info.ports = SNDRV_SEQ_MAX_PORTS; info.channels = 256; /* fixed limit */ info.cur_clients = client_usage.cur; info.cur_queues = snd_seq_queue_get_cur_queues(); @@ -1279,7 +1279,6 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, port->owner = callback->owner; port->private_data = callback->private_data; port->private_free = callback->private_free; - port->callback_all = callback->callback_all; port->event_input = callback->event_input; port->c_src.open = callback->subscribe; port->c_src.close = callback->unsubscribe; @@ -2571,6 +2570,8 @@ static const struct file_operations snd_seq_f_ops = .compat_ioctl = snd_seq_ioctl_compat, }; +static struct device seq_dev; + /* * register sequencer device */ @@ -2578,12 +2579,17 @@ int __init snd_sequencer_device_init(void) { int err; + snd_device_initialize(&seq_dev, NULL); + dev_set_name(&seq_dev, "seq"); + if (mutex_lock_interruptible(®ister_mutex)) return -ERESTARTSYS; - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, - &snd_seq_f_ops, NULL, "seq")) < 0) { + err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, + &snd_seq_f_ops, NULL, &seq_dev); + if (err < 0) { mutex_unlock(®ister_mutex); + put_device(&seq_dev); return err; } @@ -2599,5 +2605,6 @@ int __init snd_sequencer_device_init(void) */ void __exit snd_sequencer_device_done(void) { - snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0); + snd_unregister_device(&seq_dev); + put_device(&seq_dev); } diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index a1fd77af6059..68fec776da26 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -268,8 +268,7 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth) snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port); } - if (msynth->parser) - snd_midi_event_free(msynth->parser); + snd_midi_event_free(msynth->parser); } /* register new midi synth port */ diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c index 9b6470cdcf24..7ba937399ac7 100644 --- a/sound/core/seq/seq_midi_emul.c +++ b/sound/core/seq/seq_midi_emul.c @@ -269,6 +269,9 @@ do_control(struct snd_midi_op *ops, void *drv, struct snd_midi_channel_set *chse { int i; + if (control >= ARRAY_SIZE(chan->control)) + return; + /* Switches */ if ((control >=64 && control <=69) || (control >= 80 && control <= 83)) { /* These are all switches; either off or on so set to 0 or 127 */ diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 794a341bf0e5..46ff593f618d 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -134,7 +134,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, if (snd_BUG_ON(!client)) return NULL; - if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) { + if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) { pr_warn("ALSA: seq: too many ports for client %d\n", client->number); return NULL; } @@ -411,9 +411,6 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port, * invoked. * This feature is useful if these callbacks are associated with * initialization or termination of devices (see seq_midi.c). - * - * If callback_all option is set, the callback function is invoked - * at each connection/disconnection. */ static int subscribe_port(struct snd_seq_client *client, @@ -427,7 +424,7 @@ static int subscribe_port(struct snd_seq_client *client, if (!try_module_get(port->owner)) return -EFAULT; grp->count++; - if (grp->open && (port->callback_all || grp->count == 1)) { + if (grp->open && grp->count == 1) { err = grp->open(port->private_data, info); if (err < 0) { module_put(port->owner); @@ -452,7 +449,7 @@ static int unsubscribe_port(struct snd_seq_client *client, if (! grp->count) return -EINVAL; grp->count--; - if (grp->close && (port->callback_all || grp->count == 0)) + if (grp->close && grp->count == 0) err = grp->close(port->private_data, info); if (send_ack && client->type == USER_CLIENT) snd_seq_client_notify_subscription(port->addr.client, port->addr.port, diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h index 9d7117118ba4..26bd71f36c41 100644 --- a/sound/core/seq/seq_ports.h +++ b/sound/core/seq/seq_ports.h @@ -73,7 +73,6 @@ struct snd_seq_client_port { int atomic, int hop); void (*private_free)(void *private_data); void *private_data; - unsigned int callback_all : 1; unsigned int closing : 1; unsigned int timestamping: 1; unsigned int time_real: 1; diff --git a/sound/core/sound.c b/sound/core/sound.c index f1333060bf1c..185cec01ee25 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -242,30 +242,30 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) #endif /** - * snd_register_device_for_dev - Register the ALSA device file for the card + * snd_register_device - Register the ALSA device file for the card * @type: the device type, SNDRV_DEVICE_TYPE_XXX * @card: the card instance * @dev: the device index * @f_ops: the file operations * @private_data: user pointer for f_ops->open() - * @name: the device file name - * @device: the &struct device to link this new device to + * @device: the device to register * * Registers an ALSA device file for the given card. * The operators have to be set in reg parameter. * * Return: Zero if successful, or a negative error code on failure. */ -int snd_register_device_for_dev(int type, struct snd_card *card, int dev, - const struct file_operations *f_ops, - void *private_data, - const char *name, struct device *device) +int snd_register_device(int type, struct snd_card *card, int dev, + const struct file_operations *f_ops, + void *private_data, struct device *device) { int minor; + int err = 0; struct snd_minor *preg; - if (snd_BUG_ON(!name)) + if (snd_BUG_ON(!device)) return -EINVAL; + preg = kmalloc(sizeof *preg, GFP_KERNEL); if (preg == NULL) return -ENOMEM; @@ -284,102 +284,56 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, minor = -EBUSY; #endif if (minor < 0) { - mutex_unlock(&sound_mutex); - kfree(preg); - return minor; - } - snd_minors[minor] = preg; - preg->dev = device_create(sound_class, device, MKDEV(major, minor), - private_data, "%s", name); - if (IS_ERR(preg->dev)) { - snd_minors[minor] = NULL; - mutex_unlock(&sound_mutex); - minor = PTR_ERR(preg->dev); - kfree(preg); - return minor; + err = minor; + goto error; } - mutex_unlock(&sound_mutex); - return 0; -} - -EXPORT_SYMBOL(snd_register_device_for_dev); - -/* find the matching minor record - * return the index of snd_minor, or -1 if not found - */ -static int find_snd_minor(int type, struct snd_card *card, int dev) -{ - int cardnum, minor; - struct snd_minor *mptr; + preg->dev = device; + device->devt = MKDEV(major, minor); + err = device_add(device); + if (err < 0) + goto error; - cardnum = card ? card->number : -1; - for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) - if ((mptr = snd_minors[minor]) != NULL && - mptr->type == type && - mptr->card == cardnum && - mptr->device == dev) - return minor; - return -1; + snd_minors[minor] = preg; + error: + mutex_unlock(&sound_mutex); + if (err < 0) + kfree(preg); + return err; } +EXPORT_SYMBOL(snd_register_device); /** * snd_unregister_device - unregister the device on the given card - * @type: the device type, SNDRV_DEVICE_TYPE_XXX - * @card: the card instance - * @dev: the device index + * @dev: the device instance * * Unregisters the device file already registered via * snd_register_device(). * * Return: Zero if successful, or a negative error code on failure. */ -int snd_unregister_device(int type, struct snd_card *card, int dev) +int snd_unregister_device(struct device *dev) { int minor; + struct snd_minor *preg; mutex_lock(&sound_mutex); - minor = find_snd_minor(type, card, dev); - if (minor < 0) { - mutex_unlock(&sound_mutex); - return -EINVAL; + for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { + preg = snd_minors[minor]; + if (preg && preg->dev == dev) { + snd_minors[minor] = NULL; + device_del(dev); + kfree(preg); + break; + } } - - device_destroy(sound_class, MKDEV(major, minor)); - - kfree(snd_minors[minor]); - snd_minors[minor] = NULL; mutex_unlock(&sound_mutex); + if (minor >= ARRAY_SIZE(snd_minors)) + return -ENOENT; return 0; } - EXPORT_SYMBOL(snd_unregister_device); -/** - * snd_get_device - get the assigned device to the given type and device number - * @type: the device type, SNDRV_DEVICE_TYPE_XXX - * @card:the card instance - * @dev: the device index - * - * The caller needs to release it via put_device() after using it. - */ -struct device *snd_get_device(int type, struct snd_card *card, int dev) -{ - int minor; - struct device *d = NULL; - - mutex_lock(&sound_mutex); - minor = find_snd_minor(type, card, dev); - if (minor >= 0) { - d = snd_minors[minor]->dev; - if (d) - get_device(d); - } - mutex_unlock(&sound_mutex); - return d; -} -EXPORT_SYMBOL(snd_get_device); - #ifdef CONFIG_PROC_FS /* * INFO PART diff --git a/sound/core/timer.c b/sound/core/timer.c index 777a45e08e53..490b489d713d 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1030,9 +1030,7 @@ static int snd_timer_register_system(void) snd_timer_free(timer); return -ENOMEM; } - init_timer(&priv->tlist); - priv->tlist.function = snd_timer_s_function; - priv->tlist.data = (unsigned long) timer; + setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer); timer->private_data = priv; timer->private_free = snd_timer_free_system; return snd_timer_global_register(timer); @@ -1942,6 +1940,17 @@ static const struct file_operations snd_timer_f_ops = .fasync = snd_timer_user_fasync, }; +/* unregister the system timer */ +static void snd_timer_free_all(void) +{ + struct snd_timer *timer, *n; + + list_for_each_entry_safe(timer, n, &snd_timer_list, device_list) + snd_timer_free(timer); +} + +static struct device timer_dev; + /* * ENTRY functions */ @@ -1950,30 +1959,39 @@ static int __init alsa_timer_init(void) { int err; + snd_device_initialize(&timer_dev, NULL); + dev_set_name(&timer_dev, "timer"); + #ifdef SNDRV_OSS_INFO_DEV_TIMERS snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer"); #endif - if ((err = snd_timer_register_system()) < 0) + err = snd_timer_register_system(); + if (err < 0) { pr_err("ALSA: unable to register system timer (%i)\n", err); - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, - &snd_timer_f_ops, NULL, "timer")) < 0) + put_device(&timer_dev); + return err; + } + + err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, + &snd_timer_f_ops, NULL, &timer_dev); + if (err < 0) { pr_err("ALSA: unable to register timer device (%i)\n", err); + snd_timer_free_all(); + put_device(&timer_dev); + return err; + } + snd_timer_proc_init(); return 0; } static void __exit alsa_timer_exit(void) { - struct list_head *p, *n; - - snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0); - /* unregister the system timer */ - list_for_each_safe(p, n, &snd_timer_list) { - struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); - snd_timer_free(timer); - } + snd_unregister_device(&timer_dev); + snd_timer_free_all(); + put_device(&timer_dev); snd_timer_proc_done(); #ifdef SNDRV_OSS_INFO_DEV_TIMERS snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1); diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 7ea53399404d..7f9126efc1e5 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -181,8 +181,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) } tick = dpcm->period_size_frac - dpcm->irq_pos; tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; - dpcm->timer.expires = jiffies + tick; - add_timer(&dpcm->timer); + mod_timer(&dpcm->timer, jiffies + tick); } /* call in cable->lock */ diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 5d0dfb787cec..d11baaf0f0b4 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -245,9 +245,8 @@ struct dummy_systimer_pcm { static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm) { - dpcm->timer.expires = jiffies + - (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate; - add_timer(&dpcm->timer); + mod_timer(&dpcm->timer, jiffies + + (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate); } static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm) @@ -340,9 +339,8 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream) if (!dpcm) return -ENOMEM; substream->runtime->private_data = dpcm; - init_timer(&dpcm->timer); - dpcm->timer.data = (unsigned long) dpcm; - dpcm->timer.function = dummy_systimer_callback; + setup_timer(&dpcm->timer, dummy_systimer_callback, + (unsigned long) dpcm); spin_lock_init(&dpcm->lock); dpcm->substream = substream; return 0; diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index bcca825a1c8d..bdcb5721393b 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/sound/drivers/ml403-ac97cr.c @@ -1094,8 +1094,7 @@ static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr) if (ml403_ac97cr->capture_irq >= 0) free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr); /* give back "port" */ - if (ml403_ac97cr->port != NULL) - iounmap(ml403_ac97cr->port); + iounmap(ml403_ac97cr->port); kfree(ml403_ac97cr); PDEBUG(INIT_INFO, "free(): (done)\n"); return 0; @@ -1238,14 +1237,11 @@ snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) } static int -snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, - struct snd_pcm **rpcm) +snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1, &pcm); if (err < 0) @@ -1263,8 +1259,6 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, snd_dma_continuous_data(GFP_KERNEL), 64 * 1024, 128 * 1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1298,7 +1292,7 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev) return err; } PDEBUG(INIT_INFO, "probe(): mixer done\n"); - err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL); + err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0); if (err < 0) { snd_card_free(card); return err; diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index e3a90d043f03..776596b5ee05 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -28,7 +28,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/slab.h> @@ -176,8 +176,7 @@ static void snd_mpu401_uart_timer(unsigned long data) spin_lock_irqsave(&mpu->timer_lock, flags); /*mpu->mode |= MPU401_MODE_TIMER;*/ - mpu->timer.expires = 1 + jiffies; - add_timer(&mpu->timer); + mod_timer(&mpu->timer, 1 + jiffies); spin_unlock_irqrestore(&mpu->timer_lock, flags); if (mpu->rmidi) _snd_mpu401_uart_interrupt(mpu); @@ -192,11 +191,9 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) spin_lock_irqsave (&mpu->timer_lock, flags); if (mpu->timer_invoked == 0) { - init_timer(&mpu->timer); - mpu->timer.data = (unsigned long)mpu; - mpu->timer.function = snd_mpu401_uart_timer; - mpu->timer.expires = 1 + jiffies; - add_timer(&mpu->timer); + setup_timer(&mpu->timer, snd_mpu401_uart_timer, + (unsigned long)mpu); + mod_timer(&mpu->timer, 1 + jiffies); } mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : MPU401_MODE_OUTPUT_TIMER; diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 15769447688f..30e8a1d5bc87 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -414,8 +414,7 @@ static void snd_mtpav_output_timer(unsigned long data) spin_lock_irqsave(&chip->spinlock, flags); /* reprogram timer */ - chip->timer.expires = 1 + jiffies; - add_timer(&chip->timer); + mod_timer(&chip->timer, 1 + jiffies); /* process each port */ for (p = 0; p <= chip->num_ports * 2 + MTPAV_PIDX_BROADCAST; p++) { struct mtpav_port *portp = &chip->ports[p]; @@ -428,8 +427,7 @@ static void snd_mtpav_output_timer(unsigned long data) /* spinlock held! */ static void snd_mtpav_add_output_timer(struct mtpav *chip) { - chip->timer.expires = 1 + jiffies; - add_timer(&chip->timer); + mod_timer(&chip->timer, 1 + jiffies); } /* spinlock held! */ @@ -704,15 +702,13 @@ static int snd_mtpav_probe(struct platform_device *dev) mtp_card = card->private_data; spin_lock_init(&mtp_card->spinlock); - init_timer(&mtp_card->timer); mtp_card->card = card; mtp_card->irq = -1; mtp_card->share_irq = 0; mtp_card->inmidistate = 0; mtp_card->outmidihwport = 0xffffffff; - init_timer(&mtp_card->timer); - mtp_card->timer.function = snd_mtpav_output_timer; - mtp_card->timer.data = (unsigned long) mtp_card; + setup_timer(&mtp_card->timer, snd_mtpav_output_timer, + (unsigned long) mtp_card); card->private_free = snd_mtpav_free; diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index f66af5884c40..369cef212ea9 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -24,7 +24,7 @@ */ #include <sound/opl3.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/init.h> diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index 6c6d09a51f42..f62780ed64ad 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c @@ -258,12 +258,10 @@ void snd_opl3_timer_func(unsigned long data) spin_unlock_irqrestore(&opl3->voice_lock, flags); spin_lock_irqsave(&opl3->sys_timer_lock, flags); - if (again) { - opl3->tlist.expires = jiffies + 1; /* invoke again */ - add_timer(&opl3->tlist); - } else { + if (again) + mod_timer(&opl3->tlist, jiffies + 1); /* invoke again */ + else opl3->sys_timer_status = 0; - } spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); } @@ -275,8 +273,7 @@ static void snd_opl3_start_timer(struct snd_opl3 *opl3) unsigned long flags; spin_lock_irqsave(&opl3->sys_timer_lock, flags); if (! opl3->sys_timer_status) { - opl3->tlist.expires = jiffies + 1; - add_timer(&opl3->tlist); + mod_timer(&opl3->tlist, jiffies + 1); opl3->sys_timer_status = 1; } spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index 68399538e435..a9f618e06a22 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -247,9 +247,7 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev) } /* setup system timer */ - init_timer(&opl3->tlist); - opl3->tlist.function = snd_opl3_timer_func; - opl3->tlist.data = (unsigned long) opl3; + setup_timer(&opl3->tlist, snd_opl3_timer_func, (unsigned long) opl3); spin_lock_init(&opl3->sys_timer_lock); opl3->sys_timer_status = 0; diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index b953fb4aa298..3b0ee42a5343 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -23,7 +23,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); MODULE_DESCRIPTION("OPL4 driver"); diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c index 4b91adc0238c..7bc1e58c95aa 100644 --- a/sound/drivers/opl4/opl4_synth.c +++ b/sound/drivers/opl4/opl4_synth.c @@ -33,7 +33,7 @@ #include "opl4_local.h" #include <linux/delay.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/asoundef.h> /* GM2 controllers */ diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 2adc7548ffca..d9647bd84d0f 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -13,7 +13,7 @@ #include <sound/pcm.h> #include <linux/input.h> #include <linux/delay.h> -#include <asm/bitops.h> +#include <linux/bitops.h> #include "pcsp_input.h" #include "pcsp.h" diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c index 0ecf8a453e01..bfc25811985f 100644 --- a/sound/drivers/pcsp/pcsp_input.c +++ b/sound/drivers/pcsp/pcsp_input.c @@ -14,7 +14,7 @@ #include <linux/init.h> #include <linux/input.h> -#include <asm/io.h> +#include <linux/io.h> #include "pcsp.h" #include "pcsp_input.h" diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 29ebaa4ec0fd..3689f5f6be64 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -10,8 +10,8 @@ #include <linux/gfp.h> #include <linux/moduleparam.h> #include <linux/interrupt.h> +#include <linux/io.h> #include <sound/pcm.h> -#include <asm/io.h> #include "pcsp.h" static bool nforce_wa; diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 13a34e3c6382..1927b89e1d1f 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -37,6 +37,7 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/rawmidi.h> #include <sound/initval.h> @@ -44,8 +45,6 @@ #include <linux/serial_reg.h> #include <linux/jiffies.h> -#include <asm/io.h> - MODULE_DESCRIPTION("MIDI serial u16550"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ALSA, MIDI serial u16550}}"); @@ -174,9 +173,8 @@ static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart) { if (!uart->timer_running) { /* timer 38600bps * 10bit * 16byte */ - uart->buffer_timer.expires = jiffies + (HZ+255)/256; + mod_timer(&uart->buffer_timer, jiffies + (HZ + 255) / 256); uart->timer_running = 1; - add_timer(&uart->buffer_timer); } } @@ -830,9 +828,8 @@ static int snd_uart16550_create(struct snd_card *card, uart->prev_in = 0; uart->rstatus = 0; memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS); - init_timer(&uart->buffer_timer); - uart->buffer_timer.function = snd_uart16550_buffer_timer; - uart->buffer_timer.data = (unsigned long)uart; + setup_timer(&uart->buffer_timer, snd_uart16550_buffer_timer, + (unsigned long)uart); uart->timer_running = 0; /* Register device */ diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index fc05a37fd017..289f041706cd 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -27,11 +27,11 @@ #include <linux/device.h> #include <linux/firmware.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/asoundef.h> #include <sound/info.h> -#include <asm/io.h> #include <sound/vx_core.h> #include "vx_cmd.h" diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 0d580186ef1a..5cc356db5351 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -33,7 +33,7 @@ */ #define MAX_MIDI_RX_BLOCKS 8 -#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ +#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 microseconds */ /* isochronous header parameters */ #define ISO_DATA_LENGTH_SHIFT 16 @@ -78,7 +78,7 @@ static void pcm_period_tasklet(unsigned long data); int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags) { - s->unit = fw_unit_get(unit); + s->unit = unit; s->direction = dir; s->flags = flags; s->context = ERR_PTR(-1); @@ -102,7 +102,6 @@ void amdtp_stream_destroy(struct amdtp_stream *s) { WARN_ON(amdtp_stream_running(s)); mutex_destroy(&s->mutex); - fw_unit_put(s->unit); } EXPORT_SYMBOL(amdtp_stream_destroy); diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index fc19c99654aa..611b7dae7ee5 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -116,11 +116,22 @@ end: return err; } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void bebob_card_free(struct snd_card *card) { struct snd_bebob *bebob = card->private_data; + snd_bebob_stream_destroy_duplex(bebob); + fw_unit_put(bebob->unit); + + kfree(bebob->maudio_special_quirk); + if (bebob->card_index >= 0) { mutex_lock(&devices_mutex); clear_bit(bebob->card_index, devices_used); @@ -205,7 +216,7 @@ bebob_probe(struct fw_unit *unit, card->private_free = bebob_card_free; bebob->card = card; - bebob->unit = unit; + bebob->unit = fw_unit_get(unit); bebob->spec = spec; mutex_init(&bebob->mutex); spin_lock_init(&bebob->lock); @@ -306,10 +317,11 @@ static void bebob_remove(struct fw_unit *unit) if (bebob == NULL) return; - kfree(bebob->maudio_special_quirk); + /* Awake bus-reset waiters. */ + if (!completion_done(&bebob->bus_reset)) + complete_all(&bebob->bus_reset); - snd_bebob_stream_destroy_duplex(bebob); - snd_card_disconnect(bebob->card); + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(bebob->card); } diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 0ebcabfdc7ce..98e4fc8121a1 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob) static void destroy_both_connections(struct snd_bebob *bebob) { - break_both_connections(bebob); - cmp_connection_destroy(&bebob->in_conn); cmp_connection_destroy(&bebob->out_conn); } @@ -712,22 +710,16 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob) mutex_unlock(&bebob->mutex); } +/* + * This function should be called before starting streams or after stopping + * streams. + */ void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) { - mutex_lock(&bebob->mutex); - - amdtp_stream_pcm_abort(&bebob->rx_stream); - amdtp_stream_pcm_abort(&bebob->tx_stream); - - amdtp_stream_stop(&bebob->rx_stream); - amdtp_stream_stop(&bebob->tx_stream); - amdtp_stream_destroy(&bebob->rx_stream); amdtp_stream_destroy(&bebob->tx_stream); destroy_both_connections(bebob); - - mutex_unlock(&bebob->mutex); } /* diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index fa9cf761b610..07dbd01d7a6b 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -311,14 +311,21 @@ end: return err; } +/* + * This function should be called before starting streams or after stopping + * streams. + */ static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream) { - amdtp_stream_destroy(stream); + struct fw_iso_resources *resources; if (stream == &dice->tx_stream) - fw_iso_resources_destroy(&dice->tx_resources); + resources = &dice->tx_resources; else - fw_iso_resources_destroy(&dice->rx_resources); + resources = &dice->rx_resources; + + amdtp_stream_destroy(stream); + fw_iso_resources_destroy(resources); } int snd_dice_stream_init_duplex(struct snd_dice *dice) @@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) goto end; err = init_stream(dice, &dice->rx_stream); + if (err < 0) + destroy_stream(dice, &dice->tx_stream); end: return err; } @@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice) { snd_dice_transaction_clear_enable(dice); - stop_stream(dice, &dice->tx_stream); destroy_stream(dice, &dice->tx_stream); - - stop_stream(dice, &dice->rx_stream); destroy_stream(dice, &dice->rx_stream); dice->substreams_counter = 0; diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 90d8f40ff727..70a111d7f428 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -226,11 +226,20 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->mixername, "DICE"); } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void dice_card_free(struct snd_card *card) { struct snd_dice *dice = card->private_data; + snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); + fw_unit_put(dice->unit); + mutex_destroy(&dice->mutex); } @@ -251,7 +260,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice = card->private_data; dice->card = card; - dice->unit = unit; + dice->unit = fw_unit_get(unit); card->private_free = dice_card_free; spin_lock_init(&dice->lock); @@ -305,10 +314,7 @@ static void dice_remove(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); - snd_card_disconnect(dice->card); - - snd_dice_stream_destroy_duplex(dice); - + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(dice->card); } diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 3e2ed8e82cbc..2682e7e3e5c9 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -173,11 +173,23 @@ end: return err; } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void efw_card_free(struct snd_card *card) { struct snd_efw *efw = card->private_data; + snd_efw_stream_destroy_duplex(efw); + snd_efw_transaction_remove_instance(efw); + fw_unit_put(efw->unit); + + kfree(efw->resp_buf); + if (efw->card_index >= 0) { mutex_lock(&devices_mutex); clear_bit(efw->card_index, devices_used); @@ -185,7 +197,6 @@ efw_card_free(struct snd_card *card) } mutex_destroy(&efw->mutex); - kfree(efw->resp_buf); } static int @@ -218,7 +229,7 @@ efw_probe(struct fw_unit *unit, card->private_free = efw_card_free; efw->card = card; - efw->unit = unit; + efw->unit = fw_unit_get(unit); mutex_init(&efw->mutex); spin_lock_init(&efw->lock); init_waitqueue_head(&efw->hwdep_wait); @@ -289,10 +300,7 @@ static void efw_remove(struct fw_unit *unit) { struct snd_efw *efw = dev_get_drvdata(&unit->device); - snd_efw_stream_destroy_duplex(efw); - snd_efw_transaction_remove_instance(efw); - - snd_card_disconnect(efw->card); + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(efw->card); } diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 4f440e163667..c55db1bddc80 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -100,17 +100,22 @@ end: return err; } +/* + * This function should be called before starting the stream or after stopping + * the streams. + */ static void destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) { - stop_stream(efw, stream); - - amdtp_stream_destroy(stream); + struct cmp_connection *conn; if (stream == &efw->tx_stream) - cmp_connection_destroy(&efw->out_conn); + conn = &efw->out_conn; else - cmp_connection_destroy(&efw->in_conn); + conn = &efw->in_conn; + + amdtp_stream_destroy(stream); + cmp_connection_destroy(&efw->out_conn); } static int @@ -319,12 +324,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw) void snd_efw_stream_destroy_duplex(struct snd_efw *efw) { - mutex_lock(&efw->mutex); - destroy_stream(efw, &efw->rx_stream); destroy_stream(efw, &efw->tx_stream); - - mutex_unlock(&efw->mutex); } void snd_efw_stream_lock_changed(struct snd_efw *efw) diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index bda845afb470..29ccb3637164 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -337,6 +337,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, stop_stream(oxfw, stream); } +/* + * This function should be called before starting the stream or after stopping + * the streams. + */ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { @@ -347,8 +351,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, else conn = &oxfw->in_conn; - stop_stream(oxfw, stream); - amdtp_stream_destroy(stream); cmp_connection_destroy(conn); } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 60e5cad0531a..8c6ce019f437 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -104,11 +104,23 @@ end: return err; } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void oxfw_card_free(struct snd_card *card) { struct snd_oxfw *oxfw = card->private_data; unsigned int i; + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); + + fw_unit_put(oxfw->unit); + for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { kfree(oxfw->tx_stream_formats[i]); kfree(oxfw->rx_stream_formats[i]); @@ -136,7 +148,7 @@ static int oxfw_probe(struct fw_unit *unit, oxfw = card->private_data; oxfw->card = card; mutex_init(&oxfw->mutex); - oxfw->unit = unit; + oxfw->unit = fw_unit_get(unit); oxfw->device_info = (const struct device_info *)id->driver_data; spin_lock_init(&oxfw->lock); init_waitqueue_head(&oxfw->hwdep_wait); @@ -212,12 +224,7 @@ static void oxfw_remove(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - snd_card_disconnect(oxfw->card); - - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(oxfw->card); } diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index 1a3a6fa27158..88844881cbff 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c @@ -56,8 +56,7 @@ static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg) static void snd_ak4113_free(struct ak4113 *chip) { - chip->init = 1; /* don't schedule new work */ - mb(); + atomic_inc(&chip->wq_processing); /* don't schedule new work */ cancel_delayed_work_sync(&chip->work); kfree(chip); } @@ -89,6 +88,8 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read, chip->write = write; chip->private_data = private_data; INIT_DELAYED_WORK(&chip->work, ak4113_stats); + atomic_set(&chip->wq_processing, 0); + mutex_init(&chip->reinit_mutex); for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) chip->regmap[reg] = pgm[reg]; @@ -139,13 +140,13 @@ static void ak4113_init_regs(struct ak4113 *chip) void snd_ak4113_reinit(struct ak4113 *chip) { - chip->init = 1; - mb(); - flush_delayed_work(&chip->work); + if (atomic_inc_return(&chip->wq_processing) == 1) + cancel_delayed_work_sync(&chip->work); + mutex_lock(&chip->reinit_mutex); ak4113_init_regs(chip); + mutex_unlock(&chip->reinit_mutex); /* bring up statistics / event queing */ - chip->init = 0; - if (chip->kctls[0]) + if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); } EXPORT_SYMBOL_GPL(snd_ak4113_reinit); @@ -632,8 +633,25 @@ static void ak4113_stats(struct work_struct *work) { struct ak4113 *chip = container_of(work, struct ak4113, work.work); - if (!chip->init) + if (atomic_inc_return(&chip->wq_processing) == 1) snd_ak4113_check_rate_and_errors(chip, chip->check_flags); - schedule_delayed_work(&chip->work, HZ / 10); + if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); +} + +#ifdef CONFIG_PM +void snd_ak4113_suspend(struct ak4113 *chip) +{ + atomic_inc(&chip->wq_processing); /* don't schedule new work */ + cancel_delayed_work_sync(&chip->work); +} +EXPORT_SYMBOL(snd_ak4113_suspend); + +void snd_ak4113_resume(struct ak4113 *chip) +{ + atomic_dec(&chip->wq_processing); + snd_ak4113_reinit(chip); } +EXPORT_SYMBOL(snd_ak4113_resume); +#endif diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index c7f56339415d..5a4cf3fab4ae 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -66,8 +66,7 @@ static void reg_dump(struct ak4114 *ak4114) static void snd_ak4114_free(struct ak4114 *chip) { - chip->init = 1; /* don't schedule new work */ - mb(); + atomic_inc(&chip->wq_processing); /* don't schedule new work */ cancel_delayed_work_sync(&chip->work); kfree(chip); } @@ -100,6 +99,8 @@ int snd_ak4114_create(struct snd_card *card, chip->write = write; chip->private_data = private_data; INIT_DELAYED_WORK(&chip->work, ak4114_stats); + atomic_set(&chip->wq_processing, 0); + mutex_init(&chip->reinit_mutex); for (reg = 0; reg < 6; reg++) chip->regmap[reg] = pgm[reg]; @@ -122,6 +123,7 @@ int snd_ak4114_create(struct snd_card *card, snd_ak4114_free(chip); return err < 0 ? err : -EIO; } +EXPORT_SYMBOL(snd_ak4114_create); void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char mask, unsigned char val) { @@ -131,6 +133,7 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char reg_write(chip, reg, (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val); } +EXPORT_SYMBOL(snd_ak4114_reg_write); static void ak4114_init_regs(struct ak4114 *chip) { @@ -152,15 +155,16 @@ static void ak4114_init_regs(struct ak4114 *chip) void snd_ak4114_reinit(struct ak4114 *chip) { - chip->init = 1; - mb(); - flush_delayed_work(&chip->work); + if (atomic_inc_return(&chip->wq_processing) == 1) + cancel_delayed_work_sync(&chip->work); + mutex_lock(&chip->reinit_mutex); ak4114_init_regs(chip); + mutex_unlock(&chip->reinit_mutex); /* bring up statistics / event queing */ - chip->init = 0; - if (chip->kctls[0]) + if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); } +EXPORT_SYMBOL(snd_ak4114_reinit); static unsigned int external_rate(unsigned char rcs1) { @@ -505,6 +509,7 @@ int snd_ak4114_build(struct ak4114 *ak4114, schedule_delayed_work(&ak4114->work, HZ / 10); return 0; } +EXPORT_SYMBOL(snd_ak4114_build); /* notify kcontrols if any parameters are changed */ static void ak4114_notify(struct ak4114 *ak4114, @@ -560,6 +565,7 @@ int snd_ak4114_external_rate(struct ak4114 *ak4114) rcs1 = reg_read(ak4114, AK4114_REG_RCS1); return external_rate(rcs1); } +EXPORT_SYMBOL(snd_ak4114_external_rate); int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) { @@ -607,20 +613,30 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) } return res; } +EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors); static void ak4114_stats(struct work_struct *work) { struct ak4114 *chip = container_of(work, struct ak4114, work.work); - if (!chip->init) + if (atomic_inc_return(&chip->wq_processing) == 1) snd_ak4114_check_rate_and_errors(chip, chip->check_flags); + if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); +} - schedule_delayed_work(&chip->work, HZ / 10); +#ifdef CONFIG_PM +void snd_ak4114_suspend(struct ak4114 *chip) +{ + atomic_inc(&chip->wq_processing); /* don't schedule new work */ + cancel_delayed_work_sync(&chip->work); } +EXPORT_SYMBOL(snd_ak4114_suspend); -EXPORT_SYMBOL(snd_ak4114_create); -EXPORT_SYMBOL(snd_ak4114_reg_write); -EXPORT_SYMBOL(snd_ak4114_reinit); -EXPORT_SYMBOL(snd_ak4114_build); -EXPORT_SYMBOL(snd_ak4114_external_rate); -EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors); +void snd_ak4114_resume(struct ak4114 *chip) +{ + atomic_dec(&chip->wq_processing); + snd_ak4114_reinit(chip); +} +EXPORT_SYMBOL(snd_ak4114_resume); +#endif diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 88452e899bd9..48848909a5a9 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -91,9 +91,7 @@ int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t chip->read = read; chip->write = write; chip->private_data = private_data; - init_timer(&chip->timer); - chip->timer.data = (unsigned long)chip; - chip->timer.function = snd_ak4117_timer; + setup_timer(&chip->timer, snd_ak4117_timer, (unsigned long)chip); for (reg = 0; reg < 5; reg++) chip->regmap[reg] = pgm[reg]; @@ -139,8 +137,7 @@ void snd_ak4117_reinit(struct ak4117 *chip) /* release powerdown, everything is initialized now */ reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN); chip->init = 0; - chip->timer.expires = 1 + jiffies; - add_timer(&chip->timer); + mod_timer(&chip->timer, 1 + jiffies); } static unsigned int external_rate(unsigned char rcs1) @@ -540,8 +537,7 @@ static void snd_ak4117_timer(unsigned long data) if (chip->init) return; snd_ak4117_check_rate_and_errors(chip, 0); - chip->timer.expires = 1 + jiffies; - add_timer(&chip->timer); + mod_timer(&chip->timer, 1 + jiffies); } EXPORT_SYMBOL(snd_ak4117_create); diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 67dbfde837ab..c65731088aa2 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -21,7 +21,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index f481a41e027e..769226515f0d 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -142,7 +142,6 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, struct snd_card *card; struct snd_ad1816a *chip; struct snd_opl3 *opl3; - struct snd_timer *timer; error = snd_card_new(&pcard->card->dev, index[dev], id[dev], THIS_MODULE, @@ -172,7 +171,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d", card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - if ((error = snd_ad1816a_pcm(chip, 0, NULL)) < 0) { + if ((error = snd_ad1816a_pcm(chip, 0)) < 0) { snd_card_free(card); return error; } @@ -182,7 +181,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, return error; } - error = snd_ad1816a_timer(chip, 0, &timer); + error = snd_ad1816a_timer(chip, 0); if (error < 0) { snd_card_free(card); return error; diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 01a07986f4a3..5c815f5fb044 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -22,11 +22,11 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/ioport.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/tlv.h> #include <sound/ad1816a.h> -#include <asm/io.h> #include <asm/dma.h> static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip) @@ -675,7 +675,7 @@ static struct snd_pcm_ops snd_ad1816a_capture_ops = { .pointer = snd_ad1816a_capture_pointer, }; -int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm) +int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device) { int error; struct snd_pcm *pcm; @@ -697,13 +697,10 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm) 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; - if (rpcm) - *rpcm = pcm; return 0; } -int snd_ad1816a_timer(struct snd_ad1816a *chip, int device, - struct snd_timer **rtimer) +int snd_ad1816a_timer(struct snd_ad1816a *chip, int device) { struct snd_timer *timer; struct snd_timer_id tid; @@ -720,8 +717,6 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device, timer->private_data = chip; chip->timer = timer; timer->hw = snd_ad1816a_timer_table; - if (rtimer) - *rtimer = timer; return 0; } diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index 093f22a464d7..f159da4ec890 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c @@ -88,7 +88,6 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_wss *chip; - struct snd_pcm *pcm; int error; error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); @@ -103,7 +102,7 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n) card->private_data = chip; - error = snd_wss_pcm(chip, 0, &pcm); + error = snd_wss_pcm(chip, 0); if (error < 0) goto out; @@ -112,10 +111,10 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n) goto out; strcpy(card->driver, "AD1848"); - strcpy(card->shortname, pcm->name); + strcpy(card->shortname, chip->pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", - pcm->name, chip->port, irq[n], dma1[n]); + chip->pcm->name, chip->port, irq[n], dma1[n]); if (thinkpad[n]) strcat(card->longname, " [Thinkpad]"); diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 32d01525211d..bc9ea306ee02 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -233,7 +233,7 @@ static int snd_card_als100_probe(int dev, irq[dev], dma8[dev], dma16[dev]); } - if ((error = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) { + if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) { snd_card_free(card); return error; } diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index 0ea75fc62072..fff186fa621e 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -29,7 +29,7 @@ activation method (full-duplex audio!). */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/time.h> @@ -215,7 +215,7 @@ static int snd_card_azt2320_probe(int dev, sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i", card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - error = snd_wss_pcm(chip, 0, NULL); + error = snd_wss_pcm(chip, 0); if (error < 0) { snd_card_free(card); return error; @@ -225,7 +225,7 @@ static int snd_card_azt2320_probe(int dev, snd_card_free(card); return error; } - error = snd_wss_timer(chip, 0, NULL); + error = snd_wss_timer(chip, 0); if (error < 0) { snd_card_free(card); return error; diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index 4778852a1201..2c89d95da674 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c @@ -307,7 +307,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev) if (err < 0) goto error; - err = snd_wss_pcm(cmi->wss, 0, NULL); + err = snd_wss_pcm(cmi->wss, 0); if (err < 0) goto error; @@ -318,7 +318,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev) if (err < 0) goto error; - if (snd_wss_timer(cmi->wss, 0, NULL) < 0) + if (snd_wss_timer(cmi->wss, 0) < 0) snd_printk(KERN_WARNING "error initializing WSS timer\n"); if (mpuport[ndev] == SNDRV_AUTO_PORT) { diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index 7dba07a4343a..282cd75d2235 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c @@ -92,7 +92,6 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_wss *chip; - struct snd_pcm *pcm; int error; error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); @@ -106,15 +105,15 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n) card->private_data = chip; - error = snd_wss_pcm(chip, 0, &pcm); + error = snd_wss_pcm(chip, 0); if (error < 0) goto out; strcpy(card->driver, "CS4231"); - strcpy(card->shortname, pcm->name); + strcpy(card->shortname, chip->pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", - pcm->name, chip->port, irq[n], dma1[n]); + chip->pcm->name, chip->port, irq[n], dma1[n]); if (dma2[n] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]); @@ -122,7 +121,7 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n) if (error < 0) goto out; - error = snd_wss_timer(chip, 0, NULL); + error = snd_wss_timer(chip, 0); if (error < 0) goto out; diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 750f51c904fc..9d7582c90a95 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -382,7 +382,6 @@ static int snd_cs423x_card_new(struct device *pdev, int dev, static int snd_cs423x_probe(struct snd_card *card, int dev) { struct snd_card_cs4236 *acard; - struct snd_pcm *pcm; struct snd_wss *chip; struct snd_opl3 *opl3; int err; @@ -404,7 +403,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) acard->chip = chip; if (chip->hardware & WSS_HW_CS4236B_MASK) { - err = snd_cs4236_pcm(chip, 0, &pcm); + err = snd_cs4236_pcm(chip, 0); if (err < 0) return err; @@ -412,7 +411,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } else { - err = snd_wss_pcm(chip, 0, &pcm); + err = snd_wss_pcm(chip, 0); if (err < 0) return err; @@ -420,17 +419,17 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } - strcpy(card->driver, pcm->name); - strcpy(card->shortname, pcm->name); + strcpy(card->driver, chip->pcm->name); + strcpy(card->shortname, chip->pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", - pcm->name, + chip->pcm->name, chip->port, irq[dev], dma1[dev]); if (dma2[dev] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) return err; diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index c5adca300632..2b7cc596f4c6 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -79,7 +79,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/time.h> @@ -376,17 +376,14 @@ int snd_cs4236_create(struct snd_card *card, return 0; } -int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) +int snd_cs4236_pcm(struct snd_wss *chip, int device) { - struct snd_pcm *pcm; int err; - err = snd_wss_pcm(chip, device, &pcm); + err = snd_wss_pcm(chip, device); if (err < 0) return err; - pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX; - if (rpcm) - *rpcm = pcm; + chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX; return 0; } diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index 76001fe0579d..1901c2bb6c3b 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -138,10 +138,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n) { struct snd_es1688 *chip = card->private_data; struct snd_opl3 *opl3; - struct snd_pcm *pcm; int error; - error = snd_es1688_pcm(card, chip, 0, &pcm); + error = snd_es1688_pcm(card, chip, 0); if (error < 0) return error; @@ -150,9 +149,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n) return error; strlcpy(card->driver, "ES1688", sizeof(card->driver)); - strlcpy(card->shortname, pcm->name, sizeof(card->shortname)); + strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port, + "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port, chip->irq, chip->dma8); if (fm_port[n] == SNDRV_AUTO_PORT) diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index b5450143407b..e2cf508841b1 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -25,11 +25,11 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/es1688.h> #include <sound/initval.h> -#include <asm/io.h> #include <asm/dma.h> MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); @@ -728,8 +728,7 @@ static struct snd_pcm_ops snd_es1688_capture_ops = { .pointer = snd_es1688_capture_pointer, }; -int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, - int device, struct snd_pcm **rpcm) +int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device) { struct snd_pcm *pcm; int err; @@ -749,9 +748,6 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), 64*1024, 64*1024); - - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index b481bb8c31bc..5094b62d8f77 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -84,8 +84,8 @@ #include <linux/isapnp.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/dma.h> #include <sound/core.h> #include <sound/control.h> @@ -1687,16 +1687,13 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = { .pointer = snd_es18xx_capture_pointer, }; -static int snd_es18xx_pcm(struct snd_card *card, int device, - struct snd_pcm **rpcm) +static int snd_es18xx_pcm(struct snd_card *card, int device) { struct snd_es18xx *chip = card->private_data; struct snd_pcm *pcm; char str[16]; int err; - if (rpcm) - *rpcm = NULL; sprintf(str, "ES%x", chip->version); if (chip->caps & ES18XX_PCM2) err = snd_pcm_new(card, str, device, 2, 1, &pcm); @@ -1722,9 +1719,6 @@ static int snd_es18xx_pcm(struct snd_card *card, int device, snd_dma_isa_data(), 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); - - if (rpcm) - *rpcm = pcm; return 0; } @@ -2154,7 +2148,7 @@ static int snd_audiodrive_probe(struct snd_card *card, int dev) chip->port, irq[dev], dma1[dev]); - err = snd_es18xx_pcm(card, 0, NULL); + err = snd_es18xx_pcm(card, 0); if (err < 0) return err; diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c index 1eb2b1ec0fd9..32278847884f 100644 --- a/sound/isa/galaxy/galaxy.c +++ b/sound/isa/galaxy/galaxy.c @@ -569,7 +569,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n) if (err < 0) goto error; - err = snd_wss_pcm(chip, 0, NULL); + err = snd_wss_pcm(chip, 0); if (err < 0) goto error; @@ -577,7 +577,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n) if (err < 0) goto error; - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) goto error; diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c deleted file mode 100644 index 4dc9caf8ddcf..000000000000 --- a/sound/isa/gus/gus_instr.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Routines for Gravis UltraSound soundcards - Synthesizer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/time.h> -#include <sound/core.h> -#include <sound/gus.h> - -/* - * - */ - -int snd_gus_iwffff_put_sample(void *private_data, struct iwffff_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - struct snd_gf1_mem_block *block; - int err; - - if (wave->format & IWFFFF_WAVE_ROM) - return 0; /* it's probably ok - verify the address? */ - if (wave->format & IWFFFF_WAVE_STEREO) - return -EINVAL; /* not supported */ - block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, - SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF, - NULL, wave->size, - wave->format & IWFFFF_WAVE_16BIT, 1, - wave->share_id); - if (block == NULL) - return -ENOMEM; - err = snd_gus_dram_write(gus, data, - block->ptr, wave->size); - if (err < 0) { - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0); - snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block); - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1); - return err; - } - wave->address.memory = block->ptr; - return 0; -} - -int snd_gus_iwffff_get_sample(void *private_data, struct iwffff_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, - wave->format & IWFFFF_WAVE_ROM ? 1 : 0); -} - -int snd_gus_iwffff_remove_sample(void *private_data, struct iwffff_wave *wave, - int atomic) -{ - struct snd_gus_card *gus = private_data; - - if (wave->format & IWFFFF_WAVE_ROM) - return 0; /* it's probably ok - verify the address? */ - return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory); -} - -/* - * - */ - -int snd_gus_gf1_put_sample(void *private_data, struct gf1_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - struct snd_gf1_mem_block *block; - int err; - - if (wave->format & GF1_WAVE_STEREO) - return -EINVAL; /* not supported */ - block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, - SNDRV_GF1_MEM_OWNER_WAVE_GF1, - NULL, wave->size, - wave->format & GF1_WAVE_16BIT, 1, - wave->share_id); - if (block == NULL) - return -ENOMEM; - err = snd_gus_dram_write(gus, data, - block->ptr, wave->size); - if (err < 0) { - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0); - snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block); - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1); - return err; - } - wave->address.memory = block->ptr; - return 0; -} - -int snd_gus_gf1_get_sample(void *private_data, struct gf1_wave *wave, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, 0); -} - -int snd_gus_gf1_remove_sample(void *private_data, struct gf1_wave *wave, - int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory); -} - -/* - * - */ - -int snd_gus_simple_put_sample(void *private_data, struct simple_instrument *instr, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - struct snd_gf1_mem_block *block; - int err; - - if (instr->format & SIMPLE_WAVE_STEREO) - return -EINVAL; /* not supported */ - block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, - SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE, - NULL, instr->size, - instr->format & SIMPLE_WAVE_16BIT, 1, - instr->share_id); - if (block == NULL) - return -ENOMEM; - err = snd_gus_dram_write(gus, data, block->ptr, instr->size); - if (err < 0) { - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0); - snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block); - snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1); - return err; - } - instr->address.memory = block->ptr; - return 0; -} - -int snd_gus_simple_get_sample(void *private_data, struct simple_instrument *instr, - char __user *data, long len, int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gus_dram_read(gus, data, instr->address.memory, instr->size, 0); -} - -int snd_gus_simple_remove_sample(void *private_data, struct simple_instrument *instr, - int atomic) -{ - struct snd_gus_card *gus = private_data; - - return snd_gf1_mem_free(&gus->gf1.mem_alloc, instr->address.memory); -} diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 2dcf45bf7293..25f6788ccef3 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -849,7 +849,7 @@ static struct snd_pcm_ops snd_gf1_pcm_capture_ops = { .pointer = snd_gf1_pcm_capture_pointer, }; -int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm) +int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) { struct snd_card *card; struct snd_kcontrol *kctl; @@ -857,8 +857,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s struct snd_pcm_substream *substream; int capture, err; - if (rpcm) - *rpcm = NULL; card = gus->card; capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0; err = snd_pcm_new(card, @@ -903,8 +901,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s return err; kctl->id.index = control_index; - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index 21cc42e4c4be..3992912743f5 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -241,13 +241,11 @@ static struct snd_rawmidi_ops snd_gf1_uart_input = .trigger = snd_gf1_uart_input_trigger, }; -int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi ** rrawmidi) +int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1"); @@ -256,7 +254,5 @@ int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmid rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = gus; gus->midi_uart = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return err; } diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index 7ce29ffa1af9..f0019715d82e 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c @@ -181,12 +181,12 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n) if (error < 0) goto out; - error = snd_gf1_pcm_new(gus, 0, 0, NULL); + error = snd_gf1_pcm_new(gus, 0, 0); if (error < 0) goto out; if (!gus->ace_flag) { - error = snd_gf1_rawmidi_new(gus, 0, NULL); + error = snd_gf1_rawmidi_new(gus, 0); if (error < 0) goto out; } diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 28a16936a397..693d95f46804 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -284,7 +284,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n) } gus->codec_flag = 1; - error = snd_es1688_pcm(card, es1688, 0, NULL); + error = snd_es1688_pcm(card, es1688, 0); if (error < 0) goto out; @@ -295,7 +295,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n) snd_component_add(card, "ES1688"); if (pcm_channels[n] > 0) { - error = snd_gf1_pcm_new(gus, 1, 1, NULL); + error = snd_gf1_pcm_new(gus, 1, 1); if (error < 0) goto out; } diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 39df36ca3acb..8216e8d8f017 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -309,7 +309,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) if (err < 0) goto _err; - err = snd_wss_pcm(wss, 0, NULL); + err = snd_wss_pcm(wss, 0); if (err < 0) goto _err; @@ -317,19 +317,19 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) if (err < 0) goto _err; - err = snd_wss_timer(wss, 2, NULL); + err = snd_wss_timer(wss, 2); if (err < 0) goto _err; if (pcm_channels[dev] > 0) { - if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) + if ((err = snd_gf1_pcm_new(gus, 1, 1)) < 0) goto _err; } err = snd_gusmax_mixer(wss); if (err < 0) goto _err; - err = snd_gf1_rawmidi_new(gus, 0, NULL); + err = snd_gf1_rawmidi_new(gus, 0); if (err < 0) goto _err; diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index ad55e5cb8e94..70d0040484c8 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -647,7 +647,6 @@ static int snd_interwave_probe(struct snd_card *card, int dev) #ifdef SNDRV_STB struct snd_i2c_bus *i2c_bus; #endif - struct snd_pcm *pcm; char *str; int err; @@ -695,14 +694,15 @@ static int snd_interwave_probe(struct snd_card *card, int dev) if (err < 0) return err; - err = snd_wss_pcm(wss, 0, &pcm); + err = snd_wss_pcm(wss, 0); if (err < 0) return err; - sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A'); - strcat(pcm->name, " (codec)"); + sprintf(wss->pcm->name + strlen(wss->pcm->name), " rev %c", + gus->revision + 'A'); + strcat(wss->pcm->name, " (codec)"); - err = snd_wss_timer(wss, 2, NULL); + err = snd_wss_timer(wss, 2); if (err < 0) return err; @@ -711,7 +711,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev) return err; if (pcm_channels[dev] > 0) { - err = snd_gf1_pcm_new(gus, 1, 1, NULL); + err = snd_gf1_pcm_new(gus, 1, 1); if (err < 0) return err; } @@ -740,7 +740,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev) #endif gus->uart_enable = midi[dev]; - if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) + if ((err = snd_gf1_rawmidi_new(gus, 0)) < 0) return err; #ifndef SNDRV_STB diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c index 1cee18fb28a8..835d4aa26761 100644 --- a/sound/isa/msnd/msnd.c +++ b/sound/isa/msnd/msnd.c @@ -679,8 +679,7 @@ static struct snd_pcm_ops snd_msnd_capture_ops = { }; -int snd_msnd_pcm(struct snd_card *card, int device, - struct snd_pcm **rpcm) +int snd_msnd_pcm(struct snd_card *card, int device) { struct snd_msnd *chip = card->private_data; struct snd_pcm *pcm; @@ -696,9 +695,6 @@ int snd_msnd_pcm(struct snd_card *card, int device, pcm->private_data = chip; strcpy(pcm->name, "Hurricane"); - - if (rpcm) - *rpcm = pcm; return 0; } EXPORT_SYMBOL(snd_msnd_pcm); diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h index dbac3a42347b..5f3c7dcd9f9d 100644 --- a/sound/isa/msnd/msnd.h +++ b/sound/isa/msnd/msnd.h @@ -297,7 +297,7 @@ int snd_msnd_disable_irq(struct snd_msnd *chip); void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file); int snd_msnd_DAPQ(struct snd_msnd *chip, int start); int snd_msnd_DARQ(struct snd_msnd *chip, int start); -int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm); +int snd_msnd_pcm(struct snd_card *card, int device); int snd_msndmidi_new(struct snd_card *card, int device); void snd_msndmidi_input_read(void *mpu); diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 5016bf957f51..4c072666115d 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -582,7 +582,7 @@ static int snd_msnd_attach(struct snd_card *card) if (err < 0) goto err_release_region; - err = snd_msnd_pcm(card, 0, NULL); + err = snd_msnd_pcm(card, 0); if (err < 0) { printk(KERN_ERR LOGNAME ": error creating new PCM device\n"); goto err_release_region; @@ -627,8 +627,7 @@ static int snd_msnd_attach(struct snd_card *card) return 0; err_release_region: - if (chip->mappedbase) - iounmap(chip->mappedbase); + iounmap(chip->mappedbase); release_mem_region(chip->base, BUFFSIZE); release_region(chip->io, DSP_NUMIO); free_irq(chip->irq, chip); diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index a219bc37816b..ae133633a420 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -26,6 +26,7 @@ #include <linux/pm.h> #include <linux/pnp.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/wss.h> #include <sound/mpu401.h> @@ -33,8 +34,6 @@ #include <sound/initval.h> #include <sound/tlv.h> -#include <asm/io.h> - MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Yamaha OPL3SA2+"); MODULE_LICENSE("GPL"); @@ -684,7 +683,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev) return err; } chip->wss = wss; - err = snd_wss_pcm(wss, 0, NULL); + err = snd_wss_pcm(wss, 0); if (err < 0) return err; err = snd_wss_mixer(wss); @@ -693,7 +692,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev) err = snd_opl3sa2_mixer(card); if (err < 0) return err; - err = snd_wss_timer(wss, 0, NULL); + err = snd_wss_timer(wss, 0); if (err < 0) return err; if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index c2ca681ac51b..3a9067db1a84 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -29,7 +29,7 @@ #include <linux/delay.h> #include <linux/ioport.h> #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/dma.h> #include <sound/core.h> #include <sound/wss.h> @@ -1270,8 +1270,6 @@ static int snd_miro_probe(struct snd_card *card) int error; struct snd_miro *miro = card->private_data; struct snd_wss *codec; - struct snd_timer *timer; - struct snd_pcm *pcm; struct snd_rawmidi *rmidi; if (!miro->res_mc_base) { @@ -1310,7 +1308,7 @@ static int snd_miro_probe(struct snd_card *card) if (error < 0) return error; - error = snd_wss_pcm(codec, 0, &pcm); + error = snd_wss_pcm(codec, 0); if (error < 0) return error; @@ -1318,11 +1316,11 @@ static int snd_miro_probe(struct snd_card *card) if (error < 0) return error; - error = snd_wss_timer(codec, 0, &timer); + error = snd_wss_timer(codec, 0); if (error < 0) return error; - miro->pcm = pcm; + miro->pcm = codec->pcm; error = snd_miro_mixer(card, miro); if (error < 0) @@ -1356,8 +1354,8 @@ static int snd_miro_probe(struct snd_card *card) strcpy(card->driver, "miro"); sprintf(card->longname, "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, miro->name, pcm->name, miro->wss_base + 4, - miro->irq, miro->dma1, miro->dma2); + card->shortname, miro->name, codec->pcm->name, + miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2); if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index c9b582848603..0a5266003786 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -29,7 +29,7 @@ #include <linux/delay.h> #include <linux/pnp.h> #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/dma.h> #include <sound/core.h> #include <sound/tlv.h> @@ -820,10 +820,6 @@ static int snd_opti9xx_probe(struct snd_card *card) int xdma2; struct snd_opti9xx *chip = card->private_data; struct snd_wss *codec; -#ifdef CS4231 - struct snd_timer *timer; -#endif - struct snd_pcm *pcm; struct snd_rawmidi *rmidi; struct snd_hwdep *synth; @@ -855,7 +851,7 @@ static int snd_opti9xx_probe(struct snd_card *card) if (error < 0) return error; chip->codec = codec; - error = snd_wss_pcm(codec, 0, &pcm); + error = snd_wss_pcm(codec, 0); if (error < 0) return error; error = snd_wss_mixer(codec); @@ -867,7 +863,7 @@ static int snd_opti9xx_probe(struct snd_card *card) return error; #endif #ifdef CS4231 - error = snd_wss_timer(codec, 0, &timer); + error = snd_wss_timer(codec, 0); if (error < 0) return error; #endif @@ -884,11 +880,12 @@ static int snd_opti9xx_probe(struct snd_card *card) sprintf(card->shortname, "OPTi %s", card->driver); #if defined(CS4231) || defined(OPTi93X) sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, pcm->name, + card->shortname, codec->pcm->name, chip->wss_base + 4, irq, dma1, xdma2); #else sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, pcm->name, chip->wss_base + 4, irq, dma1); + card->shortname, codec->pcm->name, chip->wss_base + 4, irq, + dma1); #endif /* CS4231 || OPTi93X */ if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 45fcdff611f9..94c411299e5a 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -26,11 +26,11 @@ #include <linux/ioport.h> #include <linux/export.h> #include <linux/delay.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/emu8000.h> #include <sound/emu8000_reg.h> -#include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/init.h> #include <sound/control.h> #include <sound/initval.h> @@ -378,13 +378,12 @@ init_arrays(struct snd_emu8000 *emu) static void size_dram(struct snd_emu8000 *emu) { - int i, size, detected_size; + int i, size; if (emu->dram_checked) return; size = 0; - detected_size = 0; /* write out a magic number */ snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE); @@ -392,10 +391,19 @@ size_dram(struct snd_emu8000 *emu) EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET); EMU8000_SMLD_WRITE(emu, UNIQUE_ID1); snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */ + snd_emu8000_write_wait(emu); - while (size < EMU8000_MAX_DRAM) { + /* + * Detect first 512 KiB. If a write succeeds at the beginning of a + * 512 KiB page we assume that the whole page is there. + */ + EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET); + EMU8000_SMLD_READ(emu); /* discard stale data */ + if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1) + goto skip_detect; /* No RAM */ + snd_emu8000_read_wait(emu); - size += 512 * 1024; /* increment 512kbytes */ + for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) { /* Write a unique data on the test address. * if the address is out of range, the data is written on @@ -431,18 +439,9 @@ size_dram(struct snd_emu8000 *emu) snd_emu8000_read_wait(emu); /* Otherwise, it's valid memory. */ - detected_size = size + 512 * 1024; - } - - /* Distinguish 512 KiB from 0. */ - if (detected_size == 0) { - snd_emu8000_read_wait(emu); - EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET); - EMU8000_SMLD_READ(emu); /* discard stale data */ - if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1) - detected_size = 512 * 1024; } +skip_detect: /* wait until FULL bit in SMAxW register is false */ for (i = 0; i < 10000; i++) { if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0) @@ -454,10 +453,10 @@ size_dram(struct snd_emu8000 *emu) snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE); snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE); - snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n", - emu->port1, detected_size/1024); + pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n", + emu->port1, size/1024); - emu->mem_size = detected_size; + emu->mem_size = size; emu->dram_checked = 1; } diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index c99c6078be33..71d13c0bb746 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c @@ -20,7 +20,7 @@ */ #include "emu8000_local.h" -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/moduleparam.h> static int emu8000_reset_addr; diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 2f85c66f8e38..250fd0006b53 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -207,8 +207,7 @@ static void emu8k_pcm_timer_func(unsigned long data) rec->last_ptr = ptr; /* reprogram timer */ - rec->timer.expires = jiffies + 1; - add_timer(&rec->timer); + mod_timer(&rec->timer, jiffies + 1); /* update period */ if (rec->period_pos >= (int)rec->period_size) { @@ -240,9 +239,7 @@ static int emu8k_pcm_open(struct snd_pcm_substream *subs) runtime->private_data = rec; spin_lock_init(&rec->timer_lock); - init_timer(&rec->timer); - rec->timer.function = emu8k_pcm_timer_func; - rec->timer.data = (unsigned long)rec; + setup_timer(&rec->timer, emu8k_pcm_timer_func, (unsigned long)rec); runtime->hw = emu8k_pcm_hw; runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3; @@ -359,8 +356,7 @@ static void start_voice(struct snd_emu8k_pcm *rec, int ch) /* start timer */ spin_lock_irqsave(&rec->timer_lock, flags); if (! rec->timer_running) { - rec->timer.expires = jiffies + 1; - add_timer(&rec->timer); + mod_timer(&rec->timer, jiffies + 1); rec->timer_running = 1; } spin_unlock_irqrestore(&rec->timer_lock, flags); diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c index 95b39beb61c1..72332dfada9a 100644 --- a/sound/isa/sb/emu8000_synth.c +++ b/sound/isa/sb/emu8000_synth.c @@ -103,8 +103,7 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev) hw = dev->driver_data; if (hw->pcm) snd_device_free(dev->card, hw->pcm); - if (hw->emu) - snd_emux_free(hw->emu); + snd_emux_free(hw->emu); snd_util_memhdr_free(hw->memhdr); hw->emu = NULL; hw->memhdr = NULL; diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index 90d2eba549e9..6b4884d052a5 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -297,7 +297,7 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev) "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", port[dev], xirq, xdma8, xdma16); - err = snd_sb8dsp_pcm(chip, 0, NULL); + err = snd_sb8dsp_pcm(chip, 0); if (err < 0) goto err_free; err = snd_sbmixer_new(chip); diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 3f694543a7ea..4a7d7c89808f 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -374,7 +374,7 @@ static int snd_sb16_probe(struct snd_card *card, int dev) if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0) return err; - if ((err = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) + if ((err = snd_sb16dsp_pcm(chip, 0)) < 0) return err; strcpy(card->driver, diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 72b10f4f3e70..8b2d6c6bfe97 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -33,7 +33,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <asm/dma.h> #include <linux/init.h> #include <linux/time.h> @@ -860,19 +860,18 @@ static struct snd_pcm_ops snd_sb16_capture_ops = { .pointer = snd_sb16_capture_pointer, }; -int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm) +int snd_sb16dsp_pcm(struct snd_sb *chip, int device) { struct snd_card *card = chip->card; struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0) return err; sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; pcm->private_data = chip; + chip->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops); @@ -885,9 +884,6 @@ int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), 64*1024, 128*1024); - - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 6c32b3aa34af..b8e2391c33ff 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -157,7 +157,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) goto _err; } - if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) + if ((err = snd_sb8dsp_pcm(chip, 0)) < 0) goto _err; if ((err = snd_sbmixer_new(chip)) < 0) @@ -182,7 +182,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) goto _err; } - if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0) + if ((err = snd_sb8dsp_midi(chip, 0)) < 0) goto _err; strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8"); diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 24d4121ab0e0..9043397fe62f 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -30,7 +30,7 @@ * Cleaned up and rewrote lowlevel routines. */ -#include <asm/io.h> +#include <linux/io.h> #include <asm/dma.h> #include <linux/init.h> #include <linux/time.h> @@ -594,15 +594,13 @@ static struct snd_pcm_ops snd_sb8_capture_ops = { .pointer = snd_sb8_capture_pointer, }; -int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) +int snd_sb8dsp_pcm(struct snd_sb *chip, int device) { struct snd_card *card = chip->card; struct snd_pcm *pcm; int err; size_t max_prealloc = 64 * 1024; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0) return err; sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); @@ -618,8 +616,6 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) snd_dma_isa_data(), 64*1024, max_prealloc); - if (rpcm) - *rpcm = pcm; return 0; } diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index 988a8b73475f..d551c50e549f 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -26,7 +26,7 @@ * Added full duplex UART mode for DSP version 2.0 and later. */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/time.h> #include <sound/core.h> #include <sound/sb.h> @@ -216,8 +216,7 @@ static void snd_sb8dsp_midi_output_timer(unsigned long data) unsigned long flags; spin_lock_irqsave(&chip->open_lock, flags); - chip->midi_timer.expires = 1 + jiffies; - add_timer(&chip->midi_timer); + mod_timer(&chip->midi_timer, 1 + jiffies); spin_unlock_irqrestore(&chip->open_lock, flags); snd_sb8dsp_midi_output_write(substream); } @@ -231,11 +230,10 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre spin_lock_irqsave(&chip->open_lock, flags); if (up) { if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) { - init_timer(&chip->midi_timer); - chip->midi_timer.function = snd_sb8dsp_midi_output_timer; - chip->midi_timer.data = (unsigned long) substream; - chip->midi_timer.expires = 1 + jiffies; - add_timer(&chip->midi_timer); + setup_timer(&chip->midi_timer, + snd_sb8dsp_midi_output_timer, + (unsigned long) substream); + mod_timer(&chip->midi_timer, 1 + jiffies); chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER; } } else { @@ -263,13 +261,11 @@ static struct snd_rawmidi_ops snd_sb8dsp_midi_input = .trigger = snd_sb8dsp_midi_input_trigger, }; -int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi) +int snd_sb8dsp_midi(struct snd_sb *chip, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, "SB8 MIDI"); @@ -280,7 +276,5 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawm rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return 0; } diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index f22b4480828e..787a4ade4afd 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -26,11 +26,11 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/sb.h> #include <sound/initval.h> -#include <asm/io.h> #include <asm/dma.h> MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index e403334a19ad..add1d3f99609 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -19,7 +19,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/time.h> #include <sound/core.h> diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 15a152eaa2e8..51cfa7615f72 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -625,7 +625,7 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev) if (err < 0) goto err_unmap2; - err = snd_wss_pcm(chip, 0, NULL); + err = snd_wss_pcm(chip, 0); if (err < 0) { snd_printk(KERN_ERR PFX "error creating new WSS PCM device\n"); diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 44405df7d4be..7b248cdf06e2 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/err.h> +#include <linux/io.h> #include <linux/isa.h> #include <linux/delay.h> #include <linux/firmware.h> @@ -877,7 +878,6 @@ static int create_ad1845(struct snd_card *card, unsigned port, codec_type, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; - struct snd_pcm *pcm; if (sscape->type != SSCAPE_VIVO) { /* @@ -893,7 +893,7 @@ static int create_ad1845(struct snd_card *card, unsigned port, } - err = snd_wss_pcm(chip, 0, &pcm); + err = snd_wss_pcm(chip, 0); if (err < 0) { snd_printk(KERN_ERR "sscape: No PCM device " "for AD1845 chip\n"); @@ -907,7 +907,7 @@ static int create_ad1845(struct snd_card *card, unsigned port, goto _error; } if (chip->hardware != WSS_HW_AD1848) { - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) { snd_printk(KERN_ERR "sscape: No timer device " "for AD1845 chip\n"); diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index bfbf38cf9841..a0987a57c8a9 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -380,11 +380,11 @@ snd_wavefront_probe (struct snd_card *card, int dev) return err; } - err = snd_wss_pcm(chip, 0, NULL); + err = snd_wss_pcm(chip, 0); if (err < 0) return err; - err = snd_wss_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0); if (err < 0) return err; diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index b77883c7ee76..b5a19708473a 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/init.h> #include <linux/time.h> #include <linux/wait.h> diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index 7dc991682297..8a80fc6a616b 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -47,7 +47,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/init.h> #include <linux/time.h> #include <linux/wait.h> @@ -356,8 +356,7 @@ static void snd_wavefront_midi_output_timer(unsigned long data) unsigned long flags; spin_lock_irqsave (&midi->virtual, flags); - midi->timer.expires = 1 + jiffies; - add_timer(&midi->timer); + mod_timer(&midi->timer, 1 + jiffies); spin_unlock_irqrestore (&midi->virtual, flags); snd_wavefront_midi_output_write(card); } @@ -384,11 +383,10 @@ static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *subs if (up) { if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { if (!midi->istimer) { - init_timer(&midi->timer); - midi->timer.function = snd_wavefront_midi_output_timer; - midi->timer.data = (unsigned long) substream->rmidi->card->private_data; - midi->timer.expires = 1 + jiffies; - add_timer(&midi->timer); + setup_timer(&midi->timer, + snd_wavefront_midi_output_timer, + (unsigned long) substream->rmidi->card->private_data); + mod_timer(&midi->timer, 1 + jiffies); } midi->istimer++; midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index e5db001363ee..33f5ec14fcfa 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -20,7 +20,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/delay.h> diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 347bb1bda110..913b731d2236 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -31,12 +31,12 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/wss.h> #include <sound/pcm_params.h> #include <sound/tlv.h> -#include <asm/io.h> #include <asm/dma.h> #include <asm/irq.h> @@ -1923,7 +1923,7 @@ static struct snd_pcm_ops snd_wss_capture_ops = { .pointer = snd_wss_capture_pointer, }; -int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) +int snd_wss_pcm(struct snd_wss *chip, int device) { struct snd_pcm *pcm; int err; @@ -1949,8 +1949,6 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; - if (rpcm) - *rpcm = pcm; return 0; } EXPORT_SYMBOL(snd_wss_pcm); @@ -1961,7 +1959,7 @@ static void snd_wss_timer_free(struct snd_timer *timer) chip->timer = NULL; } -int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer) +int snd_wss_timer(struct snd_wss *chip, int device) { struct snd_timer *timer; struct snd_timer_id tid; @@ -1980,8 +1978,6 @@ int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer) timer->private_free = snd_wss_timer_free; timer->hw = snd_wss_timer_table; chip->timer = timer; - if (rtimer) - *rtimer = timer; return 0; } EXPORT_SYMBOL(snd_wss_timer); diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c index 13c214466d3b..1c56bf58eff9 100644 --- a/sound/oss/dmasound/dmasound_atari.c +++ b/sound/oss/dmasound/dmasound_atari.c @@ -851,7 +851,7 @@ static int __init AtaIrqInit(void) st_mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ st_mfp.tim_ct_a = 8; /* Turn on event counting. */ /* Register interrupt handler. */ - if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound", + if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, 0, "DMA sound", AtaInterrupt)) return 0; st_mfp.int_en_a |= 0x20; /* Turn interrupt on. */ diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index c23f9f95bfa5..a8ceef8d1a8d 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -675,7 +675,7 @@ static void dsp_write_flush(void) timeout); clear_bit(F_WRITEFLUSH, &dev.flags); if (!signal_pending(current)) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE)); } clear_bit(F_WRITING, &dev.flags); @@ -1288,7 +1288,7 @@ static int __init calibrate_adc(WORD srate) & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags); if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 3); return 0; } diff --git a/sound/oss/pss.c b/sound/oss/pss.c index ca0d6e9f49f5..81314f9e2ccb 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -1228,7 +1228,7 @@ static void __exit cleanup_pss(void) { if(!pss_no_sound) { - if(fw_load && pss_synth) + if (fw_load) vfree(pss_synth); if(pssmss) unload_pss_mss(&cfg2); diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index a33e8ce8085b..213a416b6e0b 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c @@ -1654,7 +1654,7 @@ static int drain_dac(struct cs4297a_state *s, int nonblock) s->dma_dac.hwptr = s->dma_dac.swptr = hwptr; spin_unlock_irqrestore(&s->lock, flags); remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); return 0; } diff --git a/sound/oss/trix.c b/sound/oss/trix.c index 944e0c015485..3c494dc93b93 100644 --- a/sound/oss/trix.c +++ b/sound/oss/trix.c @@ -487,7 +487,7 @@ static int __init init_trix(void) static void __exit cleanup_trix(void) { - if (fw_load && trix_boot) + if (fw_load) vfree(trix_boot); if (sb) unload_trix_sb(&cfg2); diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index 29604a239c44..99b64cb3cef8 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -44,6 +44,7 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/dma-mapping.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> @@ -52,7 +53,6 @@ #include <sound/initval.h> #include <sound/info.h> -#include <asm/io.h> #include <asm/hardware.h> #include <asm/parisc-device.h> @@ -893,9 +893,7 @@ snd_harmony_free(struct snd_harmony *h) if (h->irq >= 0) free_irq(h->irq, h); - if (h->iobase) - iounmap(h->iobase); - + iounmap(h->iobase); kfree(h); return 0; } diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 50dd0086cfb1..edfc1b8d553e 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -793,6 +793,15 @@ config SND_RME9652 To compile this driver as a module, choose M here: the module will be called snd-rme9652. +config SND_SE6X + tristate "Studio Evolution SE6X" + depends on SND_OXYGEN=n && SND_VIRTUOSO=n # PCI ID conflict + select SND_OXYGEN_LIB + select SND_PCM + select SND_MPU401_UART + help + Say Y or M here only if you actually have this sound card. + config SND_SIS7019 tristate "SiS 7019 Audio Accelerator" depends on X86_32 diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 1610c38337af..850a8c984c25 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -40,14 +40,13 @@ #include <linux/compiler.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/initval.h> #include <sound/ac97_codec.h> -#include <asm/io.h> - #include "ad1889.h" #include "ac97/ac97_id.h" @@ -623,14 +622,11 @@ snd_ad1889_interrupt(int irq, void *dev_id) } static int -snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm) +snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device) { int err; struct snd_pcm *pcm; - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm); if (err < 0) return err; @@ -658,9 +654,6 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm) return err; } - if (rpcm) - *rpcm = pcm; - return 0; } @@ -859,12 +852,9 @@ snd_ad1889_free(struct snd_ad1889 *chip) free_irq(chip->irq, chip); skip_hw: - if (chip->iobase) - iounmap(chip->iobase); - + iounmap(chip->iobase); pci_release_regions(chip->pci); pci_disable_device(chip->pci); - kfree(chip); return 0; } @@ -1016,7 +1006,7 @@ snd_ad1889_probe(struct pci_dev *pci, if (err < 0) goto free_and_ret; - err = snd_ad1889_pcm_init(chip, 0, NULL); + err = snd_ad1889_pcm_init(chip, 0); if (err < 0) goto free_and_ret; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index af89e42b2160..c8d499575c01 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -25,7 +25,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -1873,7 +1873,6 @@ static int snd_ali_mixer(struct snd_ali *codec) #ifdef CONFIG_PM_SLEEP static int ali_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ali *chip = card->private_data; struct snd_ali_image *im; @@ -1914,16 +1913,11 @@ static int ali_suspend(struct device *dev) outl(0xffffffff, ALI_REG(chip, ALI_STOP)); spin_unlock_irq(&chip->reg_lock); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int ali_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ali *chip = card->private_data; struct snd_ali_image *im; @@ -1933,15 +1927,6 @@ static int ali_resume(struct device *dev) if (!im) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - spin_lock_irq(&chip->reg_lock); for (i = 0; i < ALI_CHANNELS; i++) { diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 7bb6ac565107..57e034f208dc 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -37,8 +37,7 @@ #include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/slab.h> - -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> @@ -728,35 +727,20 @@ static int snd_als300_create(struct snd_card *card, #ifdef CONFIG_PM_SLEEP static int snd_als300_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_als300 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_als300_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_als300 *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_als300_init(chip); snd_ac97_resume(chip->ac97); diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index d3e6424ee656..a3dea464134d 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -65,7 +65,7 @@ * - power management? (card can do voice wakeup according to datasheet!!) */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/gameport.h> @@ -988,7 +988,6 @@ static void snd_card_als4000_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_als4000_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_card_als4000 *acard = card->private_data; struct snd_sb *chip = acard->chip; @@ -997,29 +996,15 @@ static int snd_als4000_suspend(struct device *dev) snd_pcm_suspend_all(chip->pcm); snd_sbmixer_suspend(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_als4000_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_card_als4000 *acard = card->private_data; struct snd_sb *chip = acard->chip; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_als4000_configure(chip); snd_sbdsp_reset(chip); snd_sbmixer_resume(chip); diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index e9273fb2a505..e5cd7be85355 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -540,9 +540,8 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream * expiry = HZ / 200; expiry = max(expiry, 1); /* don't let it be zero! */ - dpcm->timer.expires = jiffies + expiry; + mod_timer(&dpcm->timer, jiffies + expiry); dpcm->respawn_timer = 1; - add_timer(&dpcm->timer); } static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream) @@ -1064,9 +1063,8 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) If internal and other stream playing, can't switch */ - init_timer(&dpcm->timer); - dpcm->timer.data = (unsigned long) dpcm; - dpcm->timer.function = snd_card_asihpi_timer_function; + setup_timer(&dpcm->timer, snd_card_asihpi_timer_function, + (unsigned long) dpcm); dpcm->substream = substream; runtime->private_data = dpcm; runtime->private_free = snd_card_asihpi_runtime_free; @@ -1246,9 +1244,8 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) if (err) return -EIO; - init_timer(&dpcm->timer); - dpcm->timer.data = (unsigned long) dpcm; - dpcm->timer.function = snd_card_asihpi_timer_function; + setup_timer(&dpcm->timer, snd_card_asihpi_timer_function, + (unsigned long) dpcm); dpcm->substream = substream; runtime->private_data = dpcm; runtime->private_free = snd_card_asihpi_runtime_free; @@ -2832,14 +2829,11 @@ static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file, /* results in /dev/snd/hwC#D0 file for each card with index # also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card' */ -static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, - int device, struct snd_hwdep **rhwdep) +static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device) { struct snd_hwdep *hw; int err; - if (rhwdep) - *rhwdep = NULL; err = snd_hwdep_new(asihpi->card, "HPI", device, &hw); if (err < 0) return err; @@ -2849,8 +2843,6 @@ static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, hw->ops.ioctl = snd_asihpi_hpi_ioctl; hw->ops.release = snd_asihpi_hpi_release; hw->private_data = asihpi; - if (rhwdep) - *rhwdep = hw; return 0; } @@ -2993,7 +2985,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, /* always create, can be enabled or disabled dynamically by enable_hwdep module param*/ - snd_asihpi_hpi_new(asihpi, 0, NULL); + snd_asihpi_hpi_new(asihpi, 0); strcpy(card->driver, "ASIHPI"); diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index 2414d7a2239d..2d6364825d4d 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c @@ -47,7 +47,7 @@ /* operational/messaging errors */ #define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 901 - +#define HPI6000_ERROR_RESP_GET_LEN 902 #define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 903 #define HPI6000_ERROR_MSG_GET_ADR 904 #define HPI6000_ERROR_RESP_GET_ADR 905 @@ -1365,7 +1365,10 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao, length = hpi_read_word(pdo, HPI_HIF_ADDR(length)); } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout); if (!timeout) - length = sizeof(struct hpi_response); + return HPI6000_ERROR_RESP_GET_LEN; + + if (length > phr->size) + return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; /* get the response */ p_data = (u32 *)phr; diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 6aa677e60555..6610bd096fc9 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -28,7 +28,7 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/moduleparam.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/pci.h> #include <linux/stringify.h> #include <linux/module.h> @@ -153,6 +153,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } + res_max_size = min_t(size_t, res_max_size, sizeof(*hr)); + switch (hm->h.function) { case HPI_SUBSYS_CREATE_ADAPTER: case HPI_ADAPTER_DELETE: @@ -539,10 +541,8 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); /* unmap PCI memory space, mapped during device init. */ - for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { - if (pci.ap_mem_base[idx]) - iounmap(pci.ap_mem_base[idx]); - } + for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx) + iounmap(pci.ap_mem_base[idx]); if (pa->irq) free_irq(pa->irq, pa); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 9c1c4452a8ee..d5f15c9bbeda 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -19,7 +19,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -1474,7 +1474,6 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock, */ static int snd_atiixp_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp *chip = card->private_data; int i; @@ -1492,29 +1491,15 @@ static int snd_atiixp_suspend(struct device *dev) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); snd_atiixp_chip_stop(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_atiixp_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); @@ -1585,8 +1570,7 @@ static int snd_atiixp_free(struct atiixp *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->remap_addr) - iounmap(chip->remap_addr); + iounmap(chip->remap_addr); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index b2f63e0727de..0a38e08164ab 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -19,7 +19,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -1120,7 +1120,6 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) */ static int snd_atiixp_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp_modem *chip = card->private_data; int i; @@ -1132,29 +1131,15 @@ static int snd_atiixp_suspend(struct device *dev) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); snd_atiixp_chip_stop(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_atiixp_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct atiixp_modem *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); @@ -1211,8 +1196,7 @@ static int snd_atiixp_free(struct atiixp_modem *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->remap_addr) - iounmap(chip->remap_addr); + iounmap(chip->remap_addr); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index 3a8fefefea77..bcc648bf6478 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -17,9 +17,8 @@ #ifndef __SOUND_AU88X0_H #define __SOUND_AU88X0_H -#ifdef __KERNEL__ #include <linux/pci.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/rawmidi.h> @@ -27,7 +26,6 @@ #include <sound/hwdep.h> #include <sound/ac97_codec.h> #include <sound/tlv.h> -#endif #ifndef CHIP_AU8820 #include "au88x0_eq.h" diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index e1cf01949fda..8d2fee7b33bd 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -229,9 +229,7 @@ static int snd_aw2_dev_free(struct snd_device *device) if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); /* release the i/o ports & memory */ - if (chip->iobase_virt) - iounmap(chip->iobase_virt); - + iounmap(chip->iobase_virt); pci_release_regions(chip->pci); /* disable the PCI entry */ pci_disable_device(chip->pci); diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c index 6d24e9536777..1d7890459334 100644 --- a/sound/pci/aw2/aw2-saa7146.c +++ b/sound/pci/aw2/aw2-saa7146.c @@ -27,7 +27,7 @@ #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/delay.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/initval.h> #include <sound/pcm.h> diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index fdbb9c05c77b..a40a2b4c8fd7 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -179,7 +179,7 @@ * - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport. */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/init.h> #include <linux/bug.h> /* WARN_ONCE */ #include <linux/pci.h> @@ -2694,7 +2694,6 @@ snd_azf3328_resume_ac97(const struct snd_azf3328 *chip) static int snd_azf3328_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_azf3328 *chip = card->private_data; u16 *saved_regs_ctrl_u16; @@ -2720,29 +2719,15 @@ snd_azf3328_suspend(struct device *dev) ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu); snd_azf3328_suspend_regs(chip, chip->opl3_io, ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_azf3328_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); const struct snd_azf3328 *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io, ARRAY_SIZE(chip->saved_regs_game)); snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io, diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 058b9973c09c..5925b7170e25 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -27,7 +27,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/bitops.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -690,8 +690,7 @@ static int snd_bt87x_free(struct snd_bt87x *chip) snd_bt87x_stop(chip); if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->mmio) - iounmap(chip->mmio); + iounmap(chip->mmio); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 96af33965b51..dd75b7536fa2 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1910,7 +1910,6 @@ static void snd_ca0106_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_ca0106_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ca0106 *chip = card->private_data; int i; @@ -1923,30 +1922,15 @@ static int snd_ca0106_suspend(struct device *dev) snd_ca0106_mixer_suspend(chip); ca0106_stop_chip(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_ca0106_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ca0106 *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - snd_card_disconnect(card); - return -EIO; - } - - pci_set_master(pci); - ca0106_init_chip(chip, 1); if (chip->details->ac97) diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 68c0eb0a2807..025805cba779 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -70,7 +70,7 @@ #include <sound/ac97_codec.h> #include <sound/info.h> #include <sound/tlv.h> -#include <asm/io.h> +#include <linux/io.h> #include "ca0106.h" diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 4f9c2821bb31..2c5c28adbefd 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -64,13 +64,13 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/moduleparam.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/initval.h> #include <sound/pcm.h> #include <sound/ac97_codec.h> #include <sound/info.h> #include <sound/asoundef.h> -#include <asm/io.h> #include "ca0106.h" diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 85ed40339db9..1d0f2cad2f5a 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -20,7 +20,7 @@ /* Does not work. Warning may block system in capture mode */ /* #define USE_VAR48KRATE */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -3347,7 +3347,6 @@ static unsigned char saved_mixers[] = { static int snd_cmipci_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cmipci *cm = card->private_data; int i; @@ -3366,29 +3365,15 @@ static int snd_cmipci_suspend(struct device *dev) /* disable ints */ snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_cmipci_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cmipci *cm = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - /* reset / initialize to a sane state */ snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); snd_cmipci_ch_reset(cm, CM_CH_PLAY); diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 4c49b5c8a7b3..c296fd0dbc9c 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -19,7 +19,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -973,14 +973,11 @@ static struct snd_pcm_ops snd_cs4281_capture_ops = { .pointer = snd_cs4281_pointer, }; -static int snd_cs4281_pcm(struct cs4281 *chip, int device, - struct snd_pcm **rpcm) +static int snd_cs4281_pcm(struct cs4281 *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(chip->card, "CS4281", device, 1, 1, &pcm); if (err < 0) return err; @@ -996,8 +993,6 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 512*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1321,10 +1316,8 @@ static int snd_cs4281_free(struct cs4281 *chip) if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->ba0) - iounmap(chip->ba0); - if (chip->ba1) - iounmap(chip->ba1); + iounmap(chip->ba0); + iounmap(chip->ba1); pci_release_regions(chip->pci); pci_disable_device(chip->pci); @@ -1788,14 +1781,11 @@ static struct snd_rawmidi_ops snd_cs4281_midi_input = .trigger = snd_cs4281_midi_input_trigger, }; -static int snd_cs4281_midi(struct cs4281 *chip, int device, - struct snd_rawmidi **rrawmidi) +static int snd_cs4281_midi(struct cs4281 *chip, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, "CS4281"); @@ -1804,8 +1794,6 @@ static int snd_cs4281_midi(struct cs4281 *chip, int device, rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return 0; } @@ -1941,11 +1929,11 @@ static int snd_cs4281_probe(struct pci_dev *pci, snd_card_free(card); return err; } - if ((err = snd_cs4281_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_cs4281_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_cs4281_midi(chip, 0, NULL)) < 0) { + if ((err = snd_cs4281_midi(chip, 0)) < 0) { snd_card_free(card); return err; } @@ -2008,7 +1996,6 @@ static int saved_regs[SUSPEND_REGISTERS] = { static int cs4281_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs4281 *chip = card->private_data; u32 ulCLK; @@ -2047,30 +2034,16 @@ static int cs4281_suspend(struct device *dev) ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1); ulCLK &= ~CLKCR1_CKRA; snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int cs4281_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs4281 *chip = card->private_data; unsigned int i; u32 ulCLK; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1); ulCLK |= CLKCR1_CKRA; snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK); diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 6a6858c07826..655fbea1692c 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -100,16 +100,16 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, } card->private_data = chip; chip->accept_valid = mmap_valid[dev]; - if ((err = snd_cs46xx_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_cs46xx_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } #ifdef CONFIG_SND_CS46XX_NEW_DSP - if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) { + if ((err = snd_cs46xx_pcm_rear(chip, 1)) < 0) { snd_card_free(card); return err; } - if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) { + if ((err = snd_cs46xx_pcm_iec958(chip, 2)) < 0) { snd_card_free(card); return err; } @@ -120,13 +120,13 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, } #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->nr_ac97_codecs ==2) { - if ((err = snd_cs46xx_pcm_center_lfe(chip,3,NULL)) < 0) { + if ((err = snd_cs46xx_pcm_center_lfe(chip, 3)) < 0) { snd_card_free(card); return err; } } #endif - if ((err = snd_cs46xx_midi(chip, 0, NULL)) < 0) { + if ((err = snd_cs46xx_midi(chip, 0)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h index c49a082c378b..9c9f89a8be5f 100644 --- a/sound/pci/cs46xx/cs46xx.h +++ b/sound/pci/cs46xx/cs46xx.h @@ -1737,12 +1737,12 @@ int snd_cs46xx_create(struct snd_card *card, struct snd_cs46xx **rcodec); extern const struct dev_pm_ops snd_cs46xx_pm; -int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); -int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); -int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); -int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm); +int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device); +int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device); +int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device); +int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device); int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device); -int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rmidi); +int snd_cs46xx_midi(struct snd_cs46xx *chip, int device); int snd_cs46xx_start_dsp(struct snd_cs46xx *chip); int snd_cs46xx_gameport(struct snd_cs46xx *chip); diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 32b44f25b5c8..8d74004b1ed2 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -57,6 +57,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/vmalloc.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> @@ -65,8 +66,6 @@ #include <sound/pcm_params.h> #include "cs46xx.h" -#include <asm/io.h> - #include "cs46xx_lib.h" #include "dsp_spos.h" @@ -1778,13 +1777,11 @@ static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = { #define MAX_PLAYBACK_CHANNELS 1 #endif -int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm) +int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0) return err; @@ -1801,23 +1798,16 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } #ifdef CONFIG_SND_CS46XX_NEW_DSP -int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, - struct snd_pcm **rpcm) +int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0) return err; @@ -1833,21 +1823,14 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } -int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, - struct snd_pcm **rpcm) +int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "CS46xx - Center LFE", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0) return err; @@ -1863,21 +1846,14 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } -int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, - struct snd_pcm **rpcm) +int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0) return err; @@ -1893,9 +1869,6 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; - return 0; } #endif @@ -2724,13 +2697,11 @@ static struct snd_rawmidi_ops snd_cs46xx_midi_input = .trigger = snd_cs46xx_midi_input_trigger, }; -int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi) +int snd_cs46xx_midi(struct snd_cs46xx *chip, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, "CS46XX"); @@ -2739,8 +2710,6 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rr rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = NULL; return 0; } @@ -2979,8 +2948,8 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip) for (idx = 0; idx < 5; idx++) { struct snd_cs46xx_region *region = &chip->region.idx[idx]; - if (region->remap_addr) - iounmap(region->remap_addr); + + iounmap(region->remap_addr); release_and_free_resource(region->resource); } @@ -3804,7 +3773,6 @@ static unsigned int saved_regs[] = { static int snd_cs46xx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_cs46xx *chip = card->private_data; int i, amp_saved; @@ -3829,16 +3797,11 @@ static int snd_cs46xx_suspend(struct device *dev) /* disable CLKRUN */ chip->active_ctrl(chip, -chip->amplifier); chip->amplifier = amp_saved; /* restore the status */ - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_cs46xx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_cs46xx *chip = card->private_data; int amp_saved; @@ -3847,15 +3810,6 @@ static int snd_cs46xx_resume(struct device *dev) #endif unsigned int tmp; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - amp_saved = chip->amplifier; chip->amplifier = 0; chip->active_ctrl(chip, 1); /* force to on */ diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 1c4a0fb3ffef..5c99efb004c0 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -20,7 +20,7 @@ */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/init.h> diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 8284bc9b5858..2c90c0bded69 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -21,7 +21,7 @@ */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/init.h> diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index b1025507a467..0a8cf94c4858 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -223,7 +223,7 @@ static int snd_cs5530_create(struct snd_card *card, return err; } - err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm); + err = snd_sb16dsp_pcm(chip->sb, 0); if (err < 0) { dev_err(card->dev, "Could not create PCM\n"); snd_cs5530_free(chip); diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 16288e4d338a..802c33f1cc59 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -27,7 +27,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 34cc60057d0c..06ac5d8da362 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -57,7 +57,6 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au) static int snd_cs5535audio_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs5535audio *cs5535au = card->private_data; int i; @@ -72,34 +71,17 @@ static int snd_cs5535audio_suspend(struct device *dev) } /* save important regs, then disable aclink in hw */ snd_cs5535audio_stop_hardware(cs5535au); - - if (pci_save_state(pci)) { - dev_err(dev, "pci_save_state failed!\n"); - return -EIO; - } - pci_disable_device(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_cs5535audio_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct cs5535audio *cs5535au = card->private_data; u32 tmp; int timeout; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - /* set LNK_WRM_RST to reset AC link */ cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST); diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index b425aa8ee578..1cac55fd1139 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1985,10 +1985,7 @@ static int hw_card_shutdown(struct hw *hw) free_irq(hw->irq, hw); hw->irq = -1; - - if (hw->mem_base) - iounmap(hw->mem_base); - + iounmap(hw->mem_base); hw->mem_base = NULL; if (hw->io_base) @@ -2099,20 +2096,11 @@ static int hw_suspend(struct hw *hw) pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0); } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); - return 0; } static int hw_resume(struct hw *hw, struct card_conf *info) { - struct pci_dev *pci = hw->pci; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - /* Re-initialize card hardware. */ return hw_card_init(hw, info); } diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 253899d13790..955ad871e9a8 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -2110,10 +2110,7 @@ static int hw_card_shutdown(struct hw *hw) free_irq(hw->irq, hw); hw->irq = -1; - - if (hw->mem_base) - iounmap(hw->mem_base); - + iounmap(hw->mem_base); hw->mem_base = NULL; if (hw->io_base) @@ -2209,24 +2206,12 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) #ifdef CONFIG_PM_SLEEP static int hw_suspend(struct hw *hw) { - struct pci_dev *pci = hw->pci; - hw_card_stop(hw); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); - return 0; } static int hw_resume(struct hw *hw, struct card_conf *info) { - struct pci_dev *pci = hw->pci; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - /* Re-initialize card hardware. */ return hw_card_init(hw, info); } diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index 4632946205a8..c95da6301677 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c @@ -43,6 +43,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -51,7 +52,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index f81c839cc887..3013b4daa19e 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c @@ -47,6 +47,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -55,7 +56,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 3a5346c33d76..1f34a07b0b19 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c @@ -54,6 +54,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -63,7 +64,6 @@ #include <sound/asoundef.h> #include <sound/initval.h> #include <sound/rawmidi.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 21228adaa70c..a962de03ebb6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1872,12 +1872,8 @@ static int snd_echo_free(struct echoaudio *chip) if (chip->comm_page) snd_dma_free_pages(&chip->commpage_dma_buf); - if (chip->dsp_registers) - iounmap(chip->dsp_registers); - + iounmap(chip->dsp_registers); release_and_free_resource(chip->iores); - - pci_disable_device(chip->pci); /* release chip data */ @@ -2162,7 +2158,6 @@ ctl_error: static int snd_echo_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct echoaudio *chip = dev_get_drvdata(dev); snd_pcm_suspend_all(chip->analog_pcm); @@ -2188,9 +2183,6 @@ static int snd_echo_suspend(struct device *dev) chip->dsp_code = NULL; free_irq(chip->irq, chip); chip->irq = -1; - pci_save_state(pci); - pci_disable_device(pci); - return 0; } @@ -2204,7 +2196,6 @@ static int snd_echo_resume(struct device *dev) u32 pipe_alloc_mask; int err; - pci_restore_state(pci); commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); if (commpage_bak == NULL) return -ENOMEM; diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index 9cb81c500824..4fa32a2e97db 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c @@ -47,6 +47,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -55,7 +56,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index 35d3e6eac990..b1bcacaef257 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c @@ -53,6 +53,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -61,7 +62,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 8d91842d1268..175af9b1435f 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c @@ -45,6 +45,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -53,7 +54,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 289cb969f5b9..8c60314e4901 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c @@ -45,6 +45,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -53,7 +54,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index 405a3f2e496f..f7618edfd79c 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c @@ -46,6 +46,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -54,7 +55,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index b392dd776b71..12e5d2164dc4 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c @@ -52,6 +52,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -61,7 +62,6 @@ #include <sound/asoundef.h> #include <sound/initval.h> #include <sound/rawmidi.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index bc7f730b0ec6..6e4023728ef5 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c @@ -54,6 +54,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -63,7 +64,6 @@ #include <sound/asoundef.h> #include <sound/initval.h> #include <sound/rawmidi.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index 27a9a6e5db2d..2f7562f1aefb 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c @@ -53,6 +53,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -62,7 +63,6 @@ #include <sound/asoundef.h> #include <sound/initval.h> #include <sound/rawmidi.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index d913749d154a..a8fe58335ddc 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -257,9 +257,8 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream spin_lock_irq(&chip->lock); if (up) { if (!chip->tinuse) { - init_timer(&chip->timer); - chip->timer.function = snd_echo_midi_output_write; - chip->timer.data = (unsigned long)chip; + setup_timer(&chip->timer, snd_echo_midi_output_write, + (unsigned long)chip); chip->tinuse = 1; } } else { diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 3d13875c303d..34d499466393 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c @@ -51,6 +51,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -59,7 +60,6 @@ #include <sound/pcm_params.h> #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> #include <linux/atomic.h> #include "echoaudio.h" diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4c171636efcd..37d0220a094c 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -132,11 +132,11 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, goto error; card->private_data = emu; emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; - if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) + if ((err = snd_emu10k1_pcm(emu, 0)) < 0) goto error; - if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) + if ((err = snd_emu10k1_pcm_mic(emu, 1)) < 0) goto error; - if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) + if ((err = snd_emu10k1_pcm_efx(emu, 2)) < 0) goto error; /* This stores the periods table. */ if (emu->card_capabilities->ca0151_chip) { /* P16V */ @@ -151,10 +151,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, if ((err = snd_emu10k1_timer(emu, 0)) < 0) goto error; - if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) + if ((err = snd_emu10k1_pcm_multi(emu, 3)) < 0) goto error; if (emu->card_capabilities->ca0151_chip) { /* P16V */ - if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) + if ((err = snd_p16v_pcm(emu, 4)) < 0) goto error; } if (emu->audigy) { @@ -164,7 +164,7 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, if ((err = snd_emu10k1_midi(emu)) < 0) goto error; } - if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0) + if ((err = snd_emu10k1_fx8010_new(emu, 0)) < 0) goto error; #ifdef ENABLE_SYNTH if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, @@ -210,7 +210,6 @@ static void snd_card_emu10k1_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_emu10k1_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_emu10k1 *emu = card->private_data; @@ -232,28 +231,14 @@ static int snd_emu10k1_suspend(struct device *dev) snd_p16v_suspend(emu); snd_emu10k1_done(emu); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_emu10k1_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_emu10k1 *emu = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_emu10k1_resume_init(emu); snd_emu10k1_efx_resume(emu); snd_ac97_resume(emu->ac97); diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 15933f92f63a..6d1b98d14327 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -847,15 +847,13 @@ static const struct snd_pcm_chmap_elem clfe_map[] = { { } }; -static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm) +static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device) { struct snd_pcm *pcm; const struct snd_pcm_chmap_elem *map = NULL; int err; int capture = 0; - if (rpcm) - *rpcm = NULL; if (device == 0) capture = 1; @@ -896,15 +894,8 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **r snd_dma_pci_data(emu->pci), 32*1024, 32*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, 1 << 2, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - - return 0; } static int snd_emu10k1x_create(struct snd_card *card, @@ -1583,15 +1574,15 @@ static int snd_emu10k1x_probe(struct pci_dev *pci, return err; } - if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_emu10k1x_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_pcm(chip, 1, NULL)) < 0) { + if ((err = snd_emu10k1x_pcm(chip, 1)) < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_pcm(chip, 2, NULL)) < 0) { + if ((err = snd_emu10k1x_pcm(chip, 2)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index eb5c0aba41c1..56fc47bd6dba 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -2641,14 +2641,11 @@ static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file) return 0; } -int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, - struct snd_hwdep **rhwdep) +int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device) { struct snd_hwdep *hw; int err; - if (rhwdep) - *rhwdep = NULL; if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0) return err; strcpy(hw->name, "EMU10K1 (FX8010)"); @@ -2657,8 +2654,6 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, hw->ops.ioctl = snd_emu10k1_fx8010_ioctl; hw->ops.release = snd_emu10k1_fx8010_release; hw->private_data = emu; - if (rhwdep) - *rhwdep = hw; return 0; } diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index f82481bd2542..0dc07385af0e 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1400,15 +1400,12 @@ static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = { .page = snd_pcm_sgbuf_ops_page, }; -int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) +int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0) return err; @@ -1429,22 +1426,15 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); - if (rpcm) - *rpcm = pcm; - return 0; } -int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device, - struct snd_pcm **rpcm) +int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0) return err; @@ -1461,9 +1451,6 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device, if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) return err; - if (rpcm) - *rpcm = pcm; - return 0; } @@ -1479,15 +1466,11 @@ static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = { .pointer = snd_emu10k1_capture_pointer, }; -int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device, - struct snd_pcm **rpcm) +int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0) return err; @@ -1501,8 +1484,6 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1822,16 +1803,12 @@ static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = { .ack = snd_emu10k1_fx8010_playback_transfer, }; -int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device, - struct snd_pcm **rpcm) +int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_kcontrol *kctl; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0) return err; @@ -1843,8 +1820,6 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device, pcm->info_flags = 0; strcpy(pcm->name, "Multichannel Capture/PT Playback"); emu->pcm_efx = pcm; - if (rpcm) - *rpcm = pcm; /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs * to these diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 7ef3898a7806..3c60b433de9f 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -166,11 +166,8 @@ static struct snd_pcm_hardware snd_p16v_capture_hw = { static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime) { struct snd_emu10k1_pcm *epcm = runtime->private_data; - - if (epcm) { - /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */ - kfree(epcm); - } + + kfree(epcm); } /* open_playback callback */ @@ -640,7 +637,7 @@ int snd_p16v_free(struct snd_emu10k1 *chip) return 0; } -int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) +int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -649,8 +646,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */ emu->p16v_device_offset = device; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) return err; @@ -694,9 +689,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) */ } - if (rpcm) - *rpcm = pcm; - return 0; } diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index d94cb3ca7a64..0dc44ebb0032 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -26,7 +26,7 @@ * by Kurt J. Bosch */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -1268,14 +1268,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device, - struct snd_pcm **rpcm) +static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm); if (err < 0) return err; @@ -1302,22 +1299,14 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device, err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_std_chmaps, 2, 0, NULL); #endif - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; + return err; } -static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device, - struct snd_pcm **rpcm) +static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm); if (err < 0) return err; @@ -1342,12 +1331,7 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device, err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, surround_map, 2, 0, NULL); #endif - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; + return err; } /* @@ -2049,7 +2033,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq) #ifdef CONFIG_PM_SLEEP static int snd_ensoniq_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct ensoniq *ensoniq = card->private_data; @@ -2070,28 +2053,14 @@ static int snd_ensoniq_suspend(struct device *dev) udelay(100); snd_ak4531_suspend(ensoniq->u.es1370.ak4531); #endif - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_ensoniq_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct ensoniq *ensoniq = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_ensoniq_chip_init(ensoniq); #ifdef CHIP1371 @@ -2362,14 +2331,11 @@ static struct snd_rawmidi_ops snd_ensoniq_midi_input = .trigger = snd_ensoniq_midi_input_trigger, }; -static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device, - struct snd_rawmidi **rrawmidi) +static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device) { struct snd_rawmidi *rmidi; int err; - if (rrawmidi) - *rrawmidi = NULL; if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, CHIP_NAME); @@ -2379,8 +2345,6 @@ static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device, SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = ensoniq; ensoniq->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = rmidi; return 0; } @@ -2462,15 +2426,15 @@ static int snd_audiopci_probe(struct pci_dev *pci, return err; } #endif - if ((err = snd_ensoniq_pcm(ensoniq, 0, NULL)) < 0) { + if ((err = snd_ensoniq_pcm(ensoniq, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_ensoniq_pcm2(ensoniq, 1, NULL)) < 0) { + if ((err = snd_ensoniq_pcm2(ensoniq, 1)) < 0) { snd_card_free(card); return err; } - if ((err = snd_ensoniq_midi(ensoniq, 0, NULL)) < 0) { + if ((err = snd_ensoniq_midi(ensoniq, 0)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 0fc46eb4e251..e1858d9d23d8 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -55,6 +55,7 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/dma-mapping.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> @@ -63,8 +64,6 @@ #include <sound/initval.h> #include <sound/tlv.h> -#include <asm/io.h> - MODULE_AUTHOR("Jaromir Koutek <miri@punknet.cz>"); MODULE_DESCRIPTION("ESS Solo-1"); MODULE_LICENSE("GPL"); @@ -1454,7 +1453,6 @@ static unsigned char saved_regs[SAVED_REG_SIZE+1] = { static int es1938_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct es1938 *chip = card->private_data; unsigned char *s, *d; @@ -1471,9 +1469,6 @@ static int es1938_suspend(struct device *dev) free_irq(chip->irq, chip); chip->irq = -1; } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -1484,14 +1479,6 @@ static int es1938_resume(struct device *dev) struct es1938 *chip = card->private_data; unsigned char *s, *d; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(dev, "unable to grab IRQ %d, disabling device\n", diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 6039700f8579..059f3846d7b8 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -94,7 +94,7 @@ * places. */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -2383,7 +2383,6 @@ static void snd_es1968_start_irq(struct es1968 *chip) */ static int es1968_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct es1968 *chip = card->private_data; @@ -2396,16 +2395,11 @@ static int es1968_suspend(struct device *dev) snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); snd_es1968_bob_stop(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int es1968_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct es1968 *chip = card->private_data; struct esschan *es; @@ -2413,16 +2407,6 @@ static int es1968_resume(struct device *dev) if (! chip->do_pm) return 0; - /* restore all our config */ - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_es1968_chip_init(chip); /* need to restore the base pointers.. */ diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index d167afffce5f..1fdd92b6f18f 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -2,8 +2,6 @@ * The driver for the ForteMedia FM801 based soundcards * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * - * Support FM only card by Andy Shevchenko <andy@smile.org.ua> - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -14,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <linux/delay.h> @@ -704,13 +698,11 @@ static struct snd_pcm_ops snd_fm801_capture_ops = { .pointer = snd_fm801_capture_pointer, }; -static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm) +static int snd_fm801_pcm(struct fm801 *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0) return err; @@ -726,16 +718,10 @@ static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm) snd_dma_pci_data(chip->pci), chip->multichannel ? 128*1024 : 64*1024, 128*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_alt_chmaps, chip->multichannel ? 6 : 2, 0, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; } /* @@ -1186,12 +1172,6 @@ static int snd_fm801_free(struct fm801 *chip) v4l2_device_unregister(&chip->v4l2_dev); } #endif - if (chip->irq >= 0) - free_irq(chip->irq, chip); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - - kfree(chip); return 0; } @@ -1214,28 +1194,23 @@ static int snd_fm801_create(struct snd_card *card, }; *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + if ((err = pcim_enable_device(pci)) < 0) return err; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); + chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL); + if (chip == NULL) return -ENOMEM; - } spin_lock_init(&chip->reg_lock); chip->card = card; chip->pci = pci; chip->irq = -1; chip->tea575x_tuner = tea575x_tuner; - if ((err = pci_request_regions(pci, "FM801")) < 0) { - kfree(chip); - pci_disable_device(pci); + if ((err = pci_request_regions(pci, "FM801")) < 0) return err; - } chip->port = pci_resource_start(pci, 0); if ((tea575x_tuner & TUNER_ONLY) == 0) { - if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { - dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq); + if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip)) { + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_fm801_free(chip); return -EBUSY; } @@ -1250,12 +1225,6 @@ static int snd_fm801_create(struct snd_card *card, /* init might set tuner access method */ tea575x_tuner = chip->tea575x_tuner; - if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) { - pci_clear_master(pci); - free_irq(chip->irq, chip); - chip->irq = -1; - } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); return err; @@ -1340,7 +1309,7 @@ static int snd_card_fm801_probe(struct pci_dev *pci, if (chip->tea575x_tuner & TUNER_ONLY) goto __fm801_tuner_only; - if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_fm801_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } @@ -1392,7 +1361,6 @@ static unsigned char saved_regs[] = { static int snd_fm801_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct fm801 *chip = card->private_data; int i; @@ -1404,29 +1372,15 @@ static int snd_fm801_suspend(struct device *dev) for (i = 0; i < ARRAY_SIZE(saved_regs); i++) chip->saved_regs[i] = inw(chip->port + saved_regs[i]); /* FIXME: tea575x suspend */ - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_fm801_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct fm801 *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_fm801_chip_init(chip, 1); snd_ac97_resume(chip->ac97); snd_ac97_resume(chip->ac97_sec); diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index ebf4c2fb99df..7f0f2c5a4e97 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -107,6 +107,7 @@ config SND_HDA_PATCH_LOADER config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" select SND_HDA_GENERIC + select INPUT help Say Y or M here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 1ede82200ee5..3f8706bb3d16 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -409,10 +409,10 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, /* * debug prints of the parsed results */ - codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", - cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], - cfg->line_out_pins[2], cfg->line_out_pins[3], - cfg->line_out_pins[4], + codec_info(codec, "autoconfig for %s: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", + codec->chip_name, cfg->line_outs, cfg->line_out_pins[0], + cfg->line_out_pins[1], cfg->line_out_pins[2], + cfg->line_out_pins[3], cfg->line_out_pins[4], cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? "speaker" : "line")); @@ -920,6 +920,8 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, codec->fixup_id = pq->value; #ifdef CONFIG_SND_DEBUG_VERBOSE codec->fixup_name = pq->name; + codec_dbg(codec, "%s: picked fixup %s (pin match)\n", + codec->chip_name, codec->fixup_name); #endif codec->fixup_list = fixlist; return; @@ -960,6 +962,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, codec->fixup_list = NULL; codec->fixup_name = NULL; codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP; + codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n", + codec->chip_name); return; } @@ -969,6 +973,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, codec->fixup_id = models->id; codec->fixup_name = models->name; codec->fixup_list = fixlist; + codec_dbg(codec, "%s: picked fixup %s (model specified)\n", + codec->chip_name, codec->fixup_name); return; } models++; @@ -980,6 +986,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, id = q->value; #ifdef CONFIG_SND_DEBUG_VERBOSE name = q->name; + codec_dbg(codec, "%s: picked fixup %s (PCI SSID%s)\n", + codec->chip_name, name, q->subdevice_mask ? "" : " - vendor generic"); #endif } } @@ -992,6 +1000,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, id = q->value; #ifdef CONFIG_SND_DEBUG_VERBOSE name = q->name; + codec_dbg(codec, "%s: picked fixup %s (codec SSID)\n", + codec->chip_name, name); #endif break; } diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 0cfc9c8c4b4e..a2ce773bdc62 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -657,6 +657,9 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); if (start) { azx_timecounter_init(substream, 0, 0); + snd_pcm_gettime(substream->runtime, &substream->runtime->trigger_tstamp); + substream->runtime->trigger_tstamp_latched = true; + if (nsync > 1) { cycle_t cycle_last; @@ -939,7 +942,8 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, chip->card->dev, size, MAX_PREALLOC_SIZE); /* link to codec */ - pcm->dev = &codec->dev; + for (s = 0; s < 2; s++) + pcm->streams[s].dev.parent = &codec->dev; return 0; } @@ -957,7 +961,6 @@ static int azx_alloc_cmd_io(struct azx *chip) dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n"); return err; } -EXPORT_SYMBOL_GPL(azx_alloc_cmd_io); static void azx_init_cmd_io(struct azx *chip) { @@ -1022,7 +1025,6 @@ static void azx_init_cmd_io(struct azx *chip) azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); spin_unlock_irq(&chip->reg_lock); } -EXPORT_SYMBOL_GPL(azx_init_cmd_io); static void azx_free_cmd_io(struct azx *chip) { @@ -1032,7 +1034,6 @@ static void azx_free_cmd_io(struct azx *chip) azx_writeb(chip, CORBCTL, 0); spin_unlock_irq(&chip->reg_lock); } -EXPORT_SYMBOL_GPL(azx_free_cmd_io); static unsigned int azx_command_addr(u32 cmd) { @@ -1312,7 +1313,6 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val) else return azx_corb_send_cmd(bus, val); } -EXPORT_SYMBOL_GPL(azx_send_cmd); /* get a response */ static unsigned int azx_get_response(struct hda_bus *bus, @@ -1326,7 +1326,6 @@ static unsigned int azx_get_response(struct hda_bus *bus, else return azx_rirb_get_response(bus, addr); } -EXPORT_SYMBOL_GPL(azx_get_response); #ifdef CONFIG_SND_HDA_DSP_LOADER /* @@ -1993,4 +1992,4 @@ void azx_notifier_unregister(struct azx *chip) EXPORT_SYMBOL_GPL(azx_notifier_unregister); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Common HDA driver funcitons"); +MODULE_DESCRIPTION("Common HDA driver functions"); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 014a7849e8fd..11b5a42b4ec8 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -109,7 +109,6 @@ int snd_hda_create_hwdep(struct hda_codec *codec) hwdep->iface = SNDRV_HWDEP_IFACE_HDA; hwdep->private_data = codec; hwdep->exclusive = 1; - hwdep->groups = snd_hda_dev_attr_groups; hwdep->ops.open = hda_hwdep_open; hwdep->ops.ioctl = hda_hwdep_ioctl; @@ -118,7 +117,11 @@ int snd_hda_create_hwdep(struct hda_codec *codec) #endif /* link to codec */ - hwdep->dev = &codec->dev; + hwdep->dev.parent = &codec->dev; + + /* for sysfs */ + hwdep->dev.groups = snd_hda_dev_attr_groups; + dev_set_drvdata(&hwdep->dev, codec); return 0; } diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index d4d0375ac181..714894527e06 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -18,10 +18,12 @@ #include <linux/init.h> #include <linux/module.h> +#include <linux/pci.h> +#include <linux/component.h> +#include <drm/i915_component.h> #include <sound/core.h> -#include <drm/i915_powerwell.h> #include "hda_priv.h" -#include "hda_i915.h" +#include "hda_intel.h" /* Intel HSW/BDW display HDA controller Extended Mode registers. * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display @@ -31,32 +33,33 @@ #define AZX_REG_EM4 0x100c #define AZX_REG_EM5 0x1010 -static int (*get_power)(void); -static int (*put_power)(void); -static int (*get_cdclk)(void); - -int hda_display_power(bool enable) +int hda_display_power(struct hda_intel *hda, bool enable) { - if (!get_power || !put_power) + struct i915_audio_component *acomp = &hda->audio_component; + + if (!acomp->ops) return -ENODEV; - pr_debug("HDA display power %s \n", - enable ? "Enable" : "Disable"); + dev_dbg(&hda->chip.pci->dev, "display power %s\n", + enable ? "enable" : "disable"); if (enable) - return get_power(); + acomp->ops->get_power(acomp->dev); else - return put_power(); + acomp->ops->put_power(acomp->dev); + + return 0; } -void haswell_set_bclk(struct azx *chip) +void haswell_set_bclk(struct hda_intel *hda) { int cdclk_freq; unsigned int bclk_m, bclk_n; + struct i915_audio_component *acomp = &hda->audio_component; - if (!get_cdclk) + if (!acomp->ops) return; - cdclk_freq = get_cdclk(); + cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); switch (cdclk_freq) { case 337500: bclk_m = 16; @@ -80,51 +83,108 @@ void haswell_set_bclk(struct azx *chip) break; } - azx_writew(chip, EM4, bclk_m); - azx_writew(chip, EM5, bclk_n); + azx_writew(&hda->chip, EM4, bclk_m); + azx_writew(&hda->chip, EM5, bclk_n); } - -int hda_i915_init(void) +static int hda_component_master_bind(struct device *dev) { - int err = 0; - - get_power = symbol_request(i915_request_power_well); - if (!get_power) { - pr_warn("hda-i915: get_power symbol get fail\n"); - return -ENODEV; + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct i915_audio_component *acomp = &hda->audio_component; + int ret; + + ret = component_bind_all(dev, acomp); + if (ret < 0) + return ret; + + if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power && + acomp->ops->put_power && acomp->ops->get_cdclk_freq))) { + ret = -EINVAL; + goto out_unbind; } - put_power = symbol_request(i915_release_power_well); - if (!put_power) { - symbol_put(i915_request_power_well); - get_power = NULL; - return -ENODEV; + /* + * Atm, we don't support dynamic unbinding initiated by the child + * component, so pin its containing module until we unbind. + */ + if (!try_module_get(acomp->ops->owner)) { + ret = -ENODEV; + goto out_unbind; } - get_cdclk = symbol_request(i915_get_cdclk_freq); - if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ - pr_warn("hda-i915: get_cdclk symbol get fail\n"); + return 0; - pr_debug("HDA driver get symbol successfully from i915 module\n"); +out_unbind: + component_unbind_all(dev, acomp); - return err; + return ret; } -int hda_i915_exit(void) +static void hda_component_master_unbind(struct device *dev) { - if (get_power) { - symbol_put(i915_request_power_well); - get_power = NULL; - } - if (put_power) { - symbol_put(i915_release_power_well); - put_power = NULL; - } - if (get_cdclk) { - symbol_put(i915_get_cdclk_freq); - get_cdclk = NULL; + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct i915_audio_component *acomp = &hda->audio_component; + + module_put(acomp->ops->owner); + component_unbind_all(dev, acomp); + WARN_ON(acomp->ops || acomp->dev); +} + +static const struct component_master_ops hda_component_master_ops = { + .bind = hda_component_master_bind, + .unbind = hda_component_master_unbind, +}; + +static int hda_component_master_match(struct device *dev, void *data) +{ + /* i915 is the only supported component */ + return !strcmp(dev->driver->name, "i915"); +} + +int hda_i915_init(struct hda_intel *hda) +{ + struct component_match *match = NULL; + struct device *dev = &hda->chip.pci->dev; + struct i915_audio_component *acomp = &hda->audio_component; + int ret; + + component_match_add(dev, &match, hda_component_master_match, hda); + ret = component_master_add_with_match(dev, &hda_component_master_ops, + match); + if (ret < 0) + goto out_err; + + /* + * Atm, we don't support deferring the component binding, so make sure + * i915 is loaded and that the binding successfully completes. + */ + request_module("i915"); + + if (!acomp->ops) { + ret = -ENODEV; + goto out_master_del; } + dev_dbg(dev, "bound to i915 component master\n"); + + return 0; +out_master_del: + component_master_del(dev, &hda_component_master_ops); +out_err: + dev_err(dev, "failed to add i915 component master (%d)\n", ret); + + return ret; +} + +int hda_i915_exit(struct hda_intel *hda) +{ + struct device *dev = &hda->chip.pci->dev; + + component_master_del(dev, &hda_component_master_ops); + return 0; } diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h deleted file mode 100644 index e6072c627583..000000000000 --- a/sound/pci/hda/hda_i915.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __SOUND_HDA_I915_H -#define __SOUND_HDA_I915_H - -#ifdef CONFIG_SND_HDA_I915 -int hda_display_power(bool enable); -void haswell_set_bclk(struct azx *chip); -int hda_i915_init(void); -int hda_i915_exit(void); -#else -static inline int hda_display_power(bool enable) { return 0; } -static inline void haswell_set_bclk(struct azx *chip) { return; } -static inline int hda_i915_init(void) -{ - return -ENODEV; -} -static inline int hda_i915_exit(void) -{ - return 0; -} -#endif - -#endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d426a0bd6a5f..4ca3d5d02436 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include "hda_codec.h" #include "hda_controller.h" #include "hda_priv.h" -#include "hda_i915.h" +#include "hda_intel.h" /* position fix mode */ enum { @@ -354,31 +354,6 @@ static char *driver_short_names[] = { [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; -struct hda_intel { - struct azx chip; - - /* for pending irqs */ - struct work_struct irq_pending_work; - - /* sync probing */ - struct completion probe_wait; - struct work_struct probe_work; - - /* card list (for power_save trigger) */ - struct list_head list; - - /* extra flags */ - unsigned int irq_pending_warned:1; - - /* VGA-switcheroo setup */ - unsigned int use_vga_switcheroo:1; - unsigned int vga_switcheroo_registered:1; - unsigned int init_failed:1; /* delayed init failed */ - - /* secondary power domain for hdmi audio under vga device */ - struct dev_pm_domain hdmi_pm_domain; -}; - #ifdef CONFIG_X86 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) { @@ -795,7 +770,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) */ static int azx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; @@ -824,11 +798,8 @@ static int azx_suspend(struct device *dev) if (chip->msi) pci_disable_msi(chip->pci); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(false); + hda_display_power(hda, false); return 0; } @@ -848,18 +819,9 @@ static int azx_resume(struct device *dev) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(true); - haswell_set_bclk(chip); - } - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(chip->card->dev, - "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; + hda_display_power(hda, true); + haswell_set_bclk(hda); } - pci_set_master(pci); if (chip->msi) if (pci_enable_msi(pci) < 0) chip->msi = 0; @@ -901,7 +863,7 @@ static int azx_runtime_suspend(struct device *dev) azx_enter_link_reset(chip); azx_clear_irq_pending(chip); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(false); + hda_display_power(hda, false); return 0; } @@ -927,8 +889,8 @@ static int azx_runtime_resume(struct device *dev) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(true); - haswell_set_bclk(chip); + hda_display_power(hda, true); + haswell_set_bclk(hda); } /* Read STATESTS before controller reset */ @@ -1138,8 +1100,7 @@ static int azx_free(struct azx *chip) free_irq(chip->irq, (void*)chip); if (chip->msi) pci_disable_msi(chip->pci); - if (chip->remap_addr) - iounmap(chip->remap_addr); + iounmap(chip->remap_addr); azx_free_stream_pages(chip); if (chip->region_requested) @@ -1150,8 +1111,8 @@ static int azx_free(struct azx *chip) release_firmware(chip->fw); #endif if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(false); - hda_i915_exit(); + hda_display_power(hda, false); + hda_i915_exit(hda); } kfree(hda); @@ -1629,8 +1590,12 @@ static int azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - haswell_set_bclk(chip); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + struct hda_intel *hda; + + hda = container_of(chip, struct hda_intel, chip); + haswell_set_bclk(hda); + } azx_init_chip(chip, (probe_only[dev] & 2) == 0); @@ -1910,13 +1875,10 @@ static int azx_probe_continue(struct azx *chip) /* Request power well for Haswell HDA controller and codec */ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { #ifdef CONFIG_SND_HDA_I915 - err = hda_i915_init(); - if (err < 0) { - dev_err(chip->card->dev, - "Error request power-well from i915\n"); + err = hda_i915_init(hda); + if (err < 0) goto out_free; - } - err = hda_display_power(true); + err = hda_display_power(hda, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); @@ -2004,7 +1966,7 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h new file mode 100644 index 000000000000..348611835476 --- /dev/null +++ b/sound/pci/hda/hda_intel.h @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __SOUND_HDA_INTEL_H +#define __SOUND_HDA_INTEL_H + +#include <drm/i915_component.h> +#include "hda_priv.h" + +struct hda_intel { + struct azx chip; + + /* for pending irqs */ + struct work_struct irq_pending_work; + + /* sync probing */ + struct completion probe_wait; + struct work_struct probe_work; + + /* card list (for power_save trigger) */ + struct list_head list; + + /* extra flags */ + unsigned int irq_pending_warned:1; + + /* VGA-switcheroo setup */ + unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; + unsigned int init_failed:1; /* delayed init failed */ + + /* secondary power domain for hdmi audio under vga device */ + struct dev_pm_domain hdmi_pm_domain; + + /* i915 component interface */ + struct i915_audio_component audio_component; +}; + +#ifdef CONFIG_SND_HDA_I915 +int hda_display_power(struct hda_intel *hda, bool enable); +void haswell_set_bclk(struct hda_intel *hda); +int hda_i915_init(struct hda_intel *hda); +int hda_i915_exit(struct hda_intel *hda); +#else +static inline int hda_display_power(struct hda_intel *hda, bool enable) +{ + return 0; +} +static inline void haswell_set_bclk(struct hda_intel *hda) { return; } +static inline int hda_i915_init(struct hda_intel *hda) +{ + return -ENODEV; +} +static inline int hda_i915_exit(struct hda_intel *hda) +{ + return 0; +} +#endif + +#endif diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 166e3e84b963..daf458299753 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -15,7 +15,7 @@ #ifndef __SOUND_HDA_PRIV_H #define __SOUND_HDA_PRIV_H -#include <linux/clocksource.h> +#include <linux/timecounter.h> #include <sound/core.h> #include <sound/pcm.h> diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 227990bc02e3..375e94f4cf52 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -329,8 +329,8 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hda->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(chip->remap_addr)) - return PTR_ERR(chip->remap_addr); + if (IS_ERR(hda->regs)) + return PTR_ERR(hda->regs); chip->remap_addr = hda->regs + HDA_BAR0; chip->addr = res->start + HDA_BAR0; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index a9d78e275138..d285904cdb64 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -739,39 +739,6 @@ static int patch_ad1981(struct hda_codec *codec) * E/F quad mic array */ -#ifdef ENABLE_AD_STATIC_QUIRKS -static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, spec->multiout.max_channels); -} - -static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return err; -} -#endif /* ENABLE_AD_STATIC_QUIRKS */ - static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 65f1f4e18ea5..b2b24a8b3dac 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -29,6 +29,7 @@ #include <linux/pci.h> #include <linux/dmi.h> #include <linux/module.h> +#include <linux/input.h> #include <sound/core.h> #include <sound/jack.h> #include "hda_codec.h" @@ -120,6 +121,7 @@ struct alc_spec { hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; + struct input_dev *kb_dev; }; /* @@ -3472,6 +3474,79 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec, } } +static void gpio2_mic_hotkey_event(struct hda_codec *codec, + struct hda_jack_callback *event) +{ + struct alc_spec *spec = codec->spec; + + /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore + send both key on and key off event for every interrupt. */ + input_report_key(spec->kb_dev, KEY_MICMUTE, 1); + input_sync(spec->kb_dev); + input_report_key(spec->kb_dev, KEY_MICMUTE, 0); + input_sync(spec->kb_dev); +} + +static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* GPIO1 = set according to SKU external amp + GPIO2 = mic mute hotkey + GPIO3 = mute LED + GPIO4 = mic mute LED */ + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a }, + { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 }, + {} + }; + + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->kb_dev = input_allocate_device(); + if (!spec->kb_dev) { + codec_err(codec, "Out of memory (input_allocate_device)\n"); + return; + } + spec->kb_dev->name = "Microphone Mute Button"; + spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY); + spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE); + if (input_register_device(spec->kb_dev)) { + codec_err(codec, "input_register_device failed\n"); + input_free_device(spec->kb_dev); + spec->kb_dev = NULL; + return; + } + + snd_hda_add_verbs(codec, gpio_init); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04); + snd_hda_jack_detect_enable_callback(codec, codec->afg, + gpio2_mic_hotkey_event); + + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; + spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; + spec->gpio_led = 0; + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x08; + spec->gpio_mic_led_mask = 0x10; + return; + } + + if (!spec->kb_dev) + return; + + switch (action) { + case HDA_FIXUP_ACT_PROBE: + spec->init_amp = ALC_INIT_DEFAULT; + break; + case HDA_FIXUP_ACT_FREE: + input_unregister_device(spec->kb_dev); + spec->kb_dev = NULL; + } +} + static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -4341,6 +4416,8 @@ enum { ALC282_FIXUP_ASPIRE_V5_PINS, ALC280_FIXUP_HP_GPIO4, ALC286_FIXUP_HP_GPIO_LED, + ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, + ALC280_FIXUP_HP_DOCK_PINS, }; static const struct hda_fixup alc269_fixups[] = { @@ -4814,6 +4891,21 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc286_fixup_hp_gpio_led, }, + [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc280_fixup_hp_gpio2_mic_hotkey, + }, + [ALC280_FIXUP_HP_DOCK_PINS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x21011020 }, /* line-out */ + { 0x1a, 0x01a1903c }, /* headset mic */ + { 0x18, 0x2181103f }, /* line-in */ + { }, + }, + .chained = true, + .chain_id = ALC280_FIXUP_HP_GPIO4 + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4843,7 +4935,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY), /* ALC282 */ + SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), @@ -4856,6 +4950,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS), + SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS), SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 605d14003d25..87eff3173ce9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -79,6 +79,7 @@ enum { STAC_ALIENWARE_M17X, STAC_92HD89XX_HP_FRONT_JACK, STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK, + STAC_92HD73XX_ASUS_MOBO, STAC_92HD73XX_MODELS }; @@ -99,6 +100,7 @@ enum { STAC_HP_ENVY_BASS, STAC_HP_BNB13_EQ, STAC_HP_ENVY_TS_BASS, + STAC_92HD83XXX_GPIO10_EAPD, STAC_92HD83XXX_MODELS }; @@ -1910,7 +1912,18 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = { .type = HDA_FIXUP_PINS, .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs, - } + }, + [STAC_92HD73XX_ASUS_MOBO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* enable 5.1 and SPDIF out */ + { 0x0c, 0x01014411 }, + { 0x0d, 0x01014410 }, + { 0x0e, 0x01014412 }, + { 0x22, 0x014b1180 }, + { } + } + }, }; static const struct hda_model_fixup stac92hd73xx_models[] = { @@ -1922,6 +1935,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" }, { .id = STAC_DELL_EQ, .name = "dell-eq" }, { .id = STAC_ALIENWARE_M17X, .name = "alienware" }, + { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" }, {} }; @@ -1974,6 +1988,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10", + STAC_92HD73XX_ASUS_MOBO), {} /* terminator */ }; @@ -2141,6 +2157,19 @@ static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec, spec->headset_jack = 1; } +static void stac92hd83xxx_fixup_gpio10_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = + spec->gpio_data = 0x10; + spec->eapd_switch = 0; +} + static const struct hda_verb hp_bnb13_eq_verbs[] = { /* 44.1KHz base */ { 0x22, 0x7A6, 0x3E }, @@ -2656,6 +2685,10 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = { {} }, }, + [STAC_92HD83XXX_GPIO10_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_gpio10_eapd, + }, }; static const struct hda_model_fixup stac92hd83xxx_models[] = { @@ -2861,6 +2894,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a, "HP Mini", STAC_92HD83XXX_HP_LED), SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP), + SND_PCI_QUIRK(PCI_VENDOR_ID_TOSHIBA, 0xfa91, + "Toshiba Satellite S50D", STAC_92HD83XXX_GPIO10_EAPD), {} /* terminator */ }; diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c index 3981823f9094..179ef7a5f0d1 100644 --- a/sound/pci/ice1712/ak4xxx.c +++ b/sound/pci/ice1712/ak4xxx.c @@ -21,7 +21,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/slab.h> diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index b039b46152c6..f7b1523e8a82 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -880,13 +880,11 @@ static struct snd_pcm_ops snd_ice1712_capture_ops = { .pointer = snd_ice1712_capture_pointer, }; -static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm); if (err < 0) return err; @@ -902,22 +900,17 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm * snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 64*1024); - if (rpcm) - *rpcm = pcm; - dev_warn(ice->card->dev, "Consumer PCM code does not work well at the moment --jk\n"); return 0; } -static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm); if (err < 0) return err; @@ -932,9 +925,6 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pc snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = pcm; - return 0; } @@ -1260,13 +1250,11 @@ static struct snd_pcm_ops snd_ice1712_capture_pro_ops = { .pointer = snd_ice1712_capture_pro_pointer, }; -static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm); if (err < 0) return err; @@ -1282,8 +1270,6 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd snd_dma_pci_data(ice->pci), 256*1024, 256*1024); ice->pcm_pro = pcm; - if (rpcm) - *rpcm = pcm; if (ice->cs8427) { /* assign channels to iec958 */ @@ -2691,14 +2677,14 @@ static int snd_ice1712_probe(struct pci_dev *pci, c = &no_matched; __found: - err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL); + err = snd_ice1712_pcm_profi(ice, pcm_dev++); if (err < 0) { snd_card_free(card); return err; } if (ice_has_con_ac97(ice)) { - err = snd_ice1712_pcm(ice, pcm_dev++, NULL); + err = snd_ice1712_pcm(ice, pcm_dev++); if (err < 0) { snd_card_free(card); return err; @@ -2726,7 +2712,7 @@ static int snd_ice1712_probe(struct pci_dev *pci, } if (ice_has_con_ac97(ice)) { - err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL); + err = snd_ice1712_pcm_ds(ice, pcm_dev++); if (err < 0) { snd_card_free(card); return err; @@ -2798,7 +2784,6 @@ static void snd_ice1712_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_ice1712_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; @@ -2820,16 +2805,11 @@ static int snd_ice1712_suspend(struct device *dev) if (ice->pm_suspend) ice->pm_suspend(ice); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_ice1712_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; int rate; @@ -2837,16 +2817,6 @@ static int snd_ice1712_resume(struct device *dev) if (!ice->pm_suspend_enabled) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - snd_card_disconnect(card); - return -EIO; - } - - pci_set_master(pci); - if (ice->cur_rate) rate = ice->cur_rate; else diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index d73da157ea14..0b22c00642bb 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2798,7 +2798,6 @@ static void snd_vt1724_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_vt1724_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; @@ -2821,32 +2820,17 @@ static int snd_vt1724_suspend(struct device *dev) if (ice->pm_suspend) ice->pm_suspend(ice); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_vt1724_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ice1712 *ice = card->private_data; if (!ice->pm_suspend_enabled) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - snd_card_disconnect(card); - return -EIO; - } - - pci_set_master(pci); - snd_vt1724_chip_reset(ice); if (snd_vt1724_chip_init(ice) < 0) { diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index a1536c1a7ed4..4f0213427152 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -491,15 +491,17 @@ static int juli_resume(struct snd_ice1712 *ice) /* akm4358 un-reset, un-mute */ snd_akm4xxx_reset(ak, 0); /* reinit ak4114 */ - snd_ak4114_reinit(spec->ak4114); + snd_ak4114_resume(spec->ak4114); return 0; } static int juli_suspend(struct snd_ice1712 *ice) { struct snd_akm4xxx *ak = ice->akm; + struct juli_spec *spec = ice->spec; /* akm4358 reset and soft-mute */ snd_akm4xxx_reset(ak, 1); + snd_ak4114_suspend(spec->ak4114); return 0; } #endif diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c index 21b373b2e260..f7ac8d5e862c 100644 --- a/sound/pci/ice1712/wm8766.c +++ b/sound/pci/ice1712/wm8766.c @@ -183,22 +183,6 @@ void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac) snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac); } -void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode) -{ - u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_MSTR_MASK; - - mode &= WM8766_DAC3_MSTR_MASK; - snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | mode); -} - -void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power) -{ - u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_POWER_MASK; - - power &= WM8766_DAC3_POWER_MASK; - snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | power); -} - void snd_wm8766_volume_restore(struct snd_wm8766 *wm) { u16 val = wm->regs[WM8766_REG_DACR1]; diff --git a/sound/pci/ice1712/wm8766.h b/sound/pci/ice1712/wm8766.h index c119f84bd2c2..18c8d9d47b38 100644 --- a/sound/pci/ice1712/wm8766.h +++ b/sound/pci/ice1712/wm8766.h @@ -155,8 +155,6 @@ struct snd_wm8766 { void snd_wm8766_init(struct snd_wm8766 *wm); void snd_wm8766_resume(struct snd_wm8766 *wm); void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac); -void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode); -void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power); void snd_wm8766_volume_restore(struct snd_wm8766 *wm); int snd_wm8766_build_controls(struct snd_wm8766 *wm); diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c index e66c0da62014..ebd2fe4b4a57 100644 --- a/sound/pci/ice1712/wm8776.c +++ b/sound/pci/ice1712/wm8776.c @@ -452,21 +452,6 @@ void snd_wm8776_resume(struct snd_wm8776 *wm) snd_wm8776_write(wm, i, wm->regs[i]); } -void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac) -{ - snd_wm8776_write(wm, WM8776_REG_DACIFCTRL, dac); -} - -void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc) -{ - snd_wm8776_write(wm, WM8776_REG_ADCIFCTRL, adc); -} - -void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode) -{ - snd_wm8776_write(wm, WM8776_REG_MSTRCTRL, mode); -} - void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power) { snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power); diff --git a/sound/pci/ice1712/wm8776.h b/sound/pci/ice1712/wm8776.h index 93a2d6971154..42acef05540c 100644 --- a/sound/pci/ice1712/wm8776.h +++ b/sound/pci/ice1712/wm8776.h @@ -216,9 +216,6 @@ struct snd_wm8776 { void snd_wm8776_init(struct snd_wm8776 *wm); void snd_wm8776_resume(struct snd_wm8776 *wm); -void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac); -void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc); -void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode); void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power); void snd_wm8776_volume_restore(struct snd_wm8776 *wm); int snd_wm8776_build_controls(struct snd_wm8776 *wm); diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 4a28252a42b9..2c5484eeb963 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -26,7 +26,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -2654,7 +2654,6 @@ static int snd_intel8x0_free(struct intel8x0 *chip) */ static int intel8x0_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct intel8x0 *chip = card->private_data; int i; @@ -2682,12 +2681,6 @@ static int intel8x0_suspend(struct device *dev) free_irq(chip->irq, chip); chip->irq = -1; } - pci_disable_device(pci); - pci_save_state(pci); - /* The call below may disable built-in speaker on some laptops - * after S2RAM. So, don't touch it. - */ - /* pci_set_power_state(pci, PCI_D3hot); */ return 0; } @@ -2698,14 +2691,6 @@ static int intel8x0_resume(struct device *dev) struct intel8x0 *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); snd_intel8x0_chip_init(chip, 0); if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 6b40235be13c..7577f31cd504 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -23,7 +23,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -1023,7 +1023,6 @@ static int snd_intel8x0m_free(struct intel8x0m *chip) */ static int intel8x0m_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct intel8x0m *chip = card->private_data; int i; @@ -1036,9 +1035,6 @@ static int intel8x0m_suspend(struct device *dev) free_irq(chip->irq, chip); chip->irq = -1; } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -1048,14 +1044,6 @@ static int intel8x0m_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct intel8x0m *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(dev, "unable to grab IRQ %d, disabling device\n", diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 59d21c9401d2..7acbc21d642a 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -28,6 +28,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/firmware.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> @@ -36,8 +37,6 @@ #include <sound/pcm_params.h> #include <sound/initval.h> -#include <asm/io.h> - // ---------------------------------------------------------------------------- // Debug Stuff // ---------------------------------------------------------------------------- @@ -585,8 +584,7 @@ static void snd_korg1212_SendStop(struct snd_korg1212 *korg1212) korg1212->sharedBufferPtr->cardCommand = 0xffffffff; /* program the timer */ korg1212->stop_pending_cnt = HZ; - korg1212->timer.expires = jiffies + 1; - add_timer(&korg1212->timer); + mod_timer(&korg1212->timer, jiffies + 1); } } @@ -617,8 +615,7 @@ static void snd_korg1212_timer_func(unsigned long data) } else { if (--korg1212->stop_pending_cnt > 0) { /* reprogram timer */ - korg1212->timer.expires = jiffies + 1; - add_timer(&korg1212->timer); + mod_timer(&korg1212->timer, jiffies + 1); } else { snd_printd("korg1212_timer_func timeout\n"); korg1212->sharedBufferPtr->cardCommand = 0; @@ -2172,9 +2169,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, init_waitqueue_head(&korg1212->wait); spin_lock_init(&korg1212->lock); mutex_init(&korg1212->open_mutex); - init_timer(&korg1212->timer); - korg1212->timer.function = snd_korg1212_timer_func; - korg1212->timer.data = (unsigned long)korg1212; + setup_timer(&korg1212->timer, snd_korg1212_timer_func, + (unsigned long)korg1212); korg1212->irq = -1; korg1212->clkSource = K1212_CLKIDX_Local; diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 4cf4be5ef82a..9ff600084973 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -551,10 +551,8 @@ static void lola_free(struct lola *chip) lola_free_mixer(chip); if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - if (chip->bar[0].remap_addr) - iounmap(chip->bar[0].remap_addr); - if (chip->bar[1].remap_addr) - iounmap(chip->bar[1].remap_addr); + iounmap(chip->bar[0].remap_addr); + iounmap(chip->bar[1].remap_addr); if (chip->rb.area) snd_dma_free_pages(&chip->rb); pci_release_regions(chip->pci); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 98823d11d485..9be660993bd0 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -31,7 +31,7 @@ #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2" #define DRIVER_NAME "Maestro3" -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -2395,7 +2395,6 @@ static int snd_m3_free(struct snd_m3 *chip) #ifdef CONFIG_PM_SLEEP static int m3_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_m3 *chip = card->private_data; int i, dsp_index; @@ -2421,16 +2420,11 @@ static int m3_suspend(struct device *dev) for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) chip->suspend_mem[dsp_index++] = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int m3_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_m3 *chip = card->private_data; int i, dsp_index; @@ -2438,15 +2432,6 @@ static int m3_resume(struct device *dev) if (chip->suspend_mem == NULL) return 0; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - /* first lets just bring everything back. .*/ snd_m3_outw(chip, 0, 0x54); snd_m3_outw(chip, 0, 0x56); diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 1faf47e81570..c3a9f39f8d61 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1114,10 +1114,9 @@ static int snd_mixart_free(struct mixart_mgr *mgr) } /* release the i/o ports */ - for (i = 0; i < 2; i++) { - if (mgr->mem[i].virt) - iounmap(mgr->mem[i].virt); - } + for (i = 0; i < 2; ++i) + iounmap(mgr->mem[i].virt); + pci_release_regions(mgr->pci); /* free flowarray */ diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index fe80313674d9..dccf3db48fe0 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -23,8 +23,8 @@ #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/pci.h> +#include <linux/io.h> -#include <asm/io.h> #include <sound/core.h> #include "mixart.h" #include "mixart_hwdep.h" diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index 9996a4dead0f..5bfd3ac80db5 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -26,7 +26,7 @@ #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include "mixart.h" #include "mixart_mixer.h" diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 4e41a4e29a1e..4735e27cc773 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -24,7 +24,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -1392,7 +1392,6 @@ snd_nm256_peek_for_sig(struct nm256 *chip) */ static int nm256_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct nm256 *chip = card->private_data; @@ -1400,15 +1399,11 @@ static int nm256_suspend(struct device *dev) snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); chip->coeffs_current = 0; - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int nm256_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct nm256 *chip = card->private_data; int i; @@ -1416,15 +1411,6 @@ static int nm256_resume(struct device *dev) /* Perform a full reset on the hardware */ chip->in_resume = 1; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_nm256_init_chip(chip); /* restore ac97 */ @@ -1460,10 +1446,8 @@ static int snd_nm256_free(struct nm256 *chip) if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->cport) - iounmap(chip->cport); - if (chip->buffer) - iounmap(chip->buffer); + iounmap(chip->cport); + iounmap(chip->buffer); release_and_free_resource(chip->res_cport); release_and_free_resource(chip->res_buffer); diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index 8f4c409f7e45..ab085d753661 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile @@ -1,8 +1,10 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o +snd-se6x-objs := se6x.o snd-virtuoso-objs := virtuoso.o xonar_lib.o \ xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o +obj-$(CONFIG_SND_SE6X) += snd-se6x.o obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index c10ab077afd8..293d0b9a50c3 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -35,7 +35,7 @@ #define CAPTURE_1_FROM_SPDIF 0x0080 #define CAPTURE_2_FROM_I2S_2 0x0100 #define CAPTURE_2_FROM_AC97_1 0x0200 - /* CAPTURE_3_FROM_I2S_3 not implemented */ +#define CAPTURE_3_FROM_I2S_3 0x0400 #define MIDI_OUTPUT 0x0800 #define MIDI_INPUT 0x1000 #define AC97_CD_INPUT 0x2000 diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 4b8a32c37e31..c7851da37749 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c @@ -20,9 +20,9 @@ #include <linux/delay.h> #include <linux/sched.h> #include <linux/export.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/mpu401.h> -#include <asm/io.h> #include "oxygen.h" u8 oxygen_read8(struct oxygen *chip, unsigned int reg) diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index b67e30602473..ffff3b25fd73 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -319,11 +319,12 @@ static void oxygen_restore_eeprom(struct oxygen *chip, static void configure_pcie_bridge(struct pci_dev *pci) { - enum { PEX811X, PI7C9X110 }; + enum { PEX811X, PI7C9X110, XIO2001 }; static const struct pci_device_id bridge_ids[] = { { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X }, { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X }, { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 }, + { PCI_VDEVICE(TI, 0x8240), .driver_data = XIO2001 }, { } }; struct pci_dev *bridge; @@ -357,6 +358,14 @@ static void configure_pcie_bridge(struct pci_dev *pci) tmp |= 1; /* park the PCI arbiter to the sound chip */ pci_write_config_dword(bridge, 0x40, tmp); break; + + case XIO2001: /* Texas Instruments XIO2001 PCIe/PCI bridge */ + pci_read_config_dword(bridge, 0xe8, &tmp); + tmp &= ~0xf; /* request length limit: 64 bytes */ + tmp &= ~(0xf << 8); + tmp |= 1 << 8; /* request count limit: one buffer */ + pci_write_config_dword(bridge, 0xe8, tmp); + break; } } @@ -441,9 +450,18 @@ static void oxygen_init(struct oxygen *chip) oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK); - oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, - OXYGEN_I2S_MASTER | - OXYGEN_I2S_MUTE_MCLK); + if (chip->model.device_config & CAPTURE_3_FROM_I2S_3) + oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, + OXYGEN_RATE_48000 | + chip->model.adc_i2s_format | + OXYGEN_I2S_MCLK(chip->model.adc_mclks) | + OXYGEN_I2S_BITS_16 | + OXYGEN_I2S_MASTER | + OXYGEN_I2S_BCLK_64); + else + oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, + OXYGEN_I2S_MASTER | + OXYGEN_I2S_MUTE_MCLK); oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_OUT_ENABLE | OXYGEN_SPDIF_LOOPBACK); @@ -728,7 +746,6 @@ EXPORT_SYMBOL(oxygen_pci_remove); #ifdef CONFIG_PM_SLEEP static int oxygen_pci_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct oxygen *chip = card->private_data; unsigned int i, saved_interrupt_mask; @@ -736,8 +753,7 @@ static int oxygen_pci_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < PCM_COUNT; ++i) - if (chip->streams[i]) - snd_pcm_suspend(chip->streams[i]); + snd_pcm_suspend(chip->streams[i]); if (chip->model.suspend) chip->model.suspend(chip); @@ -753,10 +769,6 @@ static int oxygen_pci_suspend(struct device *dev) flush_work(&chip->spdif_input_bits_work); flush_work(&chip->gpio_work); chip->interrupt_mask = saved_interrupt_mask; - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -788,20 +800,10 @@ static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec) static int oxygen_pci_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct oxygen *chip = card->private_data; unsigned int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "cannot reenable device"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); for (i = 0; i < OXYGEN_IO_SIZE; ++i) diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 5988e044c519..6492bca8c70f 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -786,6 +786,9 @@ static const struct snd_kcontrol_new controls[] = { .get = upmix_get, .put = upmix_put, }, +}; + +static const struct snd_kcontrol_new spdif_output_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), @@ -938,6 +941,33 @@ static const struct { }, }, { + .pcm_dev = CAPTURE_3_FROM_I2S_3, + .controls = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Input Monitor Playback Switch", + .index = 2, + .info = snd_ctl_boolean_mono_info, + .get = monitor_get, + .put = monitor_put, + .private_value = OXYGEN_ADC_MONITOR_C, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Input Monitor Playback Volume", + .index = 2, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = monitor_volume_info, + .get = monitor_get, + .put = monitor_put, + .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL + | (1 << 8), + .tlv = { .p = monitor_db_scale, }, + }, + }, + }, + { .pcm_dev = CAPTURE_1_FROM_SPDIF, .controls = { { @@ -1073,6 +1103,12 @@ int oxygen_mixer_init(struct oxygen *chip) err = add_controls(chip, controls, ARRAY_SIZE(controls)); if (err < 0) return err; + if (chip->model.device_config & PLAYBACK_1_TO_SPDIF) { + err = add_controls(chip, spdif_output_controls, + ARRAY_SIZE(spdif_output_controls)); + if (err < 0) + return err; + } if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) { err = add_controls(chip, spdif_input_controls, ARRAY_SIZE(spdif_input_controls)); diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 02828240ba15..aa2ebd1d6d12 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -144,9 +144,11 @@ static int oxygen_open(struct snd_pcm_substream *substream, runtime->hw = *oxygen_hardware[channel]; switch (channel) { case PCM_C: - runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_64000); - runtime->hw.rate_min = 44100; + if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) { + runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_64000); + runtime->hw.rate_min = 44100; + } /* fall through */ case PCM_A: case PCM_B: @@ -430,17 +432,36 @@ static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct oxygen *chip = snd_pcm_substream_chip(substream); + bool is_spdif; int err; err = oxygen_hw_params(substream, hw_params); if (err < 0) return err; + is_spdif = chip->model.device_config & CAPTURE_1_FROM_SPDIF; + spin_lock_irq(&chip->reg_lock); oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT, OXYGEN_REC_FORMAT_C_MASK); + if (!is_spdif) + oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT, + oxygen_rate(hw_params) | + chip->model.adc_i2s_format | + get_mclk(chip, PCM_B, hw_params) | + oxygen_i2s_bits(hw_params), + OXYGEN_I2S_RATE_MASK | + OXYGEN_I2S_FORMAT_MASK | + OXYGEN_I2S_MCLK_MASK | + OXYGEN_I2S_BITS_MASK); spin_unlock_irq(&chip->reg_lock); + + if (!is_spdif) { + mutex_lock(&chip->mutex); + chip->model.set_adc_params(chip, hw_params); + mutex_unlock(&chip->mutex); + } return 0; } @@ -676,11 +697,6 @@ static struct snd_pcm_ops oxygen_ac97_ops = { .pointer = oxygen_pointer, }; -static void oxygen_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - int oxygen_pcm_init(struct oxygen *chip) { struct snd_pcm *pcm; @@ -705,7 +721,6 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_b_ops); pcm->private_data = chip; - pcm->private_free = oxygen_pcm_free; strcpy(pcm->name, "Multichannel"); if (outs) snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -734,7 +749,6 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_c_ops); pcm->private_data = chip; - pcm->private_free = oxygen_pcm_free; strcpy(pcm->name, "Digital"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), @@ -765,12 +779,29 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_b_ops); pcm->private_data = chip; - pcm->private_free = oxygen_pcm_free; strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), DEFAULT_BUFFER_BYTES, BUFFER_BYTES_MAX); } + + ins = !!(chip->model.device_config & CAPTURE_3_FROM_I2S_3); + if (ins) { + err = snd_pcm_new(chip->card, "Analog3", 3, 0, ins, &pcm); + if (err < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &oxygen_rec_c_ops); + oxygen_write8_masked(chip, OXYGEN_REC_ROUTING, + OXYGEN_REC_C_ROUTE_I2S_ADC_3, + OXYGEN_REC_C_ROUTE_MASK); + pcm->private_data = chip; + strcpy(pcm->name, "Analog 3"); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + DEFAULT_BUFFER_BYTES, + BUFFER_BYTES_MAX); + } return 0; } diff --git a/sound/pci/oxygen/se6x.c b/sound/pci/oxygen/se6x.c new file mode 100644 index 000000000000..f70d514c1084 --- /dev/null +++ b/sound/pci/oxygen/se6x.c @@ -0,0 +1,160 @@ +/* + * C-Media CMI8787 driver for the Studio Evolution SE6X + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this driver; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * CMI8787: + * + * SPI -> microcontroller (not actually used) + * GPIO 0 -> do. + * GPIO 2 -> do. + * + * DAC0 -> both PCM1792A (L+R, each in mono mode) + * ADC1 <- 1st PCM1804 + * ADC2 <- 2nd PCM1804 + * ADC3 <- 3rd PCM1804 + */ + +#include <linux/pci.h> +#include <linux/module.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include "oxygen.h" + +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_DESCRIPTION("Studio Evolution SE6X driver"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{Studio Evolution,SE6X}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "card index"); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string"); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "enable card"); + +static const struct pci_device_id se6x_ids[] = { + { OXYGEN_PCI_SUBID(0x13f6, 0x8788) }, + { } +}; +MODULE_DEVICE_TABLE(pci, se6x_ids); + +static void se6x_init(struct oxygen *chip) +{ + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 0x005); + + snd_component_add(chip->card, "PCM1792A"); + snd_component_add(chip->card, "PCM1804"); +} + +static int se6x_control_filter(struct snd_kcontrol_new *template) +{ + /* no DAC volume/mute */ + if (!strncmp(template->name, "Master Playback ", 16)) + return 1; + return 0; +} + +static void se6x_cleanup(struct oxygen *chip) +{ +} + +static void set_pcm1792a_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + /* nothing to do (the microcontroller monitors DAC_LRCK) */ +} + +static void set_pcm1804_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ +} + +static unsigned int se6x_adjust_dac_routing(struct oxygen *chip, + unsigned int play_routing) +{ + /* route the same stereo pair to DAC0 and DAC1 */ + return ( play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) | + ((play_routing << 2) & OXYGEN_PLAY_DAC1_SOURCE_MASK); +} + +static const struct oxygen_model model_se6x = { + .shortname = "Studio Evolution SE6X", + .longname = "C-Media Oxygen HD Audio", + .chip = "CMI8787", + .init = se6x_init, + .control_filter = se6x_control_filter, + .cleanup = se6x_cleanup, + .set_dac_params = set_pcm1792a_params, + .set_adc_params = set_pcm1804_params, + .adjust_dac_routing = se6x_adjust_dac_routing, + .device_config = PLAYBACK_0_TO_I2S | + CAPTURE_0_FROM_I2S_1 | + CAPTURE_2_FROM_I2S_2 | + CAPTURE_3_FROM_I2S_3, + .dac_channels_pcm = 2, + .function_flags = OXYGEN_FUNCTION_SPI, + .dac_mclks = OXYGEN_MCLKS(256, 128, 128), + .adc_mclks = OXYGEN_MCLKS(256, 256, 128), + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_I2S, +}; + +static int se6x_get_model(struct oxygen *chip, + const struct pci_device_id *pci_id) +{ + chip->model = model_se6x; + return 0; +} + +static int se6x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + static int dev; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + ++dev; + return -ENOENT; + } + err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE, + se6x_ids, se6x_get_model); + if (err >= 0) + ++dev; + return err; +} + +static struct pci_driver se6x_driver = { + .name = KBUILD_MODNAME, + .id_table = se6x_ids, + .probe = se6x_probe, + .remove = oxygen_pci_remove, +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &oxygen_pci_pm, + }, +#endif + .shutdown = oxygen_pci_shutdown, +}; + +module_pci_driver(se6x_driver); diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 181f7729d409..c5194f5b150a 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -24,7 +24,7 @@ #include <linux/firmware.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include "pcxhr.h" #include "pcxhr_mixer.h" diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index 15a8ce5f1f48..80633055e17e 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -25,7 +25,7 @@ #include <linux/firmware.h> #include <linux/pci.h> #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/hwdep.h> #include "pcxhr.h" diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 6abc2ac8fffb..94639d6b5fb5 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -99,7 +99,7 @@ #include <linux/firmware.h> #include <linux/kernel.h> #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> @@ -1153,7 +1153,6 @@ static void riptide_handleirq(unsigned long dev_id) #ifdef CONFIG_PM_SLEEP static int riptide_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_riptide *chip = card->private_data; @@ -1161,27 +1160,14 @@ static int riptide_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int riptide_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_riptide *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "riptide: pci_enable_device failed, " - "disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); snd_riptide_initialize(chip); snd_ac97_resume(chip->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -1706,14 +1692,11 @@ static struct snd_pcm_ops snd_riptide_capture_ops = { .pointer = snd_riptide_pointer, }; -static int -snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm) +static int snd_riptide_pcm(struct snd_riptide *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1, &pcm)) < 0) @@ -1729,8 +1712,6 @@ snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 64 * 1024, 128 * 1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -2030,32 +2011,43 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { static int dev; struct gameport *gameport; + int ret; if (dev >= SNDRV_CARDS) return -ENODEV; + if (!enable[dev]) { - dev++; - return -ENOENT; + ret = -ENOENT; + goto inc_dev; } - if (!joystick_port[dev++]) - return 0; + if (!joystick_port[dev]) { + ret = 0; + goto inc_dev; + } gameport = gameport_allocate_port(); - if (!gameport) - return -ENOMEM; + if (!gameport) { + ret = -ENOMEM; + goto inc_dev; + } if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { snd_printk(KERN_WARNING "Riptide: cannot grab gameport 0x%x\n", joystick_port[dev]); gameport_free_port(gameport); - return -EBUSY; + ret = -EBUSY; + goto inc_dev; } gameport->io = joystick_port[dev]; gameport_register_port(gameport); pci_set_drvdata(pci, gameport); - return 0; + + ret = 0; +inc_dev: + dev++; + return ret; } static void snd_riptide_joystick_remove(struct pci_dev *pci) @@ -2092,7 +2084,7 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err < 0) goto error; card->private_data = chip; - err = snd_riptide_pcm(chip, 0, NULL); + err = snd_riptide_pcm(chip, 0); if (err < 0) goto error; err = snd_riptide_mixer(chip); diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 6c60dcd2e5a1..23d7f5d30c41 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -75,6 +75,7 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> @@ -85,8 +86,6 @@ #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> - static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ @@ -632,7 +631,7 @@ snd_rme32_setframelog(struct rme32 * rme32, int n_channels, int is_playback) } } -static int snd_rme32_setformat(struct rme32 * rme32, int format) +static int snd_rme32_setformat(struct rme32 *rme32, snd_pcm_format_t format) { switch (format) { case SNDRV_PCM_FORMAT_S16_LE: diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2f1a85185a16..2306ccf7281e 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -29,6 +29,7 @@ #include <linux/pci.h> #include <linux/module.h> #include <linux/vmalloc.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> @@ -38,8 +39,6 @@ #include <sound/asoundef.h> #include <sound/initval.h> -#include <asm/io.h> - /* note, two last pcis should be equal, it is not a bug */ MODULE_AUTHOR("Anders Torger <torger@ludd.luth.se>"); @@ -922,8 +921,7 @@ snd_rme96_setframelog(struct rme96 *rme96, } static int -snd_rme96_playback_setformat(struct rme96 *rme96, - int format) +snd_rme96_playback_setformat(struct rme96 *rme96, snd_pcm_format_t format) { switch (format) { case SNDRV_PCM_FORMAT_S16_LE: @@ -940,8 +938,7 @@ snd_rme96_playback_setformat(struct rme96 *rme96, } static int -snd_rme96_capture_setformat(struct rme96 *rme96, - int format) +snd_rme96_capture_setformat(struct rme96 *rme96, snd_pcm_format_t format) { switch (format) { case SNDRV_PCM_FORMAT_S16_LE: @@ -2358,7 +2355,6 @@ snd_rme96_create_switches(struct snd_card *card, static int rme96_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct rme96 *rme96 = card->private_data; @@ -2381,26 +2377,14 @@ static int rme96_suspend(struct device *dev) /* disable the DAC */ rme96->areg &= ~RME96_AR_DAC_EN; writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); - - pci_disable_device(pci); - pci_save_state(pci); - return 0; } static int rme96_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct rme96 *rme96 = card->private_data; - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - /* reset playback and record buffer pointers */ writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS + rme96->playback_pointer); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index cf5a6c8b9a63..c19e021ccf66 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/math64.h> #include <linux/vmalloc.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> @@ -42,7 +43,6 @@ #include <asm/byteorder.h> #include <asm/current.h> -#include <asm/io.h> static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -1428,10 +1428,8 @@ static void snd_hdsp_midi_output_timer(unsigned long data) leaving istimer wherever it was set before. */ - if (hmidi->istimer) { - hmidi->timer.expires = 1 + jiffies; - add_timer(&hmidi->timer); - } + if (hmidi->istimer) + mod_timer(&hmidi->timer, 1 + jiffies); spin_unlock_irqrestore (&hmidi->lock, flags); } @@ -1445,11 +1443,9 @@ static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { - init_timer(&hmidi->timer); - hmidi->timer.function = snd_hdsp_midi_output_timer; - hmidi->timer.data = (unsigned long) hmidi; - hmidi->timer.expires = 1 + jiffies; - add_timer(&hmidi->timer); + setup_timer(&hmidi->timer, snd_hdsp_midi_output_timer, + (unsigned long) hmidi); + mod_timer(&hmidi->timer, 1 + jiffies); hmidi->istimer++; } } else { @@ -5309,9 +5305,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) release_firmware(hdsp->firmware); vfree(hdsp->fw_uploaded); - - if (hdsp->iobase) - iounmap(hdsp->iobase); + iounmap(hdsp->iobase); if (hdsp->port) pci_release_regions(hdsp->pci); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 3342705a5715..ca67f896d117 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -136,7 +136,7 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/math64.h> -#include <asm/io.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> @@ -1957,10 +1957,8 @@ static void snd_hdspm_midi_output_timer(unsigned long data) leaving istimer wherever it was set before. */ - if (hmidi->istimer) { - hmidi->timer.expires = 1 + jiffies; - add_timer(&hmidi->timer); - } + if (hmidi->istimer) + mod_timer(&hmidi->timer, 1 + jiffies); spin_unlock_irqrestore (&hmidi->lock, flags); } @@ -1975,11 +1973,9 @@ snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { - init_timer(&hmidi->timer); - hmidi->timer.function = snd_hdspm_midi_output_timer; - hmidi->timer.data = (unsigned long) hmidi; - hmidi->timer.expires = 1 + jiffies; - add_timer(&hmidi->timer); + setup_timer(&hmidi->timer, snd_hdspm_midi_output_timer, + (unsigned long) hmidi); + mod_timer(&hmidi->timer, 1 + jiffies); hmidi->istimer++; } } else { @@ -6086,6 +6082,9 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 64, 8192); + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIODS, + 2, 2); break; } @@ -6160,6 +6159,9 @@ static int snd_hdspm_capture_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 64, 8192); + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIODS, + 2, 2); break; } @@ -6965,9 +6967,7 @@ static int snd_hdspm_free(struct hdspm * hdspm) free_irq(hdspm->irq, (void *) hdspm); kfree(hdspm->mixer); - - if (hdspm->iobase) - iounmap(hdspm->iobase); + iounmap(hdspm->iobase); if (hdspm->port) pci_release_regions(hdspm->pci); diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 6521521853b8..fdbc0aa2776a 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -25,6 +25,7 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> @@ -34,7 +35,6 @@ #include <sound/initval.h> #include <asm/current.h> -#include <asm/io.h> static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -1756,8 +1756,7 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652) if (rme9652->irq >= 0) free_irq(rme9652->irq, (void *)rme9652); - if (rme9652->iobase) - iounmap(rme9652->iobase); + iounmap(rme9652->iobase); if (rme9652->port) pci_release_regions(rme9652->pci); diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 7f6a0a0d115a..efe669b80256 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -1064,12 +1064,9 @@ static int sis_chip_free(struct sis7019 *sis) if (sis->irq >= 0) free_irq(sis->irq, sis); - if (sis->ioaddr) - iounmap(sis->ioaddr); - + iounmap(sis->ioaddr); pci_release_regions(sis->pci); pci_disable_device(sis->pci); - sis_free_suspend(sis); return 0; } @@ -1211,7 +1208,6 @@ static int sis_chip_init(struct sis7019 *sis) #ifdef CONFIG_PM_SLEEP static int sis_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct sis7019 *sis = card->private_data; void __iomem *ioaddr = sis->ioaddr; @@ -1240,9 +1236,6 @@ static int sis_suspend(struct device *dev) ioaddr += 4096; } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -1254,14 +1247,6 @@ static int sis_resume(struct device *dev) void __iomem *ioaddr = sis->ioaddr; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - if (pci_enable_device(pci) < 0) { - dev_err(&pci->dev, "unable to re-enable device\n"); - goto error; - } - if (sis_chip_init(sis)) { dev_err(&pci->dev, "unable to re-init controller\n"); goto error; @@ -1284,7 +1269,6 @@ static int sis_resume(struct device *dev) memset(sis->suspend_state[0], 0, 4096); sis->irq = pci->irq; - pci_set_master(pci); if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) snd_ac97_resume(sis->ac97[0]); diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 313a7328bf9c..0f40624a4275 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -30,6 +30,7 @@ #include <linux/gameport.h> #include <linux/module.h> #include <linux/dma-mapping.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> @@ -39,8 +40,6 @@ #include <sound/opl3.h> #include <sound/initval.h> -#include <asm/io.h> - MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("S3 SonicVibes PCI"); MODULE_LICENSE("GPL"); @@ -880,8 +879,7 @@ static struct snd_pcm_ops snd_sonicvibes_capture_ops = { .pointer = snd_sonicvibes_capture_pointer, }; -static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device, - struct snd_pcm **rpcm) +static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device) { struct snd_pcm *pcm; int err; @@ -902,8 +900,6 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(sonic->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1491,7 +1487,7 @@ static int snd_sonic_probe(struct pci_dev *pci, (unsigned long long)pci_resource_start(pci, 1), sonic->irq); - if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) { + if ((err = snd_sonicvibes_pcm(sonic, 0)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index a54cd6879b31..cedf13b64803 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -127,21 +127,21 @@ static int snd_trident_probe(struct pci_dev *pci, sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d", card->shortname, trident->port, trident->irq); - if ((err = snd_trident_pcm(trident, pcm_dev++, NULL)) < 0) { + if ((err = snd_trident_pcm(trident, pcm_dev++)) < 0) { snd_card_free(card); return err; } switch (trident->device) { case TRIDENT_DEVICE_ID_DX: case TRIDENT_DEVICE_ID_NX: - if ((err = snd_trident_foldback_pcm(trident, pcm_dev++, NULL)) < 0) { + if ((err = snd_trident_foldback_pcm(trident, pcm_dev++)) < 0) { snd_card_free(card); return err; } break; } if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) { - if ((err = snd_trident_spdif_pcm(trident, pcm_dev++, NULL)) < 0) { + if ((err = snd_trident_spdif_pcm(trident, pcm_dev++)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/trident/trident.h b/sound/pci/trident/trident.h index 5f110eb56e47..9624e5937719 100644 --- a/sound/pci/trident/trident.h +++ b/sound/pci/trident/trident.h @@ -420,9 +420,9 @@ int snd_trident_create(struct snd_card *card, struct snd_trident ** rtrident); int snd_trident_create_gameport(struct snd_trident *trident); -int snd_trident_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm); -int snd_trident_foldback_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm); -int snd_trident_spdif_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm); +int snd_trident_pcm(struct snd_trident *trident, int device); +int snd_trident_foldback_pcm(struct snd_trident *trident, int device); +int snd_trident_spdif_pcm(struct snd_trident *trident, int device); int snd_trident_attach_synthesizer(struct snd_trident * trident); struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port); diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 57cd757acfe7..b72be035f785 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -36,6 +36,7 @@ #include <linux/gameport.h> #include <linux/dma-mapping.h> #include <linux/export.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/info.h> @@ -44,8 +45,6 @@ #include "trident.h" #include <sound/asoundef.h> -#include <asm/io.h> - static int snd_trident_pcm_mixer_build(struct snd_trident *trident, struct snd_trident_voice * voice, struct snd_pcm_substream *substream); @@ -2172,14 +2171,11 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = { ---------------------------------------------------------------------------*/ -int snd_trident_pcm(struct snd_trident *trident, - int device, struct snd_pcm **rpcm) +int snd_trident_pcm(struct snd_trident *trident, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm)) < 0) return err; @@ -2214,8 +2210,6 @@ int snd_trident_pcm(struct snd_trident *trident, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); } - if (rpcm) - *rpcm = pcm; return 0; } @@ -2230,16 +2224,13 @@ int snd_trident_pcm(struct snd_trident *trident, ---------------------------------------------------------------------------*/ -int snd_trident_foldback_pcm(struct snd_trident *trident, - int device, struct snd_pcm **rpcm) +int snd_trident_foldback_pcm(struct snd_trident *trident, int device) { struct snd_pcm *foldback; int err; int num_chan = 3; struct snd_pcm_substream *substream; - if (rpcm) - *rpcm = NULL; if (trident->device == TRIDENT_DEVICE_ID_NX) num_chan = 4; if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback)) < 0) @@ -2271,8 +2262,6 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = foldback; return 0; } @@ -2287,14 +2276,11 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, ---------------------------------------------------------------------------*/ -int snd_trident_spdif_pcm(struct snd_trident *trident, - int device, struct snd_pcm **rpcm) +int snd_trident_spdif_pcm(struct snd_trident *trident, int device) { struct snd_pcm *spdif; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif)) < 0) return err; @@ -2310,8 +2296,6 @@ int snd_trident_spdif_pcm(struct snd_trident *trident, snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); - if (rpcm) - *rpcm = spdif; return 0; } @@ -3926,7 +3910,6 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor #ifdef CONFIG_PM_SLEEP static int snd_trident_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_trident *trident = card->private_data; @@ -3938,28 +3921,14 @@ static int snd_trident_suspend(struct device *dev) snd_ac97_suspend(trident->ac97); snd_ac97_suspend(trident->ac97_sec); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_trident_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_trident *trident = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - switch (trident->device) { case TRIDENT_DEVICE_ID_DX: snd_trident_4d_dx_init(trident); diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 04c474658e3c..b9ebb51893c5 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -23,7 +23,7 @@ * */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/pci.h> #include <linux/time.h> #include <linux/mutex.h> diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e088467fb736..8622283e89f3 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -46,7 +46,7 @@ * - Optimize position calculation for the 823x chips. */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -2271,7 +2271,6 @@ static int snd_via82xx_chip_init(struct via82xx *chip) */ static int snd_via82xx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx *chip = card->private_data; int i; @@ -2291,28 +2290,15 @@ static int snd_via82xx_suspend(struct device *dev) chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10); } - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_via82xx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_via82xx_chip_init(chip); if (chip->chip_type == TYPE_VIA686) { diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index fd46ffe12e4f..99b9137bc677 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -31,7 +31,7 @@ * modems. */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -1031,7 +1031,6 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) */ static int snd_via82xx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx_modem *chip = card->private_data; int i; @@ -1043,29 +1042,15 @@ static int snd_via82xx_suspend(struct device *dev) snd_via82xx_channel_reset(chip, &chip->devs[i]); synchronize_irq(chip->irq); snd_ac97_suspend(chip->ac97); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } static int snd_via82xx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct via82xx_modem *chip = card->private_data; int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - snd_via82xx_chip_init(chip); snd_ac97_resume(chip->ac97); diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index c5a25e39e3a8..ecbaf473fc1e 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -259,32 +259,17 @@ static void snd_vx222_remove(struct pci_dev *pci) #ifdef CONFIG_PM_SLEEP static int snd_vx222_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_vx222 *vx = card->private_data; - int err; - err = snd_vx_suspend(&vx->core); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); - return err; + return snd_vx_suspend(&vx->core); } static int snd_vx222_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_vx222 *vx = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); return snd_vx_resume(&vx->core); } diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 52c1a8d5b88a..af83b3b38052 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -24,11 +24,11 @@ #include <linux/device.h> #include <linux/firmware.h> #include <linux/mutex.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> #include <sound/tlv.h> -#include <asm/io.h> #include "vx222.h" diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 47a192369e8f..812e27a1bcbc 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -283,11 +283,11 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, card->shortname, chip->reg_area_phys, chip->irq); - if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) { + if ((err = snd_ymfpci_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } - if ((err = snd_ymfpci_pcm_spdif(chip, 1, NULL)) < 0) { + if ((err = snd_ymfpci_pcm_spdif(chip, 1)) < 0) { snd_card_free(card); return err; } @@ -297,12 +297,12 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, return err; } if (chip->ac97->ext_id & AC97_EI_SDAC) { - err = snd_ymfpci_pcm_4ch(chip, 2, NULL); + err = snd_ymfpci_pcm_4ch(chip, 2); if (err < 0) { snd_card_free(card); return err; } - err = snd_ymfpci_pcm2(chip, 3, NULL); + err = snd_ymfpci_pcm2(chip, 3); if (err < 0) { snd_card_free(card); return err; diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h index 4631a2348915..149d4cb46998 100644 --- a/sound/pci/ymfpci/ymfpci.h +++ b/sound/pci/ymfpci/ymfpci.h @@ -379,10 +379,10 @@ void snd_ymfpci_free_gameport(struct snd_ymfpci *chip); extern const struct dev_pm_ops snd_ymfpci_pm; -int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); -int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); -int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); -int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm); +int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device); +int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device); +int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device); +int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device); int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch); int snd_ymfpci_timer(struct snd_ymfpci *chip, int device); diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 81c916a5eb96..4c26076dbf78 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/module.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> @@ -36,7 +37,6 @@ #include <sound/asoundef.h> #include <sound/mpu401.h> -#include <asm/io.h> #include <asm/byteorder.h> /* @@ -1145,13 +1145,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_rec_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) +int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1167,14 +1165,8 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_std_chmaps, 2, 0, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; } static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = { @@ -1188,13 +1180,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) +int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1210,8 +1200,6 @@ int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1226,14 +1214,11 @@ static struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = { .pointer = snd_ymfpci_playback_pointer, }; -int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, - struct snd_pcm **rpcm) +int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1248,8 +1233,6 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - if (rpcm) - *rpcm = pcm; return 0; } @@ -1272,14 +1255,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, - struct snd_pcm **rpcm) +int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device) { struct snd_pcm *pcm; int err; - if (rpcm) - *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm)) < 0) return err; pcm->private_data = chip; @@ -1294,14 +1274,8 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); - err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, surround_map, 2, 0, NULL); - if (err < 0) - return err; - - if (rpcm) - *rpcm = pcm; - return 0; } static int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -2272,8 +2246,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) release_and_free_resource(chip->mpu_res); release_and_free_resource(chip->fm_res); snd_ymfpci_free_gameport(chip); - if (chip->reg_area_virt) - iounmap(chip->reg_area_virt); + iounmap(chip->reg_area_virt); if (chip->work_ptr.area) snd_dma_free_pages(&chip->work_ptr); @@ -2326,7 +2299,6 @@ static int saved_regs_index[] = { static int snd_ymfpci_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct snd_ymfpci *chip = card->private_data; unsigned int i; @@ -2347,9 +2319,6 @@ static int snd_ymfpci_suspend(struct device *dev) snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); snd_ymfpci_disable_dsp(chip); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, PCI_D3hot); return 0; } @@ -2360,14 +2329,6 @@ static int snd_ymfpci_resume(struct device *dev) struct snd_ymfpci *chip = card->private_data; unsigned int i; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - dev_err(dev, "pci_enable_device failed, disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); snd_ymfpci_aclink_reset(pci); snd_ymfpci_codec_ready(chip, 0); snd_ymfpci_download_image(chip); diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 5fbf5db2543d..09da7b52bc2e 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -20,7 +20,7 @@ */ -#include <asm/io.h> +#include <linux/io.h> #include <asm/nvram.h> #include <linux/init.h> #include <linux/delay.h> diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 0040f048221f..d3524f9fa05d 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index cb4f0a5e984e..b86159e04493 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <asm/io.h> +#include <linux/io.h> #include <linux/init.h> #include <linux/delay.h> #include <sound/core.h> diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 5a13b22748b2..13146d701413 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -20,7 +20,7 @@ */ -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <linux/init.h> #include <linux/delay.h> @@ -867,16 +867,11 @@ static int snd_pmac_free(struct snd_pmac *chip) snd_pmac_dbdma_free(chip, &chip->capture.cmd); snd_pmac_dbdma_free(chip, &chip->extra_dma); snd_pmac_dbdma_free(chip, &emergency_dbdma); - if (chip->macio_base) - iounmap(chip->macio_base); - if (chip->latch_base) - iounmap(chip->latch_base); - if (chip->awacs) - iounmap(chip->awacs); - if (chip->playback.dma) - iounmap(chip->playback.dma); - if (chip->capture.dma) - iounmap(chip->capture.dma); + iounmap(chip->macio_base); + iounmap(chip->latch_base); + iounmap(chip->awacs); + iounmap(chip->playback.dma); + iounmap(chip->capture.dma); if (chip->node) { int i; diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 58f292a87f98..368242519279 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -1044,7 +1044,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) if (!the_card.null_buffer_start_vaddr) { pr_info("%s: nullbuffer alloc failed\n", __func__); ret = -ENOMEM; - goto clean_preallocate; + goto clean_card; } pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__, the_card.null_buffer_start_vaddr, @@ -1066,8 +1066,6 @@ clean_dma_map: PAGE_SIZE, the_card.null_buffer_start_vaddr, the_card.null_buffer_start_dma_addr); -clean_preallocate: - snd_pcm_lib_preallocate_free_for_all(the_card.pcm); clean_card: snd_card_free(the_card.card); clean_irq: diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 24c8766a925d..c8fafba218a5 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -32,8 +32,8 @@ #include <linux/interrupt.h> #include <linux/string.h> #include <linux/of_irq.h> +#include <linux/io.h> #include <sound/core.h> -#include <asm/io.h> #include <asm/irq.h> #include <asm/machdep.h> #include <asm/pmac_feature.h> diff --git a/sound/sh/aica.c b/sound/sh/aica.c index f44dda610ed2..ad3d9ae38034 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -35,12 +35,12 @@ #include <linux/timer.h> #include <linux/delay.h> #include <linux/workqueue.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> #include <sound/initval.h> #include <sound/info.h> -#include <asm/io.h> #include <asm/dma.h> #include <mach/sysasic.h> #include "aica.h" @@ -343,11 +343,9 @@ static void spu_begin_dma(struct snd_pcm_substream *substream) mod_timer(&dreamcastcard->timer, jiffies + 4); return; } - init_timer(&(dreamcastcard->timer)); - dreamcastcard->timer.data = (unsigned long) substream; - dreamcastcard->timer.function = aica_period_elapsed; - dreamcastcard->timer.expires = jiffies + 4; - add_timer(&(dreamcastcard->timer)); + setup_timer(&dreamcastcard->timer, aica_period_elapsed, + (unsigned long) substream); + mod_timer(&dreamcastcard->timer, jiffies + 4); } static int snd_aicapcm_pcm_open(struct snd_pcm_substream diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index fb0b7e8b08ff..841d05946b88 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * When the bit clock is input, limit the maximum rate according to the + * Serial Clock Ratio Considerations section from the SSC documentation: + * + * The Transmitter and the Receiver can be programmed to operate + * with the clock signals provided on either the TK or RK pins. + * This allows the SSC to support many slave-mode data transfers. + * In this case, the maximum clock speed allowed on the RK pin is: + * - Peripheral clock divided by 2 if Receiver Frame Synchro is input + * - Peripheral clock divided by 3 if Receiver Frame Synchro is output + * In addition, the maximum clock speed allowed on the TK pin is: + * - Peripheral clock divided by 6 if Transmit Frame Synchro is input + * - Peripheral clock divided by 2 if Transmit Frame Synchro is output + * + * When the bit clock is output, limit the rate according to the + * SSC divider restrictions. + */ +static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct atmel_ssc_info *ssc_p = rule->private; + struct ssc_device *ssc = ssc_p->ssc; + struct snd_interval *i = hw_param_interval(params, rule->var); + struct snd_interval t; + struct snd_ratnum r = { + .den_min = 1, + .den_max = 4095, + .den_step = 1, + }; + unsigned int num = 0, den = 0; + int frame_size; + int mck_div = 2; + int ret; + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) + return frame_size; + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFS: + if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) + && ssc->clk_from_rk_pin) + /* Receiver Frame Synchro (i.e. capture) + * is output (format is _CFS) and the RK pin + * is used for input (format is _CBM_). + */ + mck_div = 3; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) + && !ssc->clk_from_rk_pin) + /* Transmit Frame Synchro (i.e. playback) + * is input (format is _CFM) and the TK pin + * is used for input (format _CBM_ but not + * using the RK pin). + */ + mck_div = 6; + break; + } + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + r.num = ssc_p->mck_rate / mck_div / frame_size; + + ret = snd_interval_ratnum(i, 1, &r, &num, &den); + if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) { + params->rate_num = num; + params->rate_den = den; + } + break; + + case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBM_CFM: + t.min = 8000; + t.max = ssc_p->mck_rate / mck_div / frame_size; + t.openmin = t.openmax = 0; + t.integer = 0; + ret = snd_interval_refine(i, &t); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} /*-------------------------------------------------------------------------*\ * DAI functions @@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask; + int ret; pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", ssc_readl(ssc_p->ssc->regs, SR)); @@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); clk_enable(ssc_p->ssc->clk); + ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk); /* Reset the SSC to keep it at a clean status */ ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); @@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, dir_mask = SSC_DIR_MASK_CAPTURE; } + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + atmel_ssc_hw_rule_rate, + ssc_p, + SNDRV_PCM_HW_PARAM_FRAME_BITS, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret < 0) { + dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret); + return ret; + } + dma_params = &ssc_dma_params[dai->id][dir]; dma_params->ssc = ssc_p->ssc; dma_params->substream = substream; @@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) # define atmel_ssc_resume NULL #endif /* CONFIG_PM */ -#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) - #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .playback = { .channels_min = 1, .channels_max = 2, - .rates = ATMEL_SSC_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .capture = { .channels_min = 1, .channels_max = 2, - .rates = ATMEL_SSC_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, }; diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index b1f08d511495..80b153857a88 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -115,6 +115,7 @@ struct atmel_ssc_info { unsigned short rcmr_period; struct atmel_pcm_dma_params *dma_params[2]; struct atmel_ssc_state ssc_state; + unsigned long mck_rate; }; int atmel_ssc_set_audio(int ssc_id); diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index f5ad214663f9..8de836165cf2 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -46,8 +46,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h> -#include <asm/mach-types.h> - #include "../codecs/wm8731.h" #include "atmel-pcm.h" #include "atmel_ssc_dai.h" @@ -171,9 +169,7 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) int ret; if (!np) { - if (!(machine_is_at91sam9g20ek() || - machine_is_at91sam9g20ek_2mmc())) - return -ENODEV; + return -ENODEV; } ret = atmel_ssc_set_audio(0); @@ -210,39 +206,37 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; /* Parse device node info */ - if (np) { - ret = snd_soc_of_parse_card_name(card, "atmel,model"); - if (ret) - goto err; - - ret = snd_soc_of_parse_audio_routing(card, - "atmel,audio-routing"); - if (ret) - goto err; - - /* Parse codec info */ - at91sam9g20ek_dai.codec_name = NULL; - codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); - if (!codec_np) { - dev_err(&pdev->dev, "codec info missing\n"); - return -EINVAL; - } - at91sam9g20ek_dai.codec_of_node = codec_np; - - /* Parse dai and platform info */ - at91sam9g20ek_dai.cpu_dai_name = NULL; - at91sam9g20ek_dai.platform_name = NULL; - cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); - if (!cpu_np) { - dev_err(&pdev->dev, "dai and pcm info missing\n"); - return -EINVAL; - } - at91sam9g20ek_dai.cpu_of_node = cpu_np; - at91sam9g20ek_dai.platform_of_node = cpu_np; - - of_node_put(codec_np); - of_node_put(cpu_np); + ret = snd_soc_of_parse_card_name(card, "atmel,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, + "atmel,audio-routing"); + if (ret) + goto err; + + /* Parse codec info */ + at91sam9g20ek_dai.codec_name = NULL; + codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "codec info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.codec_of_node = codec_np; + + /* Parse dai and platform info */ + at91sam9g20ek_dai.cpu_dai_name = NULL; + at91sam9g20ek_dai.platform_name = NULL; + cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "dai and pcm info missing\n"); + return -EINVAL; } + at91sam9g20ek_dai.cpu_of_node = cpu_np; + at91sam9g20ek_dai.platform_of_node = cpu_np; + + of_node_put(codec_np); + of_node_put(cpu_np); ret = snd_soc_register_card(card); if (ret) { diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 7b7fbcd49e5e..c7cd60f009e9 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -16,7 +16,7 @@ config SND_EP93XX_SOC_AC97 config SND_EP93XX_SOC_SNAPPERCL15 tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" - depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 + depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C select SND_EP93XX_SOC_I2S select SND_SOC_TLV320AIC23_I2C help diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 064e6c18e109..ea9f0e31f9d4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -69,7 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98088 if I2C select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C - select SND_SOC_MAX98357A + select SND_SOC_MAX98357A if GPIOLIB select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 70ab35744aba..7ad8e156e2df 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, adau1977->dvdd_reg = NULL; } - adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); - if (IS_ERR(adau1977->reset_gpio)) { - ret = PTR_ERR(adau1977->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return PTR_ERR(adau1977->reset_gpio); - adau1977->reset_gpio = NULL; - } + adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(adau1977->reset_gpio)) + return PTR_ERR(adau1977->reset_gpio); dev_set_drvdata(dev, adau1977); - if (adau1977->reset_gpio) { - ret = gpiod_direction_output(adau1977->reset_gpio, 0); - if (ret) - return ret; + if (adau1977->reset_gpio) ndelay(100); - } ret = adau1977_power_enable(adau1977); if (ret) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index f2b8aad21274..60598b230341 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -437,20 +437,13 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, } /* Reset the Device */ - cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev, - "reset-gpios"); - if (IS_ERR(cs35l32->reset_gpio)) { - ret = PTR_ERR(cs35l32->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - cs35l32->reset_gpio = NULL; - } else { - ret = gpiod_direction_output(cs35l32->reset_gpio, 0); - if (ret) - return ret; + cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs35l32->reset_gpio)) + return PTR_ERR(cs35l32->reset_gpio); + + if (cs35l32->reset_gpio) gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); - } /* initialize codec */ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index ce6086835ebd..cac48ddf3ba6 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -605,21 +605,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, return ret; } - cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev, - "reset-gpios"); - if (IS_ERR(cs4265->reset_gpio)) { - ret = PTR_ERR(cs4265->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - cs4265->reset_gpio = NULL; - } else { - ret = gpiod_direction_output(cs4265->reset_gpio, 0); - if (ret) - return ret; + cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs4265->reset_gpio)) + return PTR_ERR(cs4265->reset_gpio); + + if (cs4265->reset_gpio) { mdelay(1); gpiod_set_value_cansleep(cs4265->reset_gpio, 1); - } i2c_set_clientdata(i2c_client, cs4265); diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 1806333ea29e..e9e6efbc21dd 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -12,9 +12,19 @@ * max98357a.c -- MAX98357A ALSA SoC Codec driver */ -#include <linux/module.h> +#include <linux/device.h> +#include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <sound/pcm.h> #include <sound/soc.h> +#include <sound/soc-dai.h> +#include <sound/soc-dapm.h> #define DRV_NAME "max98357a" diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 9974f201a08f..4b5f1fe9be97 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -54,6 +54,9 @@ struct pcm512x_priv { int pll_d; int pll_p; unsigned long real_pll; + unsigned long overclock_pll; + unsigned long overclock_dac; + unsigned long overclock_dsp; }; /* @@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg) } } +static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_pll; + return 0; +} + +static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_pll = ucontrol->value.integer.value[0]; + return 0; +} + +static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_dsp; + return 0; +} + +static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_dsp = ucontrol->value.integer.value[0]; + return 0; +} + +static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_dac; + return 0; +} + +static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_dac = ucontrol->value.integer.value[0]; + return 0; +} + static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); @@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), + +SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0, + pcm512x_overclock_pll_get, pcm512x_overclock_pll_put), +SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0, + pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put), +SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0, + pcm512x_overclock_dac_get, pcm512x_overclock_dac_put), }; static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { @@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { { "OUTR", NULL, "DACR" }, }; +static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x) +{ + return 25000000 + 25000000 * pcm512x->overclock_pll / 100; +} + +static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x) +{ + return 50000000 + 50000000 * pcm512x->overclock_dsp / 100; +} + +static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x, + unsigned long rate) +{ + return rate + rate * pcm512x->overclock_dac / 100; +} + +static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x) +{ + if (!pcm512x->pll_out) + return 25000000; + return pcm512x_pll_max(pcm512x); +} + +static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x, + unsigned long dac_rate) +{ + /* + * If the DAC is not actually overclocked, use the good old + * NCP target rate... + */ + if (dac_rate <= 6144000) + return 1536000; + /* + * ...but if the DAC is in fact overclocked, bump the NCP target + * rate to get the recommended dividers even when overclocking. + */ + return pcm512x_dac_max(pcm512x, 1536000); +} + static const u32 pcm512x_dai_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, 384000, @@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = { static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { + struct pcm512x_priv *pcm512x = rule->private; struct snd_interval ranges[2]; int frame_size; @@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, */ memset(ranges, 0, sizeof(ranges)); ranges[0].min = 8000; - ranges[0].max = 25000000 / frame_size / 2; + ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2; ranges[1].min = DIV_ROUND_UP(16000000, frame_size); ranges[1].max = 384000; break; @@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream, return snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, pcm512x_hw_rule_rate, - NULL, + pcm512x, SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); @@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, unsigned long bclk_rate) { struct device *dev = dai->dev; + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); unsigned long sck_rate; int pow2; @@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, * as many factors of 2 as possible, as that makes it easier * to find a fast DAC rate */ - pow2 = 1 << fls((25000000 - 16000000) / bclk_rate); + pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate); for (; pow2; pow2 >>= 1) { - sck_rate = rounddown(25000000, bclk_rate * pow2); + sck_rate = rounddown(pcm512x_pll_max(pcm512x), + bclk_rate * pow2); if (sck_rate >= 16000000) break; } @@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, return 0; /* futile, quit early */ /* run DAC no faster than 6144000 Hz */ - for (dac_rate = rounddown(6144000, osr_rate); + for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate); dac_rate; dac_rate -= osr_rate) { @@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, osr_rate = 16 * sample_rate; /* run DSP no faster than 50 MHz */ - dsp_div = mck_rate > 50000000 ? 2 : 1; + dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1; dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); if (dac_rate) { @@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, dacsrc_rate = pllin_rate; } else { /* run DAC no faster than 6144000 Hz */ - unsigned long dac_mul = 6144000 / osr_rate; + unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000) + / osr_rate; unsigned long sck_mul = sck_rate / osr_rate; for (; dac_mul; dac_mul--) { @@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, dacsrc_rate = sck_rate; } + osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); + if (osr_div > 128) { + dev_err(dev, "Failed to find OSR divider\n"); + return -EINVAL; + } + dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); if (dac_div > 128) { dev_err(dev, "Failed to find DAC divider\n"); return -EINVAL; } + dac_rate = dacsrc_rate / dac_div; - ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000); - if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) { + ncp_div = DIV_ROUND_CLOSEST(dac_rate, + pcm512x_ncp_target(pcm512x, dac_rate)); + if (ncp_div > 128 || dac_rate / ncp_div > 2048000) { /* run NCP no faster than 2048000 Hz, but why? */ - ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000); + ncp_div = DIV_ROUND_UP(dac_rate, 2048000); if (ncp_div > 128) { dev_err(dev, "Failed to find NCP divider\n"); return -EINVAL; } } - osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); - if (osr_div > 128) { - dev_err(dev, "Failed to find OSR divider\n"); - return -EINVAL; - } - idac = mck_rate / (dsp_div * sample_rate); ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); @@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, return ret; } - if (sample_rate <= 48000) + if (sample_rate <= pcm512x_dac_max(pcm512x, 48000)) fssp = PCM512x_FSSP_48KHZ; - else if (sample_rate <= 96000) + else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000)) fssp = PCM512x_FSSP_96KHZ; - else if (sample_rate <= 192000) + else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000)) fssp = PCM512x_FSSP_192KHZ; else fssp = PCM512x_FSSP_384KHZ; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index e1a4a45c57e2..fd102613d20d 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -225,7 +225,6 @@ static bool rt5670_volatile_register(struct device *dev, unsigned int reg) case RT5670_ADC_EQ_CTRL1: case RT5670_EQ_CTRL1: case RT5670_ALC_CTRL_1: - case RT5670_IRQ_CTRL1: case RT5670_IRQ_CTRL2: case RT5670_INT_IRQ_ST: case RT5670_IL_CMD: @@ -2703,6 +2702,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, regmap_write(rt5670->regmap, RT5670_RESET, 0); + regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val); + if (val >= 4) + regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980); + else + regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00); + ret = regmap_register_patch(rt5670->regmap, init_list, ARRAY_SIZE(init_list)); if (ret != 0) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 5d0bb8748dd1..fb9c20eace3f 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3284,8 +3284,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IB45 Bypass Mux", "Bypass", "IB45 Mux" }, { "IB45 Bypass Mux", "Pass SRC", "IB45 Mux" }, - { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6" }, - { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6" }, + { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6 Mux" }, + { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6 Mux" }, { "IB6 Mux", "SLB DAC 6", "SLB DAC6" }, { "IB6 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" }, { "IB6 Mux", "IF4 DAC L", "IF4 DAC L" }, @@ -3293,8 +3293,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IB6 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" }, { "IB6 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" }, - { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7" }, - { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7" }, + { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7 Mux" }, + { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7 Mux" }, { "IB7 Mux", "SLB DAC 7", "SLB DAC7" }, { "IB7 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" }, { "IB7 Mux", "IF4 DAC R", "IF4 DAC R" }, @@ -3635,15 +3635,15 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC1 FS", NULL, "DAC1 MIXL" }, { "DAC1 FS", NULL, "DAC1 MIXR" }, - { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2" }, - { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2" }, + { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2 Mux" }, + { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2 Mux" }, { "DAC2 L Mux", "IF3 DAC L", "IF3 DAC L" }, { "DAC2 L Mux", "IF4 DAC L", "IF4 DAC L" }, { "DAC2 L Mux", "SLB DAC 2", "SLB DAC2" }, { "DAC2 L Mux", "OB 2", "OutBound2" }, - { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3" }, - { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3" }, + { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3 Mux" }, + { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3 Mux" }, { "DAC2 R Mux", "IF3 DAC R", "IF3 DAC R" }, { "DAC2 R Mux", "IF4 DAC R", "IF4 DAC R" }, { "DAC2 R Mux", "SLB DAC 3", "SLB DAC3" }, @@ -3651,29 +3651,29 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC2 R Mux", "Haptic Generator", "Haptic Generator" }, { "DAC2 R Mux", "VAD ADC", "VAD ADC Mux" }, - { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4" }, - { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4" }, + { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4 Mux" }, + { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4 Mux" }, { "DAC3 L Mux", "IF3 DAC L", "IF3 DAC L" }, { "DAC3 L Mux", "IF4 DAC L", "IF4 DAC L" }, { "DAC3 L Mux", "SLB DAC 4", "SLB DAC4" }, { "DAC3 L Mux", "OB 4", "OutBound4" }, - { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC4" }, - { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC4" }, + { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC5 Mux" }, + { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC5 Mux" }, { "DAC3 R Mux", "IF3 DAC R", "IF3 DAC R" }, { "DAC3 R Mux", "IF4 DAC R", "IF4 DAC R" }, { "DAC3 R Mux", "SLB DAC 5", "SLB DAC5" }, { "DAC3 R Mux", "OB 5", "OutBound5" }, - { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6" }, - { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6" }, + { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6 Mux" }, + { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6 Mux" }, { "DAC4 L Mux", "IF3 DAC L", "IF3 DAC L" }, { "DAC4 L Mux", "IF4 DAC L", "IF4 DAC L" }, { "DAC4 L Mux", "SLB DAC 6", "SLB DAC6" }, { "DAC4 L Mux", "OB 6", "OutBound6" }, - { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7" }, - { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7" }, + { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7 Mux" }, + { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7 Mux" }, { "DAC4 R Mux", "IF3 DAC R", "IF3 DAC R" }, { "DAC4 R Mux", "IF4 DAC R", "IF4 DAC R" }, { "DAC4 R Mux", "SLB DAC 7", "SLB DAC7" }, diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 3a1343fa109b..007a0e3bc273 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -106,13 +106,11 @@ static const struct reg_default sta32x_regs[] = { }; static const struct regmap_range sta32x_write_regs_range[] = { - regmap_reg_range(STA32X_CONFA, STA32X_AUTO2), - regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2), + regmap_reg_range(STA32X_CONFA, STA32X_FDRC2), }; static const struct regmap_range sta32x_read_regs_range[] = { - regmap_reg_range(STA32X_CONFA, STA32X_AUTO2), - regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2), + regmap_reg_range(STA32X_CONFA, STA32X_FDRC2), }; static const struct regmap_range sta32x_volatile_regs_range[] = { diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index bda2ee18769e..669e3228241e 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1213,27 +1213,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c, #endif /* GPIOs */ - sta350->gpiod_nreset = devm_gpiod_get(dev, "reset"); - if (IS_ERR(sta350->gpiod_nreset)) { - ret = PTR_ERR(sta350->gpiod_nreset); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - sta350->gpiod_nreset = NULL; - } else { - gpiod_direction_output(sta350->gpiod_nreset, 0); - } - - sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down"); - if (IS_ERR(sta350->gpiod_power_down)) { - ret = PTR_ERR(sta350->gpiod_power_down); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - sta350->gpiod_power_down = NULL; - } else { - gpiod_direction_output(sta350->gpiod_power_down, 0); - } + sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(sta350->gpiod_nreset)) + return PTR_ERR(sta350->gpiod_nreset); + + sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down", + GPIOD_OUT_LOW); + if (IS_ERR(sta350->gpiod_power_down)) + return PTR_ERR(sta350->gpiod_power_down); /* regulators */ for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index ae23acdd2708..dfb4ff5cc9ea 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -485,16 +485,9 @@ static int tas2552_probe(struct i2c_client *client, if (data == NULL) return -ENOMEM; - data->enable_gpio = devm_gpiod_get(dev, "enable"); - if (IS_ERR(data->enable_gpio)) { - ret = PTR_ERR(data->enable_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - data->enable_gpio = NULL; - } else { - gpiod_direction_output(data->enable_gpio, 0); - } + data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(data->enable_gpio)) + return PTR_ERR(data->enable_gpio); data->tas2552_client = client; data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config); diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 3f6959c8e2f7..de438871040b 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -512,6 +512,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) memcpy(priv->dai_link, fsl_asoc_card_dai, sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); + goto asrc_fail; + } + /* Normal DAI Link */ priv->dai_link[0].cpu_of_node = cpu_np; priv->dai_link[0].codec_of_node = codec_np; diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2595611e8a6d..b9fabbf69db6 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -603,10 +603,6 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, factor = (div2 + 1) * (7 * psr + 1) * 2; for (i = 0; i < 255; i++) { - /* The bclk rate must be smaller than 1/5 sysclk rate */ - if (factor * (i + 1) < 5) - continue; - tmprate = freq * factor * (i + 2); if (baudclk_is_used) @@ -614,6 +610,13 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, else clkrate = clk_round_rate(ssi_private->baudclk, tmprate); + /* + * Hardware limitation: The bclk rate must be + * never greater than 1/5 IPG clock rate + */ + if (clkrate * 5 > clk_get_rate(ssi_private->clk)) + continue; + clkrate /= factor; afreq = clkrate / (i + 1); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f7c6734bd5da..fb550b5869d2 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -372,6 +372,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, strlen(dai_link->cpu_dai_name) + strlen(dai_link->codec_dai_name) + 2, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto dai_link_of_err; + } + sprintf(name, "%s-%s", dai_link->cpu_dai_name, dai_link->codec_dai_name); dai_link->name = dai_link->stream_name = name; diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 9cf7d01479ad..fba2ef5dac42 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -110,9 +110,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP0 to 16 bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S16_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); return 0; } diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c index 59308629043e..3b262d01c1b3 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c @@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c index bd29617a9ab9..dd935255a020 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/cht_bsw_rt5645.c @@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index ff016621583a..bc8dcacd5e6a 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -178,9 +178,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } @@ -217,7 +215,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, + .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, @@ -240,13 +238,13 @@ static struct snd_soc_dai_link cht_dailink[] = { .cpu_dai_name = "ssp2-port", .platform_name = "sst-mfld-platform", .no_pcm = 1, + .nonatomic = true, .codec_dai_name = "rt5670-aif1", .codec_name = "i2c-10EC5670:00", .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .ignore_suspend = 1, .dpcm_playback = 1, .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, @@ -285,7 +283,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-rt5672", - .pm = &snd_soc_pm_ops, }, .probe = snd_cht_mc_probe, }; diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 35edf51a52aa..00fddd3f5dfb 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c @@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP0 to 16 bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S16_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); return 0; } diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index dfebfdd5eb2a..daecc58f28af 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -150,7 +150,7 @@ enum sst_cmd_type { enum sst_task { SST_TASK_SBA = 1, - SST_TASK_MMX, + SST_TASK_MMX = 3, }; enum sst_type { diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 0ab1309ef274..394af5684c05 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -31,6 +31,7 @@ #include <linux/dma-mapping.h> #include <linux/debugfs.h> #include <linux/pm_runtime.h> +#include <sound/asound.h> #include "sst-haswell-ipc.h" #include "sst-dsp.h" @@ -242,6 +243,9 @@ struct sst_hsw_stream { u32 (*notify_position)(struct sst_hsw_stream *stream, void *data); void *pdata; + /* record the fw read position when playback */ + snd_pcm_uframes_t old_position; + bool play_silence; struct list_head node; }; @@ -1347,6 +1351,30 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) return 0; } +snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream) +{ + return stream->old_position; +} + +void sst_hsw_stream_set_old_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream, snd_pcm_uframes_t val) +{ + stream->old_position = val; +} + +bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw, + struct sst_hsw_stream *stream) +{ + return stream->play_silence; +} + +void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw, + struct sst_hsw_stream *stream, bool val) +{ + stream->play_silence = val; +} + /* Stream Information - these calls could be inline but we want the IPC ABI to be opaque to client PCM drivers to cope with any future ABI changes */ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index c1ad901342f2..858096041cb1 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -20,6 +20,7 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/platform_device.h> +#include <sound/asound.h> #define SST_HSW_NO_CHANNELS 4 #define SST_HSW_MAX_DX_REGIONS 14 @@ -425,6 +426,14 @@ int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 offset, u32 size); int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 offset, u32 size); +snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream); +void sst_hsw_stream_set_old_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream, snd_pcm_uframes_t val); +bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw, + struct sst_hsw_stream *stream); +void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw, + struct sst_hsw_stream *stream, bool val); int sst_hsw_mixer_get_info(struct sst_hsw *hsw); /* Stream ALSA trigger operations */ diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 78fa01be57f2..7e21e8f85885 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -36,6 +36,11 @@ #define HSW_PCM_COUNT 6 #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ +#define SST_OLD_POSITION(d, r, o) ((d) + \ + frames_to_bytes(r, o)) +#define SST_SAMPLES(r, x) (bytes_to_samples(r, \ + frames_to_bytes(r, (x)))) + /* simple volume table */ static const u32 volume_map[] = { HSW_VOLUME_MAX >> 30, @@ -86,7 +91,8 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP | + SNDRV_PCM_INFO_DRAIN_TRIGGER, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .period_bytes_min = PAGE_SIZE, @@ -577,23 +583,34 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); struct hsw_pcm_data *pcm_data; + struct sst_hsw_stream *sst_stream; struct sst_hsw *hsw = pdata->hsw; + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t pos; int dai; dai = mod_map[rtd->cpu_dai->id].dai_id; pcm_data = &pdata->pcm[dai][substream->stream]; + sst_stream = pcm_data->stream; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + sst_hsw_stream_set_silence_start(hsw, sst_stream, false); sst_hsw_stream_resume(hsw, pcm_data->stream, 0); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + sst_hsw_stream_set_silence_start(hsw, sst_stream, false); sst_hsw_stream_pause(hsw, pcm_data->stream, 0); break; + case SNDRV_PCM_TRIGGER_DRAIN: + pos = runtime->control->appl_ptr % runtime->buffer_size; + sst_hsw_stream_set_old_position(hsw, pcm_data->stream, pos); + sst_hsw_stream_set_silence_start(hsw, sst_stream, true); + break; default: break; } @@ -607,13 +624,62 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) struct snd_pcm_substream *substream = pcm_data->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct hsw_priv_data *pdata = + snd_soc_platform_get_drvdata(rtd->platform); + struct sst_hsw *hsw = pdata->hsw; u32 pos; + snd_pcm_uframes_t position = bytes_to_frames(runtime, + sst_hsw_get_dsp_position(hsw, pcm_data->stream)); + unsigned char *dma_area = runtime->dma_area; + snd_pcm_uframes_t dma_frames = + bytes_to_frames(runtime, runtime->dma_bytes); + snd_pcm_uframes_t old_position; + ssize_t samples; pos = frames_to_bytes(runtime, (runtime->control->appl_ptr % runtime->buffer_size)); dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); + /* SST fw don't know where to stop dma + * So, SST driver need to clean the data which has been consumed + */ + if (dma_area == NULL || dma_frames <= 0 + || (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + || !sst_hsw_stream_get_silence_start(hsw, stream)) { + snd_pcm_period_elapsed(substream); + return pos; + } + + old_position = sst_hsw_stream_get_old_position(hsw, stream); + if (position > old_position) { + if (position < dma_frames) { + samples = SST_SAMPLES(runtime, position - old_position); + snd_pcm_format_set_silence(runtime->format, + SST_OLD_POSITION(dma_area, + runtime, old_position), + samples); + } else + dev_err(rtd->dev, "PCM: position is wrong\n"); + } else { + if (old_position < dma_frames) { + samples = SST_SAMPLES(runtime, + dma_frames - old_position); + snd_pcm_format_set_silence(runtime->format, + SST_OLD_POSITION(dma_area, + runtime, old_position), + samples); + } else + dev_err(rtd->dev, "PCM: dma_bytes is wrong\n"); + if (position < dma_frames) { + samples = SST_SAMPLES(runtime, position); + snd_pcm_format_set_silence(runtime->format, + dma_area, samples); + } else + dev_err(rtd->dev, "PCM: position is wrong\n"); + } + sst_hsw_stream_set_old_position(hsw, stream, position); + /* let alsa know we have play a period */ snd_pcm_period_elapsed(substream); return pos; diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 7523cbef8780..2fbaf2c75d17 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: dev_dbg(rtd->dev, "sst: in pause\n"); status = SST_PLATFORM_PAUSED; ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: dev_dbg(rtd->dev, "sst: in pause release\n"); status = SST_PLATFORM_RUNNING; ret_val = stream->ops->stream_pause_release(sst->dev, str_id); @@ -665,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) static int sst_soc_probe(struct snd_soc_platform *platform) { + struct sst_data *drv = dev_get_drvdata(platform->dev); + + drv->soc_card = platform->component.card; return sst_dsp_init_v2_dpcm(platform); } @@ -727,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP + +static int sst_soc_prepare(struct device *dev) +{ + struct sst_data *drv = dev_get_drvdata(dev); + int i; + + /* suspend all pcms first */ + snd_soc_suspend(drv->soc_card->dev); + snd_soc_poweroff(drv->soc_card->dev); + + /* set the SSPs to idle */ + for (i = 0; i < drv->soc_card->num_rtd; i++) { + struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + + if (dai->active) { + send_ssp_cmd(dai, dai->name, 0); + sst_handle_vb_timer(dai, false); + } + } + + return 0; +} + +static void sst_soc_complete(struct device *dev) +{ + struct sst_data *drv = dev_get_drvdata(dev); + int i; + + /* restart SSPs */ + for (i = 0; i < drv->soc_card->num_rtd; i++) { + struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + + if (dai->active) { + sst_handle_vb_timer(dai, true); + send_ssp_cmd(dai, dai->name, 1); + } + } + snd_soc_resume(drv->soc_card->dev); +} + +#else + +#define sst_soc_prepare NULL +#define sst_soc_complete NULL + +#endif + + +static const struct dev_pm_ops sst_platform_pm = { + .prepare = sst_soc_prepare, + .complete = sst_soc_complete, +}; + static struct platform_driver sst_platform_driver = { .driver = { .name = "sst-mfld-platform", + .pm = &sst_platform_pm, }, .probe = sst_platform_probe, .remove = sst_platform_remove, diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 79c8d1246a8f..9094314be2b0 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -174,6 +174,7 @@ struct sst_data { struct sst_platform_data *pdata; struct snd_sst_bytes_v2 *byte_stream; struct mutex lock; + struct snd_soc_card *soc_card; }; int sst_register_dsp(struct sst_device *sst); int sst_unregister_dsp(struct sst_device *sst); diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index 8a8d56a146e7..1a7eeec444b1 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c @@ -350,7 +350,9 @@ static inline void sst_save_shim64(struct intel_sst_drv *ctx, spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); - shim_regs->imrx = sst_shim_read64(shim, SST_IMRX), + shim_regs->imrx = sst_shim_read64(shim, SST_IMRX); + shim_regs->csr = sst_shim_read64(shim, SST_CSR); + spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); } @@ -367,6 +369,7 @@ static inline void sst_restore_shim64(struct intel_sst_drv *ctx, */ spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); sst_shim_write64(shim, SST_IMRX, shim_regs->imrx), + sst_shim_write64(shim, SST_CSR, shim_regs->csr), spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); } @@ -379,6 +382,10 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx) * initially active. So change the state to active before * enabling the pm */ + + if (!acpi_disabled) + pm_runtime_set_active(ctx->dev); + pm_runtime_enable(ctx->dev); if (acpi_disabled) @@ -409,29 +416,142 @@ static int intel_sst_runtime_suspend(struct device *dev) synchronize_irq(ctx->irq_num); flush_workqueue(ctx->post_msg_wq); + ctx->ops->reset(ctx); /* save the shim registers because PMC doesn't save state */ sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); return ret; } -static int intel_sst_runtime_resume(struct device *dev) +static int intel_sst_suspend(struct device *dev) { - int ret = 0; struct intel_sst_drv *ctx = dev_get_drvdata(dev); + struct sst_fw_save *fw_save; + int i, ret = 0; - if (ctx->sst_state == SST_RESET) { - ret = sst_load_fw(ctx); - if (ret) { - dev_err(dev, "FW download fail %d\n", ret); - sst_set_fw_state_locked(ctx, SST_RESET); + /* check first if we are already in SW reset */ + if (ctx->sst_state == SST_RESET) + return 0; + + /* + * check if any stream is active and running + * they should already by suspend by soc_suspend + */ + for (i = 1; i <= ctx->info.max_streams; i++) { + struct stream_info *stream = &ctx->streams[i]; + + if (stream->status == STREAM_RUNNING) { + dev_err(dev, "stream %d is running, cant susupend, abort\n", i); + return -EBUSY; } } + synchronize_irq(ctx->irq_num); + flush_workqueue(ctx->post_msg_wq); + + /* Move the SST state to Reset */ + sst_set_fw_state_locked(ctx, SST_RESET); + + /* tell DSP we are suspending */ + if (ctx->ops->save_dsp_context(ctx)) + return -EBUSY; + + /* save the memories */ + fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL); + if (!fw_save) + return -ENOMEM; + fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); + if (!fw_save->iram) { + ret = -ENOMEM; + goto iram; + } + fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); + if (!fw_save->dram) { + ret = -ENOMEM; + goto dram; + } + fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); + if (!fw_save->sram) { + ret = -ENOMEM; + goto sram; + } + + fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); + if (!fw_save->ddr) { + ret = -ENOMEM; + goto ddr; + } + + memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base); + memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base); + memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE); + memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base); + + ctx->fw_save = fw_save; + ctx->ops->reset(ctx); + return 0; +ddr: + kfree(fw_save->sram); +sram: + kfree(fw_save->dram); +dram: + kfree(fw_save->iram); +iram: + kfree(fw_save); + return ret; +} + +static int intel_sst_resume(struct device *dev) +{ + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + struct sst_fw_save *fw_save = ctx->fw_save; + int ret = 0; + struct sst_block *block; + + if (!fw_save) + return 0; + + sst_set_fw_state_locked(ctx, SST_FW_LOADING); + + /* we have to restore the memory saved */ + ctx->ops->reset(ctx); + + ctx->fw_save = NULL; + + memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base); + memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base); + memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE); + memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base); + + kfree(fw_save->sram); + kfree(fw_save->dram); + kfree(fw_save->iram); + kfree(fw_save->ddr); + kfree(fw_save); + + block = sst_create_block(ctx, 0, FW_DWNL_ID); + if (block == NULL) + return -ENOMEM; + + + /* start and wait for ack */ + ctx->ops->start(ctx); + ret = sst_wait_timeout(ctx, block); + if (ret) { + dev_err(ctx->dev, "fw download failed %d\n", ret); + /* FW download failed due to timeout */ + ret = -EBUSY; + + } else { + sst_set_fw_state_locked(ctx, SST_FW_RUNNING); + } + + sst_free_block(ctx, block); return ret; } const struct dev_pm_ops intel_sst_pm = { + .suspend = intel_sst_suspend, + .resume = intel_sst_resume, .runtime_suspend = intel_sst_runtime_suspend, - .runtime_resume = intel_sst_runtime_resume, }; EXPORT_SYMBOL_GPL(intel_sst_pm); diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 562bc483d6b7..3f493862e98d 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h @@ -337,6 +337,13 @@ struct sst_shim_regs64 { u64 csr2; }; +struct sst_fw_save { + void *iram; + void *dram; + void *sram; + void *ddr; +}; + /** * struct intel_sst_drv - driver ops * @@ -428,6 +435,8 @@ struct intel_sst_drv { * persistent till worker thread gets called */ char firmware_name[FW_NAME_SIZE]; + + struct sst_fw_save *fw_save; }; /* misc definitions */ @@ -544,4 +553,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx, int sst_context_init(struct intel_sst_drv *ctx); void sst_context_cleanup(struct intel_sst_drv *ctx); void sst_configure_runtime_pm(struct intel_sst_drv *ctx); +void memcpy32_toio(void __iomem *dst, const void *src, int count); +void memcpy32_fromio(void *dst, const void __iomem *src, int count); + #endif diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c index 5f75ef3cdd22..f0e4b99b3aeb 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/sst/sst_drv_interface.c @@ -138,12 +138,36 @@ int sst_get_stream(struct intel_sst_drv *ctx, static int sst_power_control(struct device *dev, bool state) { struct intel_sst_drv *ctx = dev_get_drvdata(dev); - - dev_dbg(ctx->dev, "state:%d", state); - if (state == true) - return pm_runtime_get_sync(dev); - else + int ret = 0; + int usage_count = 0; + +#ifdef CONFIG_PM + usage_count = atomic_read(&dev->power.usage_count); +#else + usage_count = 1; +#endif + + if (state == true) { + ret = pm_runtime_get_sync(dev); + + dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); + if (ret < 0) { + dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); + return ret; + } + if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) { + ret = sst_load_fw(ctx); + if (ret) { + dev_err(dev, "FW download fail %d\n", ret); + sst_set_fw_state_locked(ctx, SST_RESET); + ret = sst_pm_runtime_put(ctx); + } + } + } else { + dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count); return sst_pm_runtime_put(ctx); + } + return ret; } /* @@ -572,6 +596,35 @@ static int sst_stream_drop(struct device *dev, int str_id) return sst_drop_stream(ctx, str_id); } +static int sst_stream_pause(struct device *dev, int str_id) +{ + struct stream_info *str_info; + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->sst_state != SST_FW_RUNNING) + return 0; + + str_info = get_stream_info(ctx, str_id); + if (!str_info) + return -EINVAL; + + return sst_pause_stream(ctx, str_id); +} + +static int sst_stream_resume(struct device *dev, int str_id) +{ + struct stream_info *str_info; + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->sst_state != SST_FW_RUNNING) + return 0; + + str_info = get_stream_info(ctx, str_id); + if (!str_info) + return -EINVAL; + return sst_resume_stream(ctx, str_id); +} + static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) { int str_id = 0; @@ -633,6 +686,8 @@ static struct sst_ops pcm_ops = { .stream_init = sst_stream_init, .stream_start = sst_stream_start, .stream_drop = sst_stream_drop, + .stream_pause = sst_stream_pause, + .stream_pause_release = sst_stream_resume, .stream_read_tstamp = sst_read_timestamp, .send_byte_stream = sst_send_byte_stream, .close = sst_close_pcm_stream, diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index 7888cd707853..e88907ae8b15 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c @@ -39,7 +39,15 @@ #include "sst.h" #include "../sst-dsp.h" -static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) +void memcpy32_toio(void __iomem *dst, const void *src, int count) +{ + /* __iowrite32_copy uses 32-bit count values so divide by 4 for + * right count in words + */ + __iowrite32_copy(dst, src, count/4); +} + +void memcpy32_fromio(void *dst, const void __iomem *src, int count) { /* __iowrite32_copy uses 32-bit count values so divide by 4 for * right count in words diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index ccfb41c22e53..f7eb42aa3f38 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -352,6 +352,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) return ret; card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + card->name = devm_kasprintf(dev, GFP_KERNEL, "HDMI %s", dev_name(ad->dssdev)); card->owner = THIS_MODULE; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index c7eb9dd67f60..fd99d89de6a8 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -530,8 +530,19 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_SYSCLK_CLKX_EXT: regs->srgr2 |= CLKSM; + regs->pcr0 |= SCLKME; + /* + * If McBSP is master but yet the CLKX/CLKR pin drives the SRG, + * disable output on those pins. This enables to inject the + * reference clock through CLKX/CLKR. For this to work + * set_dai_sysclk() _needs_ to be called after set_dai_fmt(). + */ + regs->pcr0 &= ~CLKXM; + break; case OMAP_MCBSP_SYSCLK_CLKR_EXT: regs->pcr0 |= SCLKME; + /* Disable ouput on CLKR pin in master mode */ + regs->pcr0 &= ~CLKRM; break; default: err = -ENODEV; diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index f4b05bc23e4b..1343ecbf0bd5 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -201,7 +201,7 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd) struct snd_pcm *pcm = rtd->pcm; int ret; - ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(64)); + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); if (ret) return ret; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 3cebf6ca03df..0632a36852c8 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -174,7 +174,7 @@ config SND_SOC_SMDK_WM8994_PCM config SND_SOC_SPEYSIDE tristate "Audio support for Wolfson Speyside" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER select SND_SAMSUNG_I2S select SND_SOC_WM8996 select SND_SOC_WM9081 @@ -189,7 +189,7 @@ config SND_SOC_TOBERMORY config SND_SOC_BELLS tristate "Audio support for Wolfson Bells" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER select SND_SAMSUNG_I2S select SND_SOC_WM5102 select SND_SOC_WM5110 @@ -206,7 +206,7 @@ config SND_SOC_LOWLAND config SND_SOC_LITTLEMILL tristate "Audio support for Wolfson Littlemill" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C select SND_SAMSUNG_I2S select MFD_WM8994 select SND_SOC_WM8994 @@ -223,7 +223,7 @@ config SND_SOC_SNOW config SND_SOC_ODROIDX2 tristate "Audio support for Odroid-X2 and Odroid-U3" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && I2C select SND_SOC_MAX98090 select SND_SAMSUNG_I2S help @@ -231,6 +231,6 @@ config SND_SOC_ODROIDX2 config SND_SOC_ARNDALE_RT5631_ALC5631 tristate "Audio support for RT5631(ALC5631) on Arndale Board" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && I2C select SND_SAMSUNG_I2S select SND_SOC_RT5631 diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1b53605f7154..110577c52317 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1252,6 +1252,8 @@ static int rsnd_probe(struct platform_device *pdev) goto exit_snd_probe; } + dev_set_drvdata(dev, priv); + /* * asoc register */ @@ -1268,8 +1270,6 @@ static int rsnd_probe(struct platform_device *pdev) goto exit_snd_soc; } - dev_set_drvdata(dev, priv); - pm_runtime_enable(dev); dev_info(dev, "probed\n"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 30579ca5bacb..5c0658d49609 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1561,6 +1561,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, card->num_dapm_widgets); + if (card->of_dapm_widgets) + snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, + card->num_of_dapm_widgets); + /* initialise the sound card only once */ if (card->probe) { ret = card->probe(card); @@ -1616,6 +1620,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, card->num_dapm_routes); + if (card->of_dapm_routes) + snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, + card->num_of_dapm_routes); + for (i = 0; i < card->num_links; i++) { if (card->dai_link[i].dai_fmt) snd_soc_runtime_set_dai_fmt(&card->rtd[i], @@ -3223,8 +3231,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, widgets[i].name = wname; } - card->dapm_widgets = widgets; - card->num_dapm_widgets = num_widgets; + card->of_dapm_widgets = widgets; + card->num_of_dapm_widgets = num_widgets; return 0; } @@ -3308,8 +3316,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } } - card->num_dapm_routes = num_routes; - card->dapm_routes = routes; + card->num_of_dapm_routes = num_routes; + card->of_dapm_routes = routes; return 0; } diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 4864392bfcba..c9917ca5de1a 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -151,7 +151,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea hw.info |= SNDRV_PCM_INFO_BATCH; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - addr_widths = dma_caps.dstn_addr_widths; + addr_widths = dma_caps.dst_addr_widths; else addr_widths = dma_caps.src_addr_widths; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0ae0e2a9eed7..6e3781e88f9a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -301,34 +301,18 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) return symmetry; } -/* - * List of sample sizes that might go over the bus for parameter - * application. There ought to be a wildcard sample size for things - * like the DAC/ADC resolution to use but there isn't right now. - */ -static int sample_sizes[] = { - 24, 32, -}; - static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - int ret, i; + int ret; if (!bits) return; - for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) { - if (bits >= sample_sizes[i]) - continue; - - ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, - sample_sizes[i], bits); - if (ret != 0) - dev_warn(rtd->dev, - "ASoC: Failed to set MSB %d/%d: %d\n", - bits, sample_sizes[i], ret); - } + ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits); + if (ret != 0) + dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n", + bits, ret); } static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) @@ -2527,6 +2511,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); + pcm->nonatomic = rtd->dai_link->nonatomic; rtd->pcm = pcm; pcm->private_data = rtd; diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 86280d63b76d..1b1a89e80d13 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -37,6 +37,7 @@ #include <linux/moduleparam.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> @@ -44,7 +45,6 @@ #include <sound/control.h> #include <sound/initval.h> -#include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 93522072bc87..49195325fdf6 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -53,9 +53,7 @@ int snd_emux_new(struct snd_emux **remu) emu->max_voices = 0; emu->use_time = 0; - init_timer(&emu->tlist); - emu->tlist.function = snd_emux_timer_callback; - emu->tlist.data = (unsigned long)emu; + setup_timer(&emu->tlist, snd_emux_timer_callback, (unsigned long)emu); emu->timer_active = 0; *remu = emu; @@ -160,12 +158,8 @@ int snd_emux_free(struct snd_emux *emu) snd_emux_detach_seq_oss(emu); #endif snd_emux_detach_seq(emu); - snd_emux_delete_hwdep(emu); - - if (emu->sflist) - snd_sf_free(emu->sflist); - + snd_sf_free(emu->sflist); kfree(emu->voices); kfree(emu->name); kfree(emu); diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index 5ae1eae9f6db..e557946718a9 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c @@ -21,7 +21,7 @@ #include <sound/core.h> #include <sound/hwdep.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "emux_voice.h" diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index 319754cf6208..ab37add269ae 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -26,7 +26,7 @@ #ifdef CONFIG_SND_SEQUENCER_OSS #include <linux/export.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <sound/core.h> #include "emux_voice.h" #include <sound/asoundef.h> diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c index 9a38de459acb..599551b5af44 100644 --- a/sound/synth/emux/emux_synth.c +++ b/sound/synth/emux/emux_synth.c @@ -186,8 +186,7 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan) */ vp->state = SNDRV_EMUX_ST_PENDING; if (! emu->timer_active) { - emu->tlist.expires = jiffies + 1; - add_timer(&emu->tlist); + mod_timer(&emu->tlist, jiffies + 1); emu->timer_active = 1; } } else @@ -223,8 +222,7 @@ void snd_emux_timer_callback(unsigned long data) } } if (do_again) { - emu->tlist.expires = jiffies + 1; - add_timer(&emu->tlist); + mod_timer(&emu->tlist, jiffies + 1); emu->timer_active = 1; } else emu->timer_active = 0; diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 78683b2064f7..31a4ea94830e 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -25,7 +25,7 @@ * of doing things so that the old sfxload utility can be used. * Everything may change when there is an alsa way of doing things. */ -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/slab.h> #include <linux/export.h> #include <sound/core.h> diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index d393153c474f..a452ad7cec40 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -160,5 +160,7 @@ config SND_BCD2000 To compile this driver as a module, choose M here: the module will be called snd-bcd2000. +source "sound/usb/line6/Kconfig" + endif # SND_USB diff --git a/sound/usb/Makefile b/sound/usb/Makefile index bcee4060fd18..2d2d122b069f 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ +obj-$(CONFIG_SND_USB_LINE6) += line6/ diff --git a/sound/usb/card.h b/sound/usb/card.h index 97acb906acc2..ef580b43f1e3 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -153,6 +153,8 @@ struct snd_usb_substream { int channel; int byte_idx; } dsd_dop; + + bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ }; struct snd_usb_stream { diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 03fed6611d9e..2ed260b10f6d 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -303,6 +303,11 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, return err; } + /* Don't check the sample rate for devices which we know don't + * support reading */ + if (snd_usb_get_sample_rate_quirk(chip)) + return 0; + if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig new file mode 100644 index 000000000000..f4585d378ef3 --- /dev/null +++ b/sound/usb/line6/Kconfig @@ -0,0 +1,42 @@ +config SND_USB_LINE6 + tristate + select SND_RAWMIDI + select SND_PCM + +config SND_USB_POD + tristate "Line 6 POD USB support" + select SND_USB_LINE6 + help + This is a driver for PODxt and other similar devices, + supporting the following features: + * Reading/writing individual parameters + * Reading/writing complete channel, effects setup, and amp + setup data + * Channel switching + * Virtual MIDI interface + * Tuner access + * Playback/capture/mixer device for any ALSA-compatible PCM + audio application + * Signal routing (record clean/processed guitar signal, + re-amping) + +config SND_USB_PODHD + tristate "Line 6 POD HD300/400/500 USB support" + select SND_USB_LINE6 + help + This is a driver for POD HD300, 400 and 500 devices. + +config SND_USB_TONEPORT + tristate "TonePort GX, UX1 and UX2 USB support" + select SND_USB_LINE6 + select NEW_LEDS + select LEDS_CLASS + help + This is a driver for TonePort GX, UX1 and UX2 devices. + +config SND_USB_VARIAX + tristate "Variax Workbench USB support" + select SND_USB_LINE6 + help + This is a driver for Variax Workbench device. + diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile new file mode 100644 index 000000000000..b8b3b2a543d8 --- /dev/null +++ b/sound/usb/line6/Makefile @@ -0,0 +1,18 @@ +snd-usb-line6-y := \ + capture.o \ + driver.o \ + midi.o \ + midibuf.o \ + pcm.o \ + playback.o + +snd-usb-pod-y := pod.o +snd-usb-podhd-y := podhd.o +snd-usb-toneport-y := toneport.o +snd-usb-variax-y := variax.o + +obj-$(CONFIG_SND_USB_LINE6) += snd-usb-line6.o +obj-$(CONFIG_SND_USB_POD) += snd-usb-pod.o +obj-$(CONFIG_SND_USB_PODHD) += snd-usb-podhd.o +obj-$(CONFIG_SND_USB_TONEPORT) += snd-usb-toneport.o +obj-$(CONFIG_SND_USB_VARIAX) += snd-usb-variax.o diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c new file mode 100644 index 000000000000..f518fbbe88de --- /dev/null +++ b/sound/usb/line6/capture.c @@ -0,0 +1,275 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> + +#include "capture.h" +#include "driver.h" +#include "pcm.h" + +/* + Find a free URB and submit it. + must be called in line6pcm->in.lock context +*/ +static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) +{ + int index; + int i, urb_size; + int ret; + struct urb *urb_in; + + index = + find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS); + + if (index < 0 || index >= LINE6_ISO_BUFFERS) { + dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); + return -EINVAL; + } + + urb_in = line6pcm->in.urbs[index]; + urb_size = 0; + + for (i = 0; i < LINE6_ISO_PACKETS; ++i) { + struct usb_iso_packet_descriptor *fin = + &urb_in->iso_frame_desc[i]; + fin->offset = urb_size; + fin->length = line6pcm->max_packet_size; + urb_size += line6pcm->max_packet_size; + } + + urb_in->transfer_buffer = + line6pcm->in.buffer + + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; + urb_in->transfer_buffer_length = urb_size; + urb_in->context = line6pcm; + + ret = usb_submit_urb(urb_in, GFP_ATOMIC); + + if (ret == 0) + set_bit(index, &line6pcm->in.active_urbs); + else + dev_err(line6pcm->line6->ifcdev, + "URB in #%d submission failed (%d)\n", index, ret); + + return 0; +} + +/* + Submit all currently available capture URBs. + must be called in line6pcm->in.lock context +*/ +int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) +{ + int ret = 0, i; + + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + ret = submit_audio_in_urb(line6pcm); + if (ret < 0) + break; + } + + return ret; +} + +/* + Copy data into ALSA capture buffer. +*/ +void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) +{ + struct snd_pcm_substream *substream = + get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); + struct snd_pcm_runtime *runtime = substream->runtime; + const int bytes_per_frame = line6pcm->properties->bytes_per_frame; + int frames = fsize / bytes_per_frame; + + if (runtime == NULL) + return; + + if (line6pcm->in.pos_done + frames > runtime->buffer_size) { + /* + The transferred area goes over buffer boundary, + copy two separate chunks. + */ + int len; + + len = runtime->buffer_size - line6pcm->in.pos_done; + + if (len > 0) { + memcpy(runtime->dma_area + + line6pcm->in.pos_done * bytes_per_frame, fbuf, + len * bytes_per_frame); + memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, + (frames - len) * bytes_per_frame); + } else { + /* this is somewhat paranoid */ + dev_err(line6pcm->line6->ifcdev, + "driver bug: len = %d\n", len); + } + } else { + /* copy single chunk */ + memcpy(runtime->dma_area + + line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize); + } + + line6pcm->in.pos_done += frames; + if (line6pcm->in.pos_done >= runtime->buffer_size) + line6pcm->in.pos_done -= runtime->buffer_size; +} + +void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) +{ + struct snd_pcm_substream *substream = + get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); + + line6pcm->in.bytes += length; + if (line6pcm->in.bytes >= line6pcm->in.period) { + line6pcm->in.bytes %= line6pcm->in.period; + spin_unlock(&line6pcm->in.lock); + snd_pcm_period_elapsed(substream); + spin_lock(&line6pcm->in.lock); + } +} + +/* + * Callback for completed capture URB. + */ +static void audio_in_callback(struct urb *urb) +{ + int i, index, length = 0, shutdown = 0; + unsigned long flags; + + struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; + + line6pcm->in.last_frame = urb->start_frame; + + /* find index of URB */ + for (index = 0; index < LINE6_ISO_BUFFERS; ++index) + if (urb == line6pcm->in.urbs[index]) + break; + + spin_lock_irqsave(&line6pcm->in.lock, flags); + + for (i = 0; i < LINE6_ISO_PACKETS; ++i) { + char *fbuf; + int fsize; + struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; + + if (fin->status == -EXDEV) { + shutdown = 1; + break; + } + + fbuf = urb->transfer_buffer + fin->offset; + fsize = fin->actual_length; + + if (fsize > line6pcm->max_packet_size) { + dev_err(line6pcm->line6->ifcdev, + "driver and/or device bug: packet too large (%d > %d)\n", + fsize, line6pcm->max_packet_size); + } + + length += fsize; + + /* the following assumes LINE6_ISO_PACKETS == 1: */ + line6pcm->prev_fbuf = fbuf; + line6pcm->prev_fsize = fsize; + + if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && + test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) && + fsize > 0) + line6_capture_copy(line6pcm, fbuf, fsize); + } + + clear_bit(index, &line6pcm->in.active_urbs); + + if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs)) + shutdown = 1; + + if (!shutdown) { + submit_audio_in_urb(line6pcm); + + if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && + test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) + line6_capture_check_period(line6pcm, length); + } + + spin_unlock_irqrestore(&line6pcm->in.lock, flags); +} + +/* open capture callback */ +static int snd_line6_capture_open(struct snd_pcm_substream *substream) +{ + int err; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + err = snd_pcm_hw_constraint_ratdens(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &line6pcm->properties->rates); + if (err < 0) + return err; + + runtime->hw = line6pcm->properties->capture_hw; + return 0; +} + +/* close capture callback */ +static int snd_line6_capture_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* capture operators */ +struct snd_pcm_ops snd_line6_capture_ops = { + .open = snd_line6_capture_open, + .close = snd_line6_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_line6_hw_params, + .hw_free = snd_line6_hw_free, + .prepare = snd_line6_prepare, + .trigger = snd_line6_trigger, + .pointer = snd_line6_pointer, +}; + +int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) +{ + struct usb_line6 *line6 = line6pcm->line6; + int i; + + /* create audio URBs and fill in constant values: */ + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + struct urb *urb; + + /* URB for audio in: */ + urb = line6pcm->in.urbs[i] = + usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); + + if (urb == NULL) + return -ENOMEM; + + urb->dev = line6->usbdev; + urb->pipe = + usb_rcvisocpipe(line6->usbdev, + line6->properties->ep_audio_r & + USB_ENDPOINT_NUMBER_MASK); + urb->transfer_flags = URB_ISO_ASAP; + urb->start_frame = -1; + urb->number_of_packets = LINE6_ISO_PACKETS; + urb->interval = LINE6_ISO_INTERVAL; + urb->error_count = 0; + urb->complete = audio_in_callback; + } + + return 0; +} diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h new file mode 100644 index 000000000000..890b21bff18c --- /dev/null +++ b/sound/usb/line6/capture.h @@ -0,0 +1,29 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef CAPTURE_H +#define CAPTURE_H + +#include <sound/pcm.h> + +#include "driver.h" +#include "pcm.h" + +extern struct snd_pcm_ops snd_line6_capture_ops; + +extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, + int fsize); +extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, + int length); +extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); +extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); + +#endif diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c new file mode 100644 index 000000000000..81b7da8e56d3 --- /dev/null +++ b/sound/usb/line6/driver.c @@ -0,0 +1,672 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <sound/core.h> +#include <sound/initval.h> + +#include "capture.h" +#include "driver.h" +#include "midi.h" +#include "playback.h" + +#define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>" +#define DRIVER_DESC "Line 6 USB Driver" + +/* + This is Line 6's MIDI manufacturer ID. +*/ +const unsigned char line6_midi_id[] = { + 0x00, 0x01, 0x0c +}; +EXPORT_SYMBOL_GPL(line6_midi_id); + +/* + Code to request version of POD, Variax interface + (and maybe other devices). +*/ +static const char line6_request_version[] = { + 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 +}; + +/* + Class for asynchronous messages. +*/ +struct message { + struct usb_line6 *line6; + const char *buffer; + int size; + int done; +}; + +/* + Forward declarations. +*/ +static void line6_data_received(struct urb *urb); +static int line6_send_raw_message_async_part(struct message *msg, + struct urb *urb); + +/* + Start to listen on endpoint. +*/ +static int line6_start_listen(struct usb_line6 *line6) +{ + int err; + + usb_fill_int_urb(line6->urb_listen, line6->usbdev, + usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r), + line6->buffer_listen, LINE6_BUFSIZE_LISTEN, + line6_data_received, line6, line6->interval); + line6->urb_listen->actual_length = 0; + err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); + return err; +} + +/* + Stop listening on endpoint. +*/ +static void line6_stop_listen(struct usb_line6 *line6) +{ + usb_kill_urb(line6->urb_listen); +} + +/* + Send raw message in pieces of wMaxPacketSize bytes. +*/ +static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, + int size) +{ + int i, done = 0; + + for (i = 0; i < size; i += line6->max_packet_size) { + int partial; + const char *frag_buf = buffer + i; + int frag_size = min(line6->max_packet_size, size - i); + int retval; + + retval = usb_interrupt_msg(line6->usbdev, + usb_sndintpipe(line6->usbdev, + line6->properties->ep_ctrl_w), + (char *)frag_buf, frag_size, + &partial, LINE6_TIMEOUT * HZ); + + if (retval) { + dev_err(line6->ifcdev, + "usb_interrupt_msg failed (%d)\n", retval); + break; + } + + done += frag_size; + } + + return done; +} + +/* + Notification of completion of asynchronous request transmission. +*/ +static void line6_async_request_sent(struct urb *urb) +{ + struct message *msg = (struct message *)urb->context; + + if (msg->done >= msg->size) { + usb_free_urb(urb); + kfree(msg); + } else + line6_send_raw_message_async_part(msg, urb); +} + +/* + Asynchronously send part of a raw message. +*/ +static int line6_send_raw_message_async_part(struct message *msg, + struct urb *urb) +{ + int retval; + struct usb_line6 *line6 = msg->line6; + int done = msg->done; + int bytes = min(msg->size - done, line6->max_packet_size); + + usb_fill_int_urb(urb, line6->usbdev, + usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), + (char *)msg->buffer + done, bytes, + line6_async_request_sent, msg, line6->interval); + + msg->done += bytes; + retval = usb_submit_urb(urb, GFP_ATOMIC); + + if (retval < 0) { + dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", + __func__, retval); + usb_free_urb(urb); + kfree(msg); + return retval; + } + + return 0; +} + +/* + Setup and start timer. +*/ +void line6_start_timer(struct timer_list *timer, unsigned long msecs, + void (*function)(unsigned long), unsigned long data) +{ + setup_timer(timer, function, data); + mod_timer(timer, jiffies + msecs_to_jiffies(msecs)); +} +EXPORT_SYMBOL_GPL(line6_start_timer); + +/* + Asynchronously send raw message. +*/ +int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, + int size) +{ + struct message *msg; + struct urb *urb; + + /* create message: */ + msg = kmalloc(sizeof(struct message), GFP_ATOMIC); + if (msg == NULL) + return -ENOMEM; + + /* create URB: */ + urb = usb_alloc_urb(0, GFP_ATOMIC); + + if (urb == NULL) { + kfree(msg); + return -ENOMEM; + } + + /* set message data: */ + msg->line6 = line6; + msg->buffer = buffer; + msg->size = size; + msg->done = 0; + + /* start sending: */ + return line6_send_raw_message_async_part(msg, urb); +} +EXPORT_SYMBOL_GPL(line6_send_raw_message_async); + +/* + Send asynchronous device version request. +*/ +int line6_version_request_async(struct usb_line6 *line6) +{ + char *buffer; + int retval; + + buffer = kmemdup(line6_request_version, + sizeof(line6_request_version), GFP_ATOMIC); + if (buffer == NULL) + return -ENOMEM; + + retval = line6_send_raw_message_async(line6, buffer, + sizeof(line6_request_version)); + kfree(buffer); + return retval; +} +EXPORT_SYMBOL_GPL(line6_version_request_async); + +/* + Send sysex message in pieces of wMaxPacketSize bytes. +*/ +int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, + int size) +{ + return line6_send_raw_message(line6, buffer, + size + SYSEX_EXTRA_SIZE) - + SYSEX_EXTRA_SIZE; +} +EXPORT_SYMBOL_GPL(line6_send_sysex_message); + +/* + Allocate buffer for sysex message and prepare header. + @param code sysex message code + @param size number of bytes between code and sysex end +*/ +char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, + int size) +{ + char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); + + if (!buffer) + return NULL; + + buffer[0] = LINE6_SYSEX_BEGIN; + memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); + buffer[sizeof(line6_midi_id) + 1] = code1; + buffer[sizeof(line6_midi_id) + 2] = code2; + buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; + return buffer; +} +EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer); + +/* + Notification of data received from the Line 6 device. +*/ +static void line6_data_received(struct urb *urb) +{ + struct usb_line6 *line6 = (struct usb_line6 *)urb->context; + struct midi_buffer *mb = &line6->line6midi->midibuf_in; + int done; + + if (urb->status == -ESHUTDOWN) + return; + + done = + line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); + + if (done < urb->actual_length) { + line6_midibuf_ignore(mb, done); + dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", + done, urb->actual_length); + } + + for (;;) { + done = + line6_midibuf_read(mb, line6->buffer_message, + LINE6_MESSAGE_MAXLEN); + + if (done == 0) + break; + + line6->message_length = done; + line6_midi_receive(line6, line6->buffer_message, done); + + if (line6->process_message) + line6->process_message(line6); + } + + line6_start_listen(line6); +} + +#define LINE6_READ_WRITE_STATUS_DELAY 2 /* milliseconds */ +#define LINE6_READ_WRITE_MAX_RETRIES 50 + +/* + Read data from device. +*/ +int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, + unsigned datalen) +{ + struct usb_device *usbdev = line6->usbdev; + int ret; + unsigned char len; + unsigned count; + + if (address > 0xffff || datalen > 0xff) + return -EINVAL; + + /* query the serial number: */ + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + (datalen << 8) | 0x21, address, + NULL, 0, LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); + return ret; + } + + /* Wait for data length. We'll get 0xff until length arrives. */ + for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { + mdelay(LINE6_READ_WRITE_STATUS_DELAY); + + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | + USB_DIR_IN, + 0x0012, 0x0000, &len, 1, + LINE6_TIMEOUT * HZ); + if (ret < 0) { + dev_err(line6->ifcdev, + "receive length failed (error %d)\n", ret); + return ret; + } + + if (len != 0xff) + break; + } + + if (len == 0xff) { + dev_err(line6->ifcdev, "read failed after %d retries\n", + count); + return -EIO; + } else if (len != datalen) { + /* should be equal or something went wrong */ + dev_err(line6->ifcdev, + "length mismatch (expected %d, got %d)\n", + (int)datalen, (int)len); + return -EIO; + } + + /* receive the result: */ + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0013, 0x0000, data, datalen, + LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, "read failed (error %d)\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(line6_read_data); + +/* + Write data to device. +*/ +int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, + unsigned datalen) +{ + struct usb_device *usbdev = line6->usbdev; + int ret; + unsigned char status; + int count; + + if (address > 0xffff || datalen > 0xffff) + return -EINVAL; + + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x0022, address, data, datalen, + LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, + "write request failed (error %d)\n", ret); + return ret; + } + + for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { + mdelay(LINE6_READ_WRITE_STATUS_DELAY); + + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), + 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | + USB_DIR_IN, + 0x0012, 0x0000, + &status, 1, LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, + "receiving status failed (error %d)\n", ret); + return ret; + } + + if (status != 0xff) + break; + } + + if (status == 0xff) { + dev_err(line6->ifcdev, "write failed after %d retries\n", + count); + return -EIO; + } else if (status != 0) { + dev_err(line6->ifcdev, "write failed (error %d)\n", ret); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_GPL(line6_write_data); + +/* + Read Line 6 device serial number. + (POD, TonePort, GuitarPort) +*/ +int line6_read_serial_number(struct usb_line6 *line6, u32 *serial_number) +{ + return line6_read_data(line6, 0x80d0, serial_number, + sizeof(*serial_number)); +} +EXPORT_SYMBOL_GPL(line6_read_serial_number); + +/* + Card destructor. +*/ +static void line6_destruct(struct snd_card *card) +{ + struct usb_line6 *line6 = card->private_data; + struct usb_device *usbdev = line6->usbdev; + + /* free buffer memory first: */ + kfree(line6->buffer_message); + kfree(line6->buffer_listen); + + /* then free URBs: */ + usb_free_urb(line6->urb_listen); + + /* decrement reference counters: */ + usb_put_dev(usbdev); +} + +/* get data from endpoint descriptor (see usb_maxpacket): */ +static void line6_get_interval(struct usb_line6 *line6) +{ + struct usb_device *usbdev = line6->usbdev; + struct usb_host_endpoint *ep; + unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r); + unsigned epnum = usb_pipeendpoint(pipe); + + ep = usbdev->ep_in[epnum]; + if (ep) { + line6->interval = ep->desc.bInterval; + line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); + } else { + dev_err(line6->ifcdev, + "endpoint not available, using fallback values"); + line6->interval = LINE6_FALLBACK_INTERVAL; + line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; + } +} + +static int line6_init_cap_control(struct usb_line6 *line6) +{ + int ret; + + /* initialize USB buffers: */ + line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); + if (!line6->buffer_listen) + return -ENOMEM; + + line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); + if (!line6->buffer_message) + return -ENOMEM; + + line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); + if (!line6->urb_listen) + return -ENOMEM; + + ret = line6_start_listen(line6); + if (ret < 0) { + dev_err(line6->ifcdev, "cannot start listening: %d\n", ret); + return ret; + } + + return 0; +} + +/* + Probe USB device. +*/ +int line6_probe(struct usb_interface *interface, + const struct usb_device_id *id, + const char *driver_name, + const struct line6_properties *properties, + int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), + size_t data_size) +{ + struct usb_device *usbdev = interface_to_usbdev(interface); + struct snd_card *card; + struct usb_line6 *line6; + int interface_number; + int ret; + + if (WARN_ON(data_size < sizeof(*line6))) + return -EINVAL; + + /* we don't handle multiple configurations */ + if (usbdev->descriptor.bNumConfigurations != 1) + return -ENODEV; + + ret = snd_card_new(&interface->dev, + SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, data_size, &card); + if (ret < 0) + return ret; + + /* store basic data: */ + line6 = card->private_data; + line6->card = card; + line6->properties = properties; + line6->usbdev = usbdev; + line6->ifcdev = &interface->dev; + + strcpy(card->id, properties->id); + strcpy(card->driver, driver_name); + strcpy(card->shortname, properties->name); + sprintf(card->longname, "Line 6 %s at USB %s", properties->name, + dev_name(line6->ifcdev)); + card->private_free = line6_destruct; + + usb_set_intfdata(interface, line6); + + /* increment reference counters: */ + usb_get_dev(usbdev); + + /* initialize device info: */ + dev_info(&interface->dev, "Line 6 %s found\n", properties->name); + + /* query interface number */ + interface_number = interface->cur_altsetting->desc.bInterfaceNumber; + + ret = usb_set_interface(usbdev, interface_number, + properties->altsetting); + if (ret < 0) { + dev_err(&interface->dev, "set_interface failed\n"); + goto error; + } + + line6_get_interval(line6); + + if (properties->capabilities & LINE6_CAP_CONTROL) { + ret = line6_init_cap_control(line6); + if (ret < 0) + goto error; + } + + /* initialize device data based on device: */ + ret = private_init(line6, id); + if (ret < 0) + goto error; + + /* creation of additional special files should go here */ + + dev_info(&interface->dev, "Line 6 %s now attached\n", + properties->name); + + return 0; + + error: + if (line6->disconnect) + line6->disconnect(line6); + snd_card_free(card); + return ret; +} +EXPORT_SYMBOL_GPL(line6_probe); + +/* + Line 6 device disconnected. +*/ +void line6_disconnect(struct usb_interface *interface) +{ + struct usb_line6 *line6 = usb_get_intfdata(interface); + struct usb_device *usbdev = interface_to_usbdev(interface); + + if (!line6) + return; + + if (WARN_ON(usbdev != line6->usbdev)) + return; + + if (line6->urb_listen != NULL) + line6_stop_listen(line6); + + snd_card_disconnect(line6->card); + if (line6->line6pcm) + line6_pcm_disconnect(line6->line6pcm); + if (line6->disconnect) + line6->disconnect(line6); + + dev_info(&interface->dev, "Line 6 %s now disconnected\n", + line6->properties->name); + + /* make sure the device isn't destructed twice: */ + usb_set_intfdata(interface, NULL); + + snd_card_free_when_closed(line6->card); +} +EXPORT_SYMBOL_GPL(line6_disconnect); + +#ifdef CONFIG_PM + +/* + Suspend Line 6 device. +*/ +int line6_suspend(struct usb_interface *interface, pm_message_t message) +{ + struct usb_line6 *line6 = usb_get_intfdata(interface); + struct snd_line6_pcm *line6pcm = line6->line6pcm; + + snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); + + if (line6->properties->capabilities & LINE6_CAP_CONTROL) + line6_stop_listen(line6); + + if (line6pcm != NULL) { + snd_pcm_suspend_all(line6pcm->pcm); + line6pcm->flags = 0; + } + + return 0; +} +EXPORT_SYMBOL_GPL(line6_suspend); + +/* + Resume Line 6 device. +*/ +int line6_resume(struct usb_interface *interface) +{ + struct usb_line6 *line6 = usb_get_intfdata(interface); + + if (line6->properties->capabilities & LINE6_CAP_CONTROL) + line6_start_listen(line6); + + snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); + return 0; +} +EXPORT_SYMBOL_GPL(line6_resume); + +#endif /* CONFIG_PM */ + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h new file mode 100644 index 000000000000..7da643e79e3b --- /dev/null +++ b/sound/usb/line6/driver.h @@ -0,0 +1,181 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef DRIVER_H +#define DRIVER_H + +#include <linux/spinlock.h> +#include <linux/usb.h> +#include <sound/core.h> + +#include "midi.h" + +#define USB_INTERVALS_PER_SECOND 1000 + +/* Fallback USB interval and max packet size values */ +#define LINE6_FALLBACK_INTERVAL 10 +#define LINE6_FALLBACK_MAXPACKETSIZE 16 + +#define LINE6_TIMEOUT 1 +#define LINE6_BUFSIZE_LISTEN 32 +#define LINE6_MESSAGE_MAXLEN 256 + +/* + Line 6 MIDI control commands +*/ +#define LINE6_PARAM_CHANGE 0xb0 +#define LINE6_PROGRAM_CHANGE 0xc0 +#define LINE6_SYSEX_BEGIN 0xf0 +#define LINE6_SYSEX_END 0xf7 +#define LINE6_RESET 0xff + +/* + MIDI channel for messages initiated by the host + (and eventually echoed back by the device) +*/ +#define LINE6_CHANNEL_HOST 0x00 + +/* + MIDI channel for messages initiated by the device +*/ +#define LINE6_CHANNEL_DEVICE 0x02 + +#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */ + +#define LINE6_CHANNEL_MASK 0x0f + +#define CHECK_STARTUP_PROGRESS(x, n) \ +do { \ + if ((x) >= (n)) \ + return; \ + x = (n); \ +} while (0) + +extern const unsigned char line6_midi_id[3]; + +static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3; +static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; + +/* + Common properties of Line 6 devices. +*/ +struct line6_properties { + /* Card id string (maximum 16 characters). + * This can be used to address the device in ALSA programs as + * "default:CARD=<id>" + */ + const char *id; + + /* Card short name (maximum 32 characters) */ + const char *name; + + /* Bit vector defining this device's capabilities in line6usb driver */ + int capabilities; + + int altsetting; + + unsigned ep_ctrl_r; + unsigned ep_ctrl_w; + unsigned ep_audio_r; + unsigned ep_audio_w; +}; + +/* Capability bits */ +enum { + /* device supports settings parameter via USB */ + LINE6_CAP_CONTROL = 1 << 0, + /* device supports PCM input/output via USB */ + LINE6_CAP_PCM = 1 << 1, + /* device support hardware monitoring */ + LINE6_CAP_HWMON = 1 << 2, +}; + +/* + Common data shared by all Line 6 devices. + Corresponds to a pair of USB endpoints. +*/ +struct usb_line6 { + /* USB device */ + struct usb_device *usbdev; + + /* Properties */ + const struct line6_properties *properties; + + /* Interval (ms) */ + int interval; + + /* Maximum size of USB packet */ + int max_packet_size; + + /* Device representing the USB interface */ + struct device *ifcdev; + + /* Line 6 sound card data structure. + * Each device has at least MIDI or PCM. + */ + struct snd_card *card; + + /* Line 6 PCM device data structure */ + struct snd_line6_pcm *line6pcm; + + /* Line 6 MIDI device data structure */ + struct snd_line6_midi *line6midi; + + /* URB for listening to PODxt Pro control endpoint */ + struct urb *urb_listen; + + /* Buffer for listening to PODxt Pro control endpoint */ + unsigned char *buffer_listen; + + /* Buffer for message to be processed */ + unsigned char *buffer_message; + + /* Length of message to be processed */ + int message_length; + + void (*process_message)(struct usb_line6 *); + void (*disconnect)(struct usb_line6 *line6); +}; + +extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, + int code2, int size); +extern int line6_read_data(struct usb_line6 *line6, unsigned address, + void *data, unsigned datalen); +extern int line6_read_serial_number(struct usb_line6 *line6, + u32 *serial_number); +extern int line6_send_raw_message_async(struct usb_line6 *line6, + const char *buffer, int size); +extern int line6_send_sysex_message(struct usb_line6 *line6, + const char *buffer, int size); +extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +extern void line6_start_timer(struct timer_list *timer, unsigned long msecs, + void (*function)(unsigned long), + unsigned long data); +extern int line6_version_request_async(struct usb_line6 *line6); +extern int line6_write_data(struct usb_line6 *line6, unsigned address, + void *data, unsigned datalen); + +int line6_probe(struct usb_interface *interface, + const struct usb_device_id *id, + const char *driver_name, + const struct line6_properties *properties, + int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), + size_t data_size); + +void line6_disconnect(struct usb_interface *interface); + +#ifdef CONFIG_PM +int line6_suspend(struct usb_interface *interface, pm_message_t message); +int line6_resume(struct usb_interface *interface); +#endif + +#endif diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c new file mode 100644 index 000000000000..cebea9b7f769 --- /dev/null +++ b/sound/usb/line6/midi.c @@ -0,0 +1,292 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/export.h> +#include <sound/core.h> +#include <sound/rawmidi.h> + +#include "driver.h" +#include "midi.h" + +#define line6_rawmidi_substream_midi(substream) \ + ((struct snd_line6_midi *)((substream)->rmidi->private_data)) + +static int send_midi_async(struct usb_line6 *line6, unsigned char *data, + int length); + +/* + Pass data received via USB to MIDI. +*/ +void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, + int length) +{ + if (line6->line6midi->substream_receive) + snd_rawmidi_receive(line6->line6midi->substream_receive, + data, length); +} + +/* + Read data from MIDI buffer and transmit them via USB. +*/ +static void line6_midi_transmit(struct snd_rawmidi_substream *substream) +{ + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + struct snd_line6_midi *line6midi = line6->line6midi; + struct midi_buffer *mb = &line6midi->midibuf_out; + unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE]; + int req, done; + + for (;;) { + req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); + done = snd_rawmidi_transmit_peek(substream, chunk, req); + + if (done == 0) + break; + + line6_midibuf_write(mb, chunk, done); + snd_rawmidi_transmit_ack(substream, done); + } + + for (;;) { + done = line6_midibuf_read(mb, chunk, + LINE6_FALLBACK_MAXPACKETSIZE); + + if (done == 0) + break; + + send_midi_async(line6, chunk, done); + } +} + +/* + Notification of completion of MIDI transmission. +*/ +static void midi_sent(struct urb *urb) +{ + unsigned long flags; + int status; + int num; + struct usb_line6 *line6 = (struct usb_line6 *)urb->context; + + status = urb->status; + kfree(urb->transfer_buffer); + usb_free_urb(urb); + + if (status == -ESHUTDOWN) + return; + + spin_lock_irqsave(&line6->line6midi->lock, flags); + num = --line6->line6midi->num_active_send_urbs; + + if (num == 0) { + line6_midi_transmit(line6->line6midi->substream_transmit); + num = line6->line6midi->num_active_send_urbs; + } + + if (num == 0) + wake_up(&line6->line6midi->send_wait); + + spin_unlock_irqrestore(&line6->line6midi->lock, flags); +} + +/* + Send an asynchronous MIDI message. + Assumes that line6->line6midi->lock is held + (i.e., this function is serialized). +*/ +static int send_midi_async(struct usb_line6 *line6, unsigned char *data, + int length) +{ + struct urb *urb; + int retval; + unsigned char *transfer_buffer; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + + if (urb == NULL) + return -ENOMEM; + + transfer_buffer = kmemdup(data, length, GFP_ATOMIC); + + if (transfer_buffer == NULL) { + usb_free_urb(urb); + return -ENOMEM; + } + + usb_fill_int_urb(urb, line6->usbdev, + usb_sndbulkpipe(line6->usbdev, + line6->properties->ep_ctrl_w), + transfer_buffer, length, midi_sent, line6, + line6->interval); + urb->actual_length = 0; + retval = usb_submit_urb(urb, GFP_ATOMIC); + + if (retval < 0) { + dev_err(line6->ifcdev, "usb_submit_urb failed\n"); + usb_free_urb(urb); + return retval; + } + + ++line6->line6midi->num_active_send_urbs; + return 0; +} + +static int line6_midi_output_open(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static int line6_midi_output_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + unsigned long flags; + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + + line6->line6midi->substream_transmit = substream; + spin_lock_irqsave(&line6->line6midi->lock, flags); + + if (line6->line6midi->num_active_send_urbs == 0) + line6_midi_transmit(substream); + + spin_unlock_irqrestore(&line6->line6midi->lock, flags); +} + +static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) +{ + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + struct snd_line6_midi *midi = line6->line6midi; + + wait_event_interruptible(midi->send_wait, + midi->num_active_send_urbs == 0); +} + +static int line6_midi_input_open(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static int line6_midi_input_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct usb_line6 *line6 = + line6_rawmidi_substream_midi(substream)->line6; + + if (up) + line6->line6midi->substream_receive = substream; + else + line6->line6midi->substream_receive = NULL; +} + +static struct snd_rawmidi_ops line6_midi_output_ops = { + .open = line6_midi_output_open, + .close = line6_midi_output_close, + .trigger = line6_midi_output_trigger, + .drain = line6_midi_output_drain, +}; + +static struct snd_rawmidi_ops line6_midi_input_ops = { + .open = line6_midi_input_open, + .close = line6_midi_input_close, + .trigger = line6_midi_input_trigger, +}; + +/* Create a MIDI device */ +static int snd_line6_new_midi(struct usb_line6 *line6, + struct snd_rawmidi **rmidi_ret) +{ + struct snd_rawmidi *rmidi; + int err; + + err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret); + if (err < 0) + return err; + + rmidi = *rmidi_ret; + strcpy(rmidi->id, line6->properties->id); + strcpy(rmidi->name, line6->properties->name); + + rmidi->info_flags = + SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; + + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &line6_midi_output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &line6_midi_input_ops); + return 0; +} + +/* MIDI device destructor */ +static void snd_line6_midi_free(struct snd_rawmidi *rmidi) +{ + struct snd_line6_midi *line6midi = rmidi->private_data; + + line6_midibuf_destroy(&line6midi->midibuf_in); + line6_midibuf_destroy(&line6midi->midibuf_out); + kfree(line6midi); +} + +/* + Initialize the Line 6 MIDI subsystem. +*/ +int line6_init_midi(struct usb_line6 *line6) +{ + int err; + struct snd_rawmidi *rmidi; + struct snd_line6_midi *line6midi; + + if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { + /* skip MIDI initialization and report success */ + return 0; + } + + err = snd_line6_new_midi(line6, &rmidi); + if (err < 0) + return err; + + line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); + if (!line6midi) + return -ENOMEM; + + rmidi->private_data = line6midi; + rmidi->private_free = snd_line6_midi_free; + + init_waitqueue_head(&line6midi->send_wait); + spin_lock_init(&line6midi->lock); + line6midi->line6 = line6; + + err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); + if (err < 0) + return err; + + err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); + if (err < 0) + return err; + + line6->line6midi = line6midi; + return 0; +} +EXPORT_SYMBOL_GPL(line6_init_midi); diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h new file mode 100644 index 000000000000..cf82d69e2747 --- /dev/null +++ b/sound/usb/line6/midi.h @@ -0,0 +1,51 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef MIDI_H +#define MIDI_H + +#include <sound/rawmidi.h> + +#include "midibuf.h" + +#define MIDI_BUFFER_SIZE 1024 + +struct snd_line6_midi { + /* Pointer back to the Line 6 driver data structure */ + struct usb_line6 *line6; + + /* MIDI substream for receiving (or NULL if not active) */ + struct snd_rawmidi_substream *substream_receive; + + /* MIDI substream for transmitting (or NULL if not active) */ + struct snd_rawmidi_substream *substream_transmit; + + /* Number of currently active MIDI send URBs */ + int num_active_send_urbs; + + /* Spin lock to protect MIDI buffer handling */ + spinlock_t lock; + + /* Wait queue for MIDI transmission */ + wait_queue_head_t send_wait; + + /* Buffer for incoming MIDI stream */ + struct midi_buffer midibuf_in; + + /* Buffer for outgoing MIDI stream */ + struct midi_buffer midibuf_out; +}; + +extern int line6_init_midi(struct usb_line6 *line6); +extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, + int length); + +#endif diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c new file mode 100644 index 000000000000..36a610ba342e --- /dev/null +++ b/sound/usb/line6/midibuf.c @@ -0,0 +1,252 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/slab.h> + +#include "midibuf.h" + +static int midibuf_message_length(unsigned char code) +{ + int message_length; + + if (code < 0x80) + message_length = -1; + else if (code < 0xf0) { + static const int length[] = { 3, 3, 3, 3, 2, 2, 3 }; + + message_length = length[(code >> 4) - 8]; + } else { + /* + Note that according to the MIDI specification 0xf2 is + the "Song Position Pointer", but this is used by Line 6 + to send sysex messages to the host. + */ + static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1, + 1, 1, 1, -1, 1, 1 + }; + message_length = length[code & 0x0f]; + } + + return message_length; +} + +static int midibuf_is_empty(struct midi_buffer *this) +{ + return (this->pos_read == this->pos_write) && !this->full; +} + +static int midibuf_is_full(struct midi_buffer *this) +{ + return this->full; +} + +void line6_midibuf_reset(struct midi_buffer *this) +{ + this->pos_read = this->pos_write = this->full = 0; + this->command_prev = -1; +} + +int line6_midibuf_init(struct midi_buffer *this, int size, int split) +{ + this->buf = kmalloc(size, GFP_KERNEL); + + if (this->buf == NULL) + return -ENOMEM; + + this->size = size; + this->split = split; + line6_midibuf_reset(this); + return 0; +} + +int line6_midibuf_bytes_free(struct midi_buffer *this) +{ + return + midibuf_is_full(this) ? + 0 : + (this->pos_read - this->pos_write + this->size - 1) % this->size + + 1; +} + +int line6_midibuf_bytes_used(struct midi_buffer *this) +{ + return + midibuf_is_empty(this) ? + 0 : + (this->pos_write - this->pos_read + this->size - 1) % this->size + + 1; +} + +int line6_midibuf_write(struct midi_buffer *this, unsigned char *data, + int length) +{ + int bytes_free; + int length1, length2; + int skip_active_sense = 0; + + if (midibuf_is_full(this) || (length <= 0)) + return 0; + + /* skip trailing active sense */ + if (data[length - 1] == 0xfe) { + --length; + skip_active_sense = 1; + } + + bytes_free = line6_midibuf_bytes_free(this); + + if (length > bytes_free) + length = bytes_free; + + if (length > 0) { + length1 = this->size - this->pos_write; + + if (length < length1) { + /* no buffer wraparound */ + memcpy(this->buf + this->pos_write, data, length); + this->pos_write += length; + } else { + /* buffer wraparound */ + length2 = length - length1; + memcpy(this->buf + this->pos_write, data, length1); + memcpy(this->buf, data + length1, length2); + this->pos_write = length2; + } + + if (this->pos_write == this->pos_read) + this->full = 1; + } + + return length + skip_active_sense; +} + +int line6_midibuf_read(struct midi_buffer *this, unsigned char *data, + int length) +{ + int bytes_used; + int length1, length2; + int command; + int midi_length; + int repeat = 0; + int i; + + /* we need to be able to store at least a 3 byte MIDI message */ + if (length < 3) + return -EINVAL; + + if (midibuf_is_empty(this)) + return 0; + + bytes_used = line6_midibuf_bytes_used(this); + + if (length > bytes_used) + length = bytes_used; + + length1 = this->size - this->pos_read; + + /* check MIDI command length */ + command = this->buf[this->pos_read]; + + if (command & 0x80) { + midi_length = midibuf_message_length(command); + this->command_prev = command; + } else { + if (this->command_prev > 0) { + int midi_length_prev = + midibuf_message_length(this->command_prev); + + if (midi_length_prev > 0) { + midi_length = midi_length_prev - 1; + repeat = 1; + } else + midi_length = -1; + } else + midi_length = -1; + } + + if (midi_length < 0) { + /* search for end of message */ + if (length < length1) { + /* no buffer wraparound */ + for (i = 1; i < length; ++i) + if (this->buf[this->pos_read + i] & 0x80) + break; + + midi_length = i; + } else { + /* buffer wraparound */ + length2 = length - length1; + + for (i = 1; i < length1; ++i) + if (this->buf[this->pos_read + i] & 0x80) + break; + + if (i < length1) + midi_length = i; + else { + for (i = 0; i < length2; ++i) + if (this->buf[i] & 0x80) + break; + + midi_length = length1 + i; + } + } + + if (midi_length == length) + midi_length = -1; /* end of message not found */ + } + + if (midi_length < 0) { + if (!this->split) + return 0; /* command is not yet complete */ + } else { + if (length < midi_length) + return 0; /* command is not yet complete */ + + length = midi_length; + } + + if (length < length1) { + /* no buffer wraparound */ + memcpy(data + repeat, this->buf + this->pos_read, length); + this->pos_read += length; + } else { + /* buffer wraparound */ + length2 = length - length1; + memcpy(data + repeat, this->buf + this->pos_read, length1); + memcpy(data + repeat + length1, this->buf, length2); + this->pos_read = length2; + } + + if (repeat) + data[0] = this->command_prev; + + this->full = 0; + return length + repeat; +} + +int line6_midibuf_ignore(struct midi_buffer *this, int length) +{ + int bytes_used = line6_midibuf_bytes_used(this); + + if (length > bytes_used) + length = bytes_used; + + this->pos_read = (this->pos_read + length) % this->size; + this->full = 0; + return length; +} + +void line6_midibuf_destroy(struct midi_buffer *this) +{ + kfree(this->buf); + this->buf = NULL; +} diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h new file mode 100644 index 000000000000..6ea21ffb6627 --- /dev/null +++ b/sound/usb/line6/midibuf.h @@ -0,0 +1,35 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef MIDIBUF_H +#define MIDIBUF_H + +struct midi_buffer { + unsigned char *buf; + int size; + int split; + int pos_read, pos_write; + int full; + int command_prev; +}; + +extern int line6_midibuf_bytes_used(struct midi_buffer *mb); +extern int line6_midibuf_bytes_free(struct midi_buffer *mb); +extern void line6_midibuf_destroy(struct midi_buffer *mb); +extern int line6_midibuf_ignore(struct midi_buffer *mb, int length); +extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split); +extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data, + int length); +extern void line6_midibuf_reset(struct midi_buffer *mb); +extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data, + int length); + +#endif diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c new file mode 100644 index 000000000000..8461d6bf992f --- /dev/null +++ b/sound/usb/line6/pcm.c @@ -0,0 +1,588 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/slab.h> +#include <linux/export.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> + +#include "capture.h" +#include "driver.h" +#include "playback.h" + +/* impulse response volume controls */ +static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + return 0; +} + +static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = line6pcm->impulse_volume; + return 0; +} + +static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + int value = ucontrol->value.integer.value[0]; + int err; + + if (line6pcm->impulse_volume == value) + return 0; + + line6pcm->impulse_volume = value; + if (value > 0) { + err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); + if (err < 0) { + line6pcm->impulse_volume = 0; + line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); + return err; + } + } else { + line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); + } + return 1; +} + +/* impulse response period controls */ +static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 2000; + return 0; +} + +static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = line6pcm->impulse_period; + return 0; +} + +static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + int value = ucontrol->value.integer.value[0]; + + if (line6pcm->impulse_period == value) + return 0; + + line6pcm->impulse_period = value; + return 1; +} + +/* + Unlink all currently active URBs. +*/ +static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pcms) +{ + int i; + + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { + if (test_bit(i, &pcms->active_urbs)) { + if (!test_and_set_bit(i, &pcms->unlink_urbs)) + usb_unlink_urb(pcms->urbs[i]); + } + } +} + +/* + Wait until unlinking of all currently active URBs has been finished. +*/ +static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pcms) +{ + int timeout = HZ; + int i; + int alive; + + do { + alive = 0; + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { + if (test_bit(i, &pcms->active_urbs)) + alive++; + } + if (!alive) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } while (--timeout > 0); + if (alive) + dev_err(line6pcm->line6->ifcdev, + "timeout: still %d active urbs..\n", alive); +} + +static inline struct line6_pcm_stream * +get_stream(struct snd_line6_pcm *line6pcm, int direction) +{ + return (direction == SNDRV_PCM_STREAM_PLAYBACK) ? + &line6pcm->out : &line6pcm->in; +} + +/* allocate a buffer if not opened yet; + * call this in line6pcm.state_change mutex + */ +static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pstr, int type) +{ + /* Invoked multiple times in a row so allocate once only */ + if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) { + pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + if (!pstr->buffer) + return -ENOMEM; + } + return 0; +} + +/* free a buffer if all streams are closed; + * call this in line6pcm.state_change mutex + */ +static void line6_buffer_release(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pstr, int type) +{ + + clear_bit(type, &pstr->opened); + if (!pstr->opened) { + line6_wait_clear_audio_urbs(line6pcm, pstr); + kfree(pstr->buffer); + pstr->buffer = NULL; + } +} + +/* start a PCM stream */ +static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, + int type) +{ + unsigned long flags; + struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); + int ret = 0; + + spin_lock_irqsave(&pstr->lock, flags); + if (!test_and_set_bit(type, &pstr->running)) { + if (pstr->active_urbs || pstr->unlink_urbs) { + ret = -EBUSY; + goto error; + } + + pstr->count = 0; + /* Submit all currently available URBs */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + ret = line6_submit_audio_out_all_urbs(line6pcm); + else + ret = line6_submit_audio_in_all_urbs(line6pcm); + } + error: + if (ret < 0) + clear_bit(type, &pstr->running); + spin_unlock_irqrestore(&pstr->lock, flags); + return ret; +} + +/* stop a PCM stream; this doesn't sync with the unlinked URBs */ +static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, + int type) +{ + unsigned long flags; + struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); + + spin_lock_irqsave(&pstr->lock, flags); + clear_bit(type, &pstr->running); + if (!pstr->running) { + line6_unlink_audio_urbs(line6pcm, pstr); + if (direction == SNDRV_PCM_STREAM_CAPTURE) { + line6pcm->prev_fbuf = NULL; + line6pcm->prev_fsize = 0; + } + } + spin_unlock_irqrestore(&pstr->lock, flags); +} + +/* common PCM trigger callback */ +int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct snd_pcm_substream *s; + int err; + + clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags); + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + err = line6_stream_start(line6pcm, s->stream, + LINE6_STREAM_PCM); + if (err < 0) + return err; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + line6_stream_stop(line6pcm, s->stream, + LINE6_STREAM_PCM); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) + return -EINVAL; + set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) + return -EINVAL; + clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); + break; + + default: + return -EINVAL; + } + } + + return 0; +} + +/* common PCM pointer callback */ +snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); + + return pstr->pos_done; +} + +/* Acquire and start duplex streams: + * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR + */ +int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type) +{ + struct line6_pcm_stream *pstr; + int ret = 0, dir; + + mutex_lock(&line6pcm->state_mutex); + for (dir = 0; dir < 2; dir++) { + pstr = get_stream(line6pcm, dir); + ret = line6_buffer_acquire(line6pcm, pstr, type); + if (ret < 0) + goto error; + if (!pstr->running) + line6_wait_clear_audio_urbs(line6pcm, pstr); + } + for (dir = 0; dir < 2; dir++) { + ret = line6_stream_start(line6pcm, dir, type); + if (ret < 0) + goto error; + } + error: + mutex_unlock(&line6pcm->state_mutex); + if (ret < 0) + line6_pcm_release(line6pcm, type); + return ret; +} +EXPORT_SYMBOL_GPL(line6_pcm_acquire); + +/* Stop and release duplex streams */ +void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) +{ + struct line6_pcm_stream *pstr; + int dir; + + mutex_lock(&line6pcm->state_mutex); + for (dir = 0; dir < 2; dir++) + line6_stream_stop(line6pcm, dir, type); + for (dir = 0; dir < 2; dir++) { + pstr = get_stream(line6pcm, dir); + line6_buffer_release(line6pcm, pstr, type); + } + mutex_unlock(&line6pcm->state_mutex); +} +EXPORT_SYMBOL_GPL(line6_pcm_release); + +/* common PCM hw_params callback */ +int snd_line6_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + int ret; + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); + + mutex_lock(&line6pcm->state_mutex); + ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM); + if (ret < 0) + goto error; + + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (ret < 0) { + line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); + goto error; + } + + pstr->period = params_period_bytes(hw_params); + error: + mutex_unlock(&line6pcm->state_mutex); + return ret; +} + +/* common PCM hw_free callback */ +int snd_line6_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); + + mutex_lock(&line6pcm->state_mutex); + line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); + mutex_unlock(&line6pcm->state_mutex); + return snd_pcm_lib_free_pages(substream); +} + + +/* control info callback */ +static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 256; + return 0; +} + +/* control get callback */ +static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i; + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + for (i = 0; i < 2; i++) + ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; + + return 0; +} + +/* control put callback */ +static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i, changed = 0; + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + for (i = 0; i < 2; i++) + if (line6pcm->volume_playback[i] != + ucontrol->value.integer.value[i]) { + line6pcm->volume_playback[i] = + ucontrol->value.integer.value[i]; + changed = 1; + } + + return changed; +} + +/* control definition */ +static struct snd_kcontrol_new line6_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = snd_line6_control_playback_info, + .get = snd_line6_control_playback_get, + .put = snd_line6_control_playback_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Impulse Response Volume", + .info = snd_line6_impulse_volume_info, + .get = snd_line6_impulse_volume_get, + .put = snd_line6_impulse_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Impulse Response Period", + .info = snd_line6_impulse_period_info, + .get = snd_line6_impulse_period_get, + .put = snd_line6_impulse_period_put + }, +}; + +/* + Cleanup the PCM device. +*/ +static void cleanup_urbs(struct line6_pcm_stream *pcms) +{ + int i; + + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { + if (pcms->urbs[i]) { + usb_kill_urb(pcms->urbs[i]); + usb_free_urb(pcms->urbs[i]); + } + } +} + +static void line6_cleanup_pcm(struct snd_pcm *pcm) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); + + cleanup_urbs(&line6pcm->out); + cleanup_urbs(&line6pcm->in); + kfree(line6pcm); +} + +/* create a PCM device */ +static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) +{ + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(line6->card, (char *)line6->properties->name, + 0, 1, 1, pcm_ret); + if (err < 0) + return err; + pcm = *pcm_ret; + strcpy(pcm->name, line6->properties->name); + + /* set operators */ + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_line6_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); + + /* pre-allocation of buffers */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data + (GFP_KERNEL), 64 * 1024, + 128 * 1024); + return 0; +} + +/* + Sync with PCM stream stops. +*/ +void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) +{ + line6_unlink_audio_urbs(line6pcm, &line6pcm->out); + line6_unlink_audio_urbs(line6pcm, &line6pcm->in); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); +} + +/* + Create and register the PCM device and mixer entries. + Create URBs for playback and capture. +*/ +int line6_init_pcm(struct usb_line6 *line6, + struct line6_pcm_properties *properties) +{ + int i, err; + unsigned ep_read = line6->properties->ep_audio_r; + unsigned ep_write = line6->properties->ep_audio_w; + struct snd_pcm *pcm; + struct snd_line6_pcm *line6pcm; + + if (!(line6->properties->capabilities & LINE6_CAP_PCM)) + return 0; /* skip PCM initialization and report success */ + + err = snd_line6_new_pcm(line6, &pcm); + if (err < 0) + return err; + + line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); + if (!line6pcm) + return -ENOMEM; + + mutex_init(&line6pcm->state_mutex); + line6pcm->pcm = pcm; + line6pcm->properties = properties; + line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; + line6pcm->volume_monitor = 255; + line6pcm->line6 = line6; + + /* Read and write buffers are sized identically, so choose minimum */ + line6pcm->max_packet_size = min( + usb_maxpacket(line6->usbdev, + usb_rcvisocpipe(line6->usbdev, ep_read), 0), + usb_maxpacket(line6->usbdev, + usb_sndisocpipe(line6->usbdev, ep_write), 1)); + + spin_lock_init(&line6pcm->out.lock); + spin_lock_init(&line6pcm->in.lock); + line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; + + line6->line6pcm = line6pcm; + + pcm->private_data = line6pcm; + pcm->private_free = line6_cleanup_pcm; + + err = line6_create_audio_out_urbs(line6pcm); + if (err < 0) + return err; + + err = line6_create_audio_in_urbs(line6pcm); + if (err < 0) + return err; + + /* mixer: */ + for (i = 0; i < ARRAY_SIZE(line6_controls); i++) { + err = snd_ctl_add(line6->card, + snd_ctl_new1(&line6_controls[i], line6pcm)); + if (err < 0) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(line6_init_pcm); + +/* prepare pcm callback */ +int snd_line6_prepare(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); + + mutex_lock(&line6pcm->state_mutex); + if (!pstr->running) + line6_wait_clear_audio_urbs(line6pcm, pstr); + + if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) { + line6pcm->out.count = 0; + line6pcm->out.pos = 0; + line6pcm->out.pos_done = 0; + line6pcm->out.bytes = 0; + line6pcm->in.count = 0; + line6pcm->in.pos_done = 0; + line6pcm->in.bytes = 0; + } + + mutex_unlock(&line6pcm->state_mutex); + return 0; +} diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h new file mode 100644 index 000000000000..508410adbd51 --- /dev/null +++ b/sound/usb/line6/pcm.h @@ -0,0 +1,197 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +/* + PCM interface to POD series devices. +*/ + +#ifndef PCM_H +#define PCM_H + +#include <sound/pcm.h> + +#include "driver.h" + +/* number of URBs */ +#define LINE6_ISO_BUFFERS 2 + +/* + number of USB frames per URB + The Line 6 Windows driver always transmits two frames per packet, but + the Linux driver performs significantly better (i.e., lower latency) + with only one frame per packet. +*/ +#define LINE6_ISO_PACKETS 1 + +/* in a "full speed" device (such as the PODxt Pro) this means 1ms */ +#define LINE6_ISO_INTERVAL 1 + +#define LINE6_IMPULSE_DEFAULT_PERIOD 100 + +/* + Get substream from Line 6 PCM data structure +*/ +#define get_substream(line6pcm, stream) \ + (line6pcm->pcm->streams[stream].substream) + +/* + PCM mode bits. + + There are several features of the Line 6 USB driver which require PCM + data to be exchanged with the device: + *) PCM playback and capture via ALSA + *) software monitoring (for devices without hardware monitoring) + *) optional impulse response measurement + However, from the device's point of view, there is just a single + capture and playback stream, which must be shared between these + subsystems. It is therefore necessary to maintain the state of the + subsystems with respect to PCM usage. + + We define two bit flags, "opened" and "running", for each playback + or capture stream. Both can contain the bit flag corresponding to + LINE6_STREAM_* type, + LINE6_STREAM_PCM = ALSA PCM playback or capture + LINE6_STREAM_MONITOR = software monitoring + IMPULSE = optional impulse response measurement + The opened flag indicates whether the buffer is allocated while + the running flag indicates whether the stream is running. + + For monitor or impulse operations, the driver needs to call + line6_pcm_acquire() or line6_pcm_release() with the appropriate + LINE6_STREAM_* flag. +*/ + +/* stream types */ +enum { + LINE6_STREAM_PCM, + LINE6_STREAM_MONITOR, + LINE6_STREAM_IMPULSE, +}; + +/* misc bit flags for PCM operation */ +enum { + LINE6_FLAG_PAUSE_PLAYBACK, + LINE6_FLAG_PREPARED, +}; + +struct line6_pcm_properties { + struct snd_pcm_hardware playback_hw, capture_hw; + struct snd_pcm_hw_constraint_ratdens rates; + int bytes_per_frame; +}; + +struct line6_pcm_stream { + /* allocated URBs */ + struct urb *urbs[LINE6_ISO_BUFFERS]; + + /* Temporary buffer; + * Since the packet size is not known in advance, this buffer is + * large enough to store maximum size packets. + */ + unsigned char *buffer; + + /* Free frame position in the buffer. */ + snd_pcm_uframes_t pos; + + /* Count processed bytes; + * This is modulo period size (to determine when a period is finished). + */ + unsigned bytes; + + /* Counter to create desired sample rate */ + unsigned count; + + /* period size in bytes */ + unsigned period; + + /* Processed frame position in the buffer; + * The contents of the ring buffer have been consumed by the USB + * subsystem (i.e., sent to the USB device) up to this position. + */ + snd_pcm_uframes_t pos_done; + + /* Bit mask of active URBs */ + unsigned long active_urbs; + + /* Bit mask of URBs currently being unlinked */ + unsigned long unlink_urbs; + + /* Spin lock to protect updates of the buffer positions (not contents) + */ + spinlock_t lock; + + /* Bit flags for operational stream types */ + unsigned long opened; + + /* Bit flags for running stream types */ + unsigned long running; + + int last_frame; +}; + +struct snd_line6_pcm { + /* Pointer back to the Line 6 driver data structure */ + struct usb_line6 *line6; + + /* Properties. */ + struct line6_pcm_properties *properties; + + /* ALSA pcm stream */ + struct snd_pcm *pcm; + + /* protection to state changes of in/out streams */ + struct mutex state_mutex; + + /* Capture and playback streams */ + struct line6_pcm_stream in; + struct line6_pcm_stream out; + + /* Previously captured frame (for software monitoring) */ + unsigned char *prev_fbuf; + + /* Size of previously captured frame (for software monitoring) */ + int prev_fsize; + + /* Maximum size of USB packet */ + int max_packet_size; + + /* PCM playback volume (left and right) */ + int volume_playback[2]; + + /* PCM monitor volume */ + int volume_monitor; + + /* Volume of impulse response test signal (if zero, test is disabled) */ + int impulse_volume; + + /* Period of impulse response test signal */ + int impulse_period; + + /* Counter for impulse response test signal */ + int impulse_count; + + /* Several status bits (see LINE6_FLAG_*) */ + unsigned long flags; +}; + +extern int line6_init_pcm(struct usb_line6 *line6, + struct line6_pcm_properties *properties); +extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); +extern int snd_line6_prepare(struct snd_pcm_substream *substream); +extern int snd_line6_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params); +extern int snd_line6_hw_free(struct snd_pcm_substream *substream); +extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream); +extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); +extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type); +extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type); + +#endif diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c new file mode 100644 index 000000000000..05dee690f487 --- /dev/null +++ b/sound/usb/line6/playback.c @@ -0,0 +1,429 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> + +#include "capture.h" +#include "driver.h" +#include "pcm.h" +#include "playback.h" + +/* + Software stereo volume control. +*/ +static void change_volume(struct urb *urb_out, int volume[], + int bytes_per_frame) +{ + int chn = 0; + + if (volume[0] == 256 && volume[1] == 256) + return; /* maximum volume - no change */ + + if (bytes_per_frame == 4) { + __le16 *p, *buf_end; + + p = (__le16 *)urb_out->transfer_buffer; + buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); + + for (; p < buf_end; ++p) { + short pv = le16_to_cpu(*p); + int val = (pv * volume[chn & 1]) >> 8; + pv = clamp(val, 0x7fff, -0x8000); + *p = cpu_to_le16(pv); + ++chn; + } + } else if (bytes_per_frame == 6) { + unsigned char *p, *buf_end; + + p = (unsigned char *)urb_out->transfer_buffer; + buf_end = p + urb_out->transfer_buffer_length; + + for (; p < buf_end; p += 3) { + int val; + + val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); + val = (val * volume[chn & 1]) >> 8; + val = clamp(val, 0x7fffff, -0x800000); + p[0] = val; + p[1] = val >> 8; + p[2] = val >> 16; + ++chn; + } + } +} + +/* + Create signal for impulse response test. +*/ +static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, + struct urb *urb_out, int bytes_per_frame) +{ + int frames = urb_out->transfer_buffer_length / bytes_per_frame; + + if (bytes_per_frame == 4) { + int i; + short *pi = (short *)line6pcm->prev_fbuf; + short *po = (short *)urb_out->transfer_buffer; + + for (i = 0; i < frames; ++i) { + po[0] = pi[0]; + po[1] = 0; + pi += 2; + po += 2; + } + } else if (bytes_per_frame == 6) { + int i, j; + unsigned char *pi = line6pcm->prev_fbuf; + unsigned char *po = urb_out->transfer_buffer; + + for (i = 0; i < frames; ++i) { + for (j = 0; j < bytes_per_frame / 2; ++j) + po[j] = pi[j]; + + for (; j < bytes_per_frame; ++j) + po[j] = 0; + + pi += bytes_per_frame; + po += bytes_per_frame; + } + } + if (--line6pcm->impulse_count <= 0) { + ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame - + 1] = + line6pcm->impulse_volume; + line6pcm->impulse_count = line6pcm->impulse_period; + } +} + +/* + Add signal to buffer for software monitoring. +*/ +static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, + int volume, int bytes_per_frame) +{ + if (volume == 0) + return; /* zero volume - no change */ + + if (bytes_per_frame == 4) { + __le16 *pi, *po, *buf_end; + + pi = (__le16 *)signal; + po = (__le16 *)urb_out->transfer_buffer; + buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); + + for (; po < buf_end; ++pi, ++po) { + short pov = le16_to_cpu(*po); + short piv = le16_to_cpu(*pi); + int val = pov + ((piv * volume) >> 8); + pov = clamp(val, 0x7fff, -0x8000); + *po = cpu_to_le16(pov); + } + } + + /* + We don't need to handle devices with 6 bytes per frame here + since they all support hardware monitoring. + */ +} + +/* + Find a free URB, prepare audio data, and submit URB. + must be called in line6pcm->out.lock context +*/ +static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) +{ + int index; + int i, urb_size, urb_frames; + int ret; + const int bytes_per_frame = line6pcm->properties->bytes_per_frame; + const int frame_increment = + line6pcm->properties->rates.rats[0].num_min; + const int frame_factor = + line6pcm->properties->rates.rats[0].den * + (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); + struct urb *urb_out; + + index = + find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS); + + if (index < 0 || index >= LINE6_ISO_BUFFERS) { + dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); + return -EINVAL; + } + + urb_out = line6pcm->out.urbs[index]; + urb_size = 0; + + for (i = 0; i < LINE6_ISO_PACKETS; ++i) { + /* compute frame size for given sampling rate */ + int fsize = 0; + struct usb_iso_packet_descriptor *fout = + &urb_out->iso_frame_desc[i]; + + fsize = line6pcm->prev_fsize; + if (fsize == 0) { + int n; + + line6pcm->out.count += frame_increment; + n = line6pcm->out.count / frame_factor; + line6pcm->out.count -= n * frame_factor; + fsize = n * bytes_per_frame; + } + + fout->offset = urb_size; + fout->length = fsize; + urb_size += fsize; + } + + if (urb_size == 0) { + /* can't determine URB size */ + dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); + return -EINVAL; + } + + urb_frames = urb_size / bytes_per_frame; + urb_out->transfer_buffer = + line6pcm->out.buffer + + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; + urb_out->transfer_buffer_length = urb_size; + urb_out->context = line6pcm; + + if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running) && + !test_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags)) { + struct snd_pcm_runtime *runtime = + get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; + + if (line6pcm->out.pos + urb_frames > runtime->buffer_size) { + /* + The transferred area goes over buffer boundary, + copy the data to the temp buffer. + */ + int len; + + len = runtime->buffer_size - line6pcm->out.pos; + + if (len > 0) { + memcpy(urb_out->transfer_buffer, + runtime->dma_area + + line6pcm->out.pos * bytes_per_frame, + len * bytes_per_frame); + memcpy(urb_out->transfer_buffer + + len * bytes_per_frame, runtime->dma_area, + (urb_frames - len) * bytes_per_frame); + } else + dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", + len); + } else { + memcpy(urb_out->transfer_buffer, + runtime->dma_area + + line6pcm->out.pos * bytes_per_frame, + urb_out->transfer_buffer_length); + } + + line6pcm->out.pos += urb_frames; + if (line6pcm->out.pos >= runtime->buffer_size) + line6pcm->out.pos -= runtime->buffer_size; + + change_volume(urb_out, line6pcm->volume_playback, + bytes_per_frame); + } else { + memset(urb_out->transfer_buffer, 0, + urb_out->transfer_buffer_length); + } + + spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING); + if (line6pcm->prev_fbuf) { + if (test_bit(LINE6_STREAM_IMPULSE, &line6pcm->out.running)) { + create_impulse_test_signal(line6pcm, urb_out, + bytes_per_frame); + if (test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) { + line6_capture_copy(line6pcm, + urb_out->transfer_buffer, + urb_out-> + transfer_buffer_length); + line6_capture_check_period(line6pcm, + urb_out->transfer_buffer_length); + } + } else { + if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON) + && line6pcm->out.running && line6pcm->in.running) + add_monitor_signal(urb_out, line6pcm->prev_fbuf, + line6pcm->volume_monitor, + bytes_per_frame); + } + line6pcm->prev_fbuf = NULL; + line6pcm->prev_fsize = 0; + } + spin_unlock(&line6pcm->in.lock); + + ret = usb_submit_urb(urb_out, GFP_ATOMIC); + + if (ret == 0) + set_bit(index, &line6pcm->out.active_urbs); + else + dev_err(line6pcm->line6->ifcdev, + "URB out #%d submission failed (%d)\n", index, ret); + + return 0; +} + +/* + Submit all currently available playback URBs. + must be called in line6pcm->out.lock context + */ +int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) +{ + int ret = 0, i; + + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + ret = submit_audio_out_urb(line6pcm); + if (ret < 0) + break; + } + + return ret; +} + +/* + Callback for completed playback URB. +*/ +static void audio_out_callback(struct urb *urb) +{ + int i, index, length = 0, shutdown = 0; + unsigned long flags; + struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; + struct snd_pcm_substream *substream = + get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK); + +#if USE_CLEAR_BUFFER_WORKAROUND + memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); +#endif + + line6pcm->out.last_frame = urb->start_frame; + + /* find index of URB */ + for (index = 0; index < LINE6_ISO_BUFFERS; index++) + if (urb == line6pcm->out.urbs[index]) + break; + + if (index >= LINE6_ISO_BUFFERS) + return; /* URB has been unlinked asynchronously */ + + for (i = 0; i < LINE6_ISO_PACKETS; i++) + length += urb->iso_frame_desc[i].length; + + spin_lock_irqsave(&line6pcm->out.lock, flags); + + if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { + struct snd_pcm_runtime *runtime = substream->runtime; + + line6pcm->out.pos_done += + length / line6pcm->properties->bytes_per_frame; + + if (line6pcm->out.pos_done >= runtime->buffer_size) + line6pcm->out.pos_done -= runtime->buffer_size; + } + + clear_bit(index, &line6pcm->out.active_urbs); + + for (i = 0; i < LINE6_ISO_PACKETS; i++) + if (urb->iso_frame_desc[i].status == -EXDEV) { + shutdown = 1; + break; + } + + if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs)) + shutdown = 1; + + if (!shutdown) { + submit_audio_out_urb(line6pcm); + + if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { + line6pcm->out.bytes += length; + if (line6pcm->out.bytes >= line6pcm->out.period) { + line6pcm->out.bytes %= line6pcm->out.period; + spin_unlock(&line6pcm->out.lock); + snd_pcm_period_elapsed(substream); + spin_lock(&line6pcm->out.lock); + } + } + } + spin_unlock_irqrestore(&line6pcm->out.lock, flags); +} + +/* open playback callback */ +static int snd_line6_playback_open(struct snd_pcm_substream *substream) +{ + int err; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &line6pcm->properties->rates); + if (err < 0) + return err; + + runtime->hw = line6pcm->properties->playback_hw; + return 0; +} + +/* close playback callback */ +static int snd_line6_playback_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* playback operators */ +struct snd_pcm_ops snd_line6_playback_ops = { + .open = snd_line6_playback_open, + .close = snd_line6_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_line6_hw_params, + .hw_free = snd_line6_hw_free, + .prepare = snd_line6_prepare, + .trigger = snd_line6_trigger, + .pointer = snd_line6_pointer, +}; + +int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) +{ + struct usb_line6 *line6 = line6pcm->line6; + int i; + + /* create audio URBs and fill in constant values: */ + for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { + struct urb *urb; + + /* URB for audio out: */ + urb = line6pcm->out.urbs[i] = + usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); + + if (urb == NULL) + return -ENOMEM; + + urb->dev = line6->usbdev; + urb->pipe = + usb_sndisocpipe(line6->usbdev, + line6->properties->ep_audio_w & + USB_ENDPOINT_NUMBER_MASK); + urb->transfer_flags = URB_ISO_ASAP; + urb->start_frame = -1; + urb->number_of_packets = LINE6_ISO_PACKETS; + urb->interval = LINE6_ISO_INTERVAL; + urb->error_count = 0; + urb->complete = audio_out_callback; + } + + return 0; +} diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h new file mode 100644 index 000000000000..51fce29e8726 --- /dev/null +++ b/sound/usb/line6/playback.h @@ -0,0 +1,35 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef PLAYBACK_H +#define PLAYBACK_H + +#include <sound/pcm.h> + +#include "driver.h" + +/* + * When the TonePort is used with jack in full duplex mode and the outputs are + * not connected, the software monitor produces an ugly noise since everything + * written to the output buffer (i.e., the input signal) will be repeated in + * the next period (sounds like a delay effect). As a workaround, the output + * buffer is cleared after the data have been read, but there must be a better + * solution. Until one is found, this workaround can be used to fix the + * problem. + */ +#define USE_CLEAR_BUFFER_WORKAROUND 1 + +extern struct snd_pcm_ops snd_line6_playback_ops; + +extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); +extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); + +#endif diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c new file mode 100644 index 000000000000..daf81d169a42 --- /dev/null +++ b/sound/usb/line6/pod.c @@ -0,0 +1,584 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/slab.h> +#include <linux/wait.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/usb.h> + +#include <sound/core.h> +#include <sound/control.h> + +#include "capture.h" +#include "driver.h" +#include "playback.h" + +/* + Locate name in binary program dump +*/ +#define POD_NAME_OFFSET 0 +#define POD_NAME_LENGTH 16 + +/* + Other constants +*/ +#define POD_CONTROL_SIZE 0x80 +#define POD_BUFSIZE_DUMPREQ 7 +#define POD_STARTUP_DELAY 1000 + +/* + Stages of POD startup procedure +*/ +enum { + POD_STARTUP_INIT = 1, + POD_STARTUP_VERSIONREQ, + POD_STARTUP_WORKQUEUE, + POD_STARTUP_SETUP, + POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 +}; + +enum { + LINE6_BASSPODXT, + LINE6_BASSPODXTLIVE, + LINE6_BASSPODXTPRO, + LINE6_POCKETPOD, + LINE6_PODXT, + LINE6_PODXTLIVE_POD, + LINE6_PODXTPRO, +}; + +struct usb_line6_pod { + /* Generic Line 6 USB data */ + struct usb_line6 line6; + + /* Instrument monitor level */ + int monitor_level; + + /* Timer for device initialization */ + struct timer_list startup_timer; + + /* Work handler for device initialization */ + struct work_struct startup_work; + + /* Current progress in startup procedure */ + int startup_progress; + + /* Serial number of device */ + u32 serial_number; + + /* Firmware version (x 100) */ + int firmware_version; + + /* Device ID */ + int device_id; +}; + +#define POD_SYSEX_CODE 3 +#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ + +/* *INDENT-OFF* */ + +enum { + POD_SYSEX_SAVE = 0x24, + POD_SYSEX_SYSTEM = 0x56, + POD_SYSEX_SYSTEMREQ = 0x57, + /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */ + POD_SYSEX_STORE = 0x71, + POD_SYSEX_FINISH = 0x72, + POD_SYSEX_DUMPMEM = 0x73, + POD_SYSEX_DUMP = 0x74, + POD_SYSEX_DUMPREQ = 0x75 + + /* dumps entire internal memory of PODxt Pro */ + /* POD_SYSEX_DUMPMEM2 = 0x76 */ +}; + +enum { + POD_MONITOR_LEVEL = 0x04, + POD_SYSTEM_INVALID = 0x10000 +}; + +/* *INDENT-ON* */ + +enum { + POD_DUMP_MEMORY = 2 +}; + +enum { + POD_BUSY_READ, + POD_BUSY_WRITE, + POD_CHANNEL_DIRTY, + POD_SAVE_PRESSED, + POD_BUSY_MIDISEND +}; + +static struct snd_ratden pod_ratden = { + .num_min = 78125, + .num_max = 78125, + .num_step = 1, + .den = 2 +}; + +static struct line6_pcm_properties pod_pcm_properties = { + .playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 39062, + .rate_max = 39063, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 39062, + .rate_max = 39063, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .rates = { + .nrats = 1, + .rats = &pod_ratden}, + .bytes_per_frame = POD_BYTES_PER_FRAME +}; + +static const char pod_version_header[] = { + 0xf2, 0x7e, 0x7f, 0x06, 0x02 +}; + +/* forward declarations: */ +static void pod_startup2(unsigned long data); +static void pod_startup3(struct usb_line6_pod *pod); + +static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, + int size) +{ + return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, + size); +} + +/* + Process a completely received message. +*/ +static void line6_pod_process_message(struct usb_line6 *line6) +{ + struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; + const unsigned char *buf = pod->line6.buffer_message; + + if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { + pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; + pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | + (int) buf[10]; + pod_startup3(pod); + return; + } + + /* Only look for sysex messages from this device */ + if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) && + buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) { + return; + } + if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0) + return; + + if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) { + short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | + ((int)buf[9] << 4) | (int)buf[10]; + pod->monitor_level = value; + } +} + +/* + Send system parameter (from integer). +*/ +static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, + int code) +{ + char *sysex; + static const int size = 5; + + sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size); + if (!sysex) + return -ENOMEM; + sysex[SYSEX_DATA_OFS] = code; + sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; + sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; + sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; + sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f; + line6_send_sysex_message(&pod->line6, sysex, size); + kfree(sysex); + return 0; +} + +/* + "read" request on "serial_number" special file. +*/ +static ssize_t serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6_pod *pod = usb_get_intfdata(interface); + + return sprintf(buf, "%u\n", pod->serial_number); +} + +/* + "read" request on "firmware_version" special file. +*/ +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6_pod *pod = usb_get_intfdata(interface); + + return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, + pod->firmware_version % 100); +} + +/* + "read" request on "device_id" special file. +*/ +static ssize_t device_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *interface = to_usb_interface(dev); + struct usb_line6_pod *pod = usb_get_intfdata(interface); + + return sprintf(buf, "%d\n", pod->device_id); +} + +/* + POD startup procedure. + This is a sequence of functions with special requirements (e.g., must + not run immediately after initialization, must not run in interrupt + context). After the last one has finished, the device is ready to use. +*/ + +static void pod_startup1(struct usb_line6_pod *pod) +{ + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); + + /* delay startup procedure: */ + line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, + (unsigned long)pod); +} + +static void pod_startup2(unsigned long data) +{ + struct usb_line6_pod *pod = (struct usb_line6_pod *)data; + struct usb_line6 *line6 = &pod->line6; + + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); + + /* request firmware version: */ + line6_version_request_async(line6); +} + +static void pod_startup3(struct usb_line6_pod *pod) +{ + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE); + + /* schedule work for global work queue: */ + schedule_work(&pod->startup_work); +} + +static void pod_startup4(struct work_struct *work) +{ + struct usb_line6_pod *pod = + container_of(work, struct usb_line6_pod, startup_work); + struct usb_line6 *line6 = &pod->line6; + + CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP); + + /* serial number: */ + line6_read_serial_number(&pod->line6, &pod->serial_number); + + /* ALSA audio interface: */ + snd_card_register(line6->card); +} + +/* POD special files: */ +static DEVICE_ATTR_RO(device_id); +static DEVICE_ATTR_RO(firmware_version); +static DEVICE_ATTR_RO(serial_number); + +static struct attribute *pod_dev_attrs[] = { + &dev_attr_device_id.attr, + &dev_attr_firmware_version.attr, + &dev_attr_serial_number.attr, + NULL +}; + +static const struct attribute_group pod_dev_attr_group = { + .name = "pod", + .attrs = pod_dev_attrs, +}; + +/* control info callback */ +static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 65535; + return 0; +} + +/* control get callback */ +static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; + + ucontrol->value.integer.value[0] = pod->monitor_level; + return 0; +} + +/* control put callback */ +static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; + + if (ucontrol->value.integer.value[0] == pod->monitor_level) + return 0; + + pod->monitor_level = ucontrol->value.integer.value[0]; + pod_set_system_param_int(pod, ucontrol->value.integer.value[0], + POD_MONITOR_LEVEL); + return 1; +} + +/* control definition */ +static struct snd_kcontrol_new pod_control_monitor = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitor Playback Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_pod_control_monitor_info, + .get = snd_pod_control_monitor_get, + .put = snd_pod_control_monitor_put +}; + +/* + POD device disconnected. +*/ +static void line6_pod_disconnect(struct usb_line6 *line6) +{ + struct usb_line6_pod *pod = (struct usb_line6_pod *)line6; + + del_timer_sync(&pod->startup_timer); + cancel_work_sync(&pod->startup_work); +} + +/* + Try to init POD device. +*/ +static int pod_init(struct usb_line6 *line6, + const struct usb_device_id *id) +{ + int err; + struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; + + line6->process_message = line6_pod_process_message; + line6->disconnect = line6_pod_disconnect; + + init_timer(&pod->startup_timer); + INIT_WORK(&pod->startup_work, pod_startup4); + + /* create sysfs entries: */ + err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group); + if (err < 0) + return err; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(line6); + if (err < 0) + return err; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &pod_pcm_properties); + if (err < 0) + return err; + + /* register monitor control: */ + err = snd_ctl_add(line6->card, + snd_ctl_new1(&pod_control_monitor, line6->line6pcm)); + if (err < 0) + return err; + + /* + When the sound card is registered at this point, the PODxt Live + displays "Invalid Code Error 07", so we do it later in the event + handler. + */ + + if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { + pod->monitor_level = POD_SYSTEM_INVALID; + + /* initiate startup procedure: */ + pod_startup1(pod); + } + + return 0; +} + +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id pod_id_table[] = { + { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, + { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, + { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, + { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, + { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, + { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, + { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, + {} +}; + +MODULE_DEVICE_TABLE(usb, pod_id_table); + +static const struct line6_properties pod_properties_table[] = { + [LINE6_BASSPODXT] = { + .id = "BassPODxt", + .name = "BassPODxt", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_BASSPODXTLIVE] = { + .id = "BassPODxtLive", + .name = "BassPODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_BASSPODXTPRO] = { + .id = "BassPODxtPro", + .name = "BassPODxt Pro", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_POCKETPOD] = { + .id = "PocketPOD", + .name = "Pocket POD", + .capabilities = LINE6_CAP_CONTROL, + .altsetting = 0, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x02, + /* no audio channel */ + }, + [LINE6_PODXT] = { + .id = "PODxt", + .name = "PODxt", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXTLIVE_POD] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXTPRO] = { + .id = "PODxtPro", + .name = "PODxt Pro", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, +}; + +/* + Probe USB device. +*/ +static int pod_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + return line6_probe(interface, id, "Line6-POD", + &pod_properties_table[id->driver_info], + pod_init, sizeof(struct usb_line6_pod)); +} + +static struct usb_driver pod_driver = { + .name = KBUILD_MODNAME, + .probe = pod_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = line6_resume, +#endif + .id_table = pod_id_table, +}; + +module_usb_driver(pod_driver); + +MODULE_DESCRIPTION("Line 6 POD USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c new file mode 100644 index 000000000000..63dcaef41ac3 --- /dev/null +++ b/sound/usb/line6/podhd.c @@ -0,0 +1,192 @@ +/* + * Line 6 Pod HD + * + * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/usb.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <sound/core.h> +#include <sound/pcm.h> + +#include "driver.h" +#include "pcm.h" + +enum { + LINE6_PODHD300, + LINE6_PODHD400, + LINE6_PODHD500_0, + LINE6_PODHD500_1, +}; + +#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ + +static struct snd_ratden podhd_ratden = { + .num_min = 48000, + .num_max = 48000, + .num_step = 1, + .den = 1, +}; + +static struct line6_pcm_properties podhd_pcm_properties = { + .playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .rates = { + .nrats = 1, + .rats = &podhd_ratden}, + .bytes_per_frame = PODHD_BYTES_PER_FRAME +}; + +/* + Try to init POD HD device. +*/ +static int podhd_init(struct usb_line6 *line6, + const struct usb_device_id *id) +{ + int err; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(line6); + if (err < 0) + return err; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &podhd_pcm_properties); + if (err < 0) + return err; + + /* register USB audio system: */ + return snd_card_register(line6->card); +} + +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id podhd_id_table[] = { + { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, + { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, + { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, + { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, + {} +}; + +MODULE_DEVICE_TABLE(usb, podhd_id_table); + +static const struct line6_properties podhd_properties_table[] = { + [LINE6_PODHD300] = { + .id = "PODHD300", + .name = "POD HD300", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODHD400] = { + .id = "PODHD400", + .name = "POD HD400", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODHD500_0] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, + [LINE6_PODHD500_1] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, +}; + +/* + Probe USB device. +*/ +static int podhd_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + return line6_probe(interface, id, "Line6-PODHD", + &podhd_properties_table[id->driver_info], + podhd_init, sizeof(struct usb_line6)); +} + +static struct usb_driver podhd_driver = { + .name = KBUILD_MODNAME, + .probe = podhd_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = line6_resume, +#endif + .id_table = podhd_id_table, +}; + +module_usb_driver(podhd_driver); + +MODULE_DESCRIPTION("Line 6 PODHD USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c new file mode 100644 index 000000000000..6d4c50c9b17d --- /dev/null +++ b/sound/usb/line6/toneport.c @@ -0,0 +1,580 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * Emil Myhrman (emil.myhrman@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/wait.h> +#include <linux/usb.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/leds.h> +#include <sound/core.h> +#include <sound/control.h> + +#include "capture.h" +#include "driver.h" +#include "playback.h" + +enum line6_device_type { + LINE6_GUITARPORT, + LINE6_PODSTUDIO_GX, + LINE6_PODSTUDIO_UX1, + LINE6_PODSTUDIO_UX2, + LINE6_TONEPORT_GX, + LINE6_TONEPORT_UX1, + LINE6_TONEPORT_UX2, +}; + +struct usb_line6_toneport; + +struct toneport_led { + struct led_classdev dev; + char name[64]; + struct usb_line6_toneport *toneport; + bool registered; +}; + +struct usb_line6_toneport { + /* Generic Line 6 USB data */ + struct usb_line6 line6; + + /* Source selector */ + int source; + + /* Serial number of device */ + u32 serial_number; + + /* Firmware version (x 100) */ + u8 firmware_version; + + /* Timer for delayed PCM startup */ + struct timer_list timer; + + /* Device type */ + enum line6_device_type type; + + /* LED instances */ + struct toneport_led leds[2]; +}; + +static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); + +#define TONEPORT_PCM_DELAY 1 + +static struct snd_ratden toneport_ratden = { + .num_min = 44100, + .num_max = 44100, + .num_step = 1, + .den = 1 +}; + +static struct line6_pcm_properties toneport_pcm_properties = { + .playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 44100, + .rate_max = 44100, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_KNOT, + .rate_min = 44100, + .rate_max = 44100, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .rates = { + .nrats = 1, + .rats = &toneport_ratden}, + .bytes_per_frame = 4 +}; + +static const struct { + const char *name; + int code; +} toneport_source_info[] = { + {"Microphone", 0x0a01}, + {"Line", 0x0801}, + {"Instrument", 0x0b01}, + {"Inst & Mic", 0x0901} +}; + +static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) +{ + int ret; + + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(&usbdev->dev, "send failed (error %d)\n", ret); + return ret; + } + + return 0; +} + +/* monitor info callback */ +static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 256; + return 0; +} + +/* monitor get callback */ +static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = line6pcm->volume_monitor; + return 0; +} + +/* monitor put callback */ +static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + int err; + + if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) + return 0; + + line6pcm->volume_monitor = ucontrol->value.integer.value[0]; + + if (line6pcm->volume_monitor > 0) { + err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); + if (err < 0) { + line6pcm->volume_monitor = 0; + line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); + return err; + } + } else { + line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); + } + + return 1; +} + +/* source info callback */ +static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + const int size = ARRAY_SIZE(toneport_source_info); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = size; + + if (uinfo->value.enumerated.item >= size) + uinfo->value.enumerated.item = size - 1; + + strcpy(uinfo->value.enumerated.name, + toneport_source_info[uinfo->value.enumerated.item].name); + + return 0; +} + +/* source get callback */ +static int snd_toneport_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_toneport *toneport = + (struct usb_line6_toneport *)line6pcm->line6; + ucontrol->value.enumerated.item[0] = toneport->source; + return 0; +} + +/* source put callback */ +static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + struct usb_line6_toneport *toneport = + (struct usb_line6_toneport *)line6pcm->line6; + unsigned int source; + + source = ucontrol->value.enumerated.item[0]; + if (source >= ARRAY_SIZE(toneport_source_info)) + return -EINVAL; + if (source == toneport->source) + return 0; + + toneport->source = source; + toneport_send_cmd(toneport->line6.usbdev, + toneport_source_info[source].code, 0x0000); + return 1; +} + +static void toneport_start_pcm(unsigned long arg) +{ + struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; + struct usb_line6 *line6 = &toneport->line6; + + line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR); +} + +/* control definition */ +static struct snd_kcontrol_new toneport_control_monitor = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitor Playback Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_toneport_monitor_info, + .get = snd_toneport_monitor_get, + .put = snd_toneport_monitor_put +}; + +/* source selector definition */ +static struct snd_kcontrol_new toneport_control_source = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Capture Source", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_toneport_source_info, + .get = snd_toneport_source_get, + .put = snd_toneport_source_put +}; + +/* + For the led on Guitarport. + Brightness goes from 0x00 to 0x26. Set a value above this to have led + blink. + (void cmd_0x02(byte red, byte green) +*/ + +static bool toneport_has_led(struct usb_line6_toneport *toneport) +{ + switch (toneport->type) { + case LINE6_GUITARPORT: + case LINE6_TONEPORT_GX: + /* add your device here if you are missing support for the LEDs */ + return true; + + default: + return false; + } +} + +static const char * const led_colors[2] = { "red", "green" }; +static const int led_init_vals[2] = { 0x00, 0x26 }; + +static void toneport_update_led(struct usb_line6_toneport *toneport) +{ + toneport_send_cmd(toneport->line6.usbdev, + (toneport->leds[0].dev.brightness << 8) | 0x0002, + toneport->leds[1].dev.brightness); +} + +static void toneport_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct toneport_led *leds = + container_of(led_cdev, struct toneport_led, dev); + toneport_update_led(leds->toneport); +} + +static int toneport_init_leds(struct usb_line6_toneport *toneport) +{ + struct device *dev = &toneport->line6.usbdev->dev; + int i, err; + + for (i = 0; i < 2; i++) { + struct toneport_led *led = &toneport->leds[i]; + struct led_classdev *leddev = &led->dev; + + led->toneport = toneport; + snprintf(led->name, sizeof(led->name), "%s::%s", + dev_name(dev), led_colors[i]); + leddev->name = led->name; + leddev->brightness = led_init_vals[i]; + leddev->max_brightness = 0x26; + leddev->brightness_set = toneport_led_brightness_set; + err = led_classdev_register(dev, leddev); + if (err) + return err; + led->registered = true; + } + + return 0; +} + +static void toneport_remove_leds(struct usb_line6_toneport *toneport) +{ + struct toneport_led *led; + int i; + + for (i = 0; i < 2; i++) { + led = &toneport->leds[i]; + if (!led->registered) + break; + led_classdev_unregister(&led->dev); + led->registered = false; + } +} + +static bool toneport_has_source_select(struct usb_line6_toneport *toneport) +{ + switch (toneport->type) { + case LINE6_TONEPORT_UX1: + case LINE6_TONEPORT_UX2: + case LINE6_PODSTUDIO_UX1: + case LINE6_PODSTUDIO_UX2: + return true; + + default: + return false; + } +} + +/* + Setup Toneport device. +*/ +static void toneport_setup(struct usb_line6_toneport *toneport) +{ + int ticks; + struct usb_line6 *line6 = &toneport->line6; + struct usb_device *usbdev = line6->usbdev; + + /* sync time on device with host: */ + ticks = (int)get_seconds(); + line6_write_data(line6, 0x80c6, &ticks, 4); + + /* enable device: */ + toneport_send_cmd(usbdev, 0x0301, 0x0000); + + /* initialize source select: */ + if (toneport_has_source_select(toneport)) + toneport_send_cmd(usbdev, + toneport_source_info[toneport->source].code, + 0x0000); + + if (toneport_has_led(toneport)) + toneport_update_led(toneport); + + mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); +} + +/* + Toneport device disconnected. +*/ +static void line6_toneport_disconnect(struct usb_line6 *line6) +{ + struct usb_line6_toneport *toneport = + (struct usb_line6_toneport *)line6; + + del_timer_sync(&toneport->timer); + + if (toneport_has_led(toneport)) + toneport_remove_leds(toneport); +} + + +/* + Try to init Toneport device. +*/ +static int toneport_init(struct usb_line6 *line6, + const struct usb_device_id *id) +{ + int err; + struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; + + toneport->type = id->driver_info; + setup_timer(&toneport->timer, toneport_start_pcm, + (unsigned long)toneport); + + line6->disconnect = line6_toneport_disconnect; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &toneport_pcm_properties); + if (err < 0) + return err; + + /* register monitor control: */ + err = snd_ctl_add(line6->card, + snd_ctl_new1(&toneport_control_monitor, + line6->line6pcm)); + if (err < 0) + return err; + + /* register source select control: */ + if (toneport_has_source_select(toneport)) { + err = + snd_ctl_add(line6->card, + snd_ctl_new1(&toneport_control_source, + line6->line6pcm)); + if (err < 0) + return err; + } + + line6_read_serial_number(line6, &toneport->serial_number); + line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); + + if (toneport_has_led(toneport)) { + err = toneport_init_leds(toneport); + if (err < 0) + return err; + } + + toneport_setup(toneport); + + /* register audio system: */ + return snd_card_register(line6->card); +} + +#ifdef CONFIG_PM +/* + Resume Toneport device after reset. +*/ +static int toneport_reset_resume(struct usb_interface *interface) +{ + toneport_setup(usb_get_intfdata(interface)); + return line6_resume(interface); +} +#endif + +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id toneport_id_table[] = { + { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, + { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, + { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, + { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, + { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, + { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, + { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, + {} +}; + +MODULE_DEVICE_TABLE(usb, toneport_id_table); + +static const struct line6_properties toneport_properties_table[] = { + [LINE6_GUITARPORT] = { + .id = "GuitarPort", + .name = "GuitarPort", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_GX] = { + .id = "PODStudioGX", + .name = "POD Studio GX", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_UX1] = { + .id = "PODStudioUX1", + .name = "POD Studio UX1", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_UX2] = { + .id = "PODStudioUX2", + .name = "POD Studio UX2", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_GX] = { + .id = "TonePortGX", + .name = "TonePort GX", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_UX1] = { + .id = "TonePortUX1", + .name = "TonePort UX1", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_UX2] = { + .id = "TonePortUX2", + .name = "TonePort UX2", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, +}; + +/* + Probe USB device. +*/ +static int toneport_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + return line6_probe(interface, id, "Line6-TonePort", + &toneport_properties_table[id->driver_info], + toneport_init, sizeof(struct usb_line6_toneport)); +} + +static struct usb_driver toneport_driver = { + .name = KBUILD_MODNAME, + .probe = toneport_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = toneport_reset_resume, +#endif + .id_table = toneport_id_table, +}; + +module_usb_driver(toneport_driver); + +MODULE_DESCRIPTION("TonePort USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c new file mode 100644 index 000000000000..ddc23ddf0750 --- /dev/null +++ b/sound/usb/line6/variax.c @@ -0,0 +1,306 @@ +/* + * Line 6 Linux USB driver + * + * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/usb.h> +#include <linux/wait.h> +#include <linux/module.h> +#include <sound/core.h> + +#include "driver.h" + +#define VARIAX_STARTUP_DELAY1 1000 +#define VARIAX_STARTUP_DELAY3 100 +#define VARIAX_STARTUP_DELAY4 100 + +/* + Stages of Variax startup procedure +*/ +enum { + VARIAX_STARTUP_INIT = 1, + VARIAX_STARTUP_VERSIONREQ, + VARIAX_STARTUP_WAIT, + VARIAX_STARTUP_ACTIVATE, + VARIAX_STARTUP_WORKQUEUE, + VARIAX_STARTUP_SETUP, + VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 +}; + +enum { + LINE6_PODXTLIVE_VARIAX, + LINE6_VARIAX +}; + +struct usb_line6_variax { + /* Generic Line 6 USB data */ + struct usb_line6 line6; + + /* Buffer for activation code */ + unsigned char *buffer_activate; + + /* Handler for device initialization */ + struct work_struct startup_work; + + /* Timers for device initialization */ + struct timer_list startup_timer1; + struct timer_list startup_timer2; + + /* Current progress in startup procedure */ + int startup_progress; +}; + +#define VARIAX_OFFSET_ACTIVATE 7 + +/* + This message is sent by the device during initialization and identifies + the connected guitar version. +*/ +static const char variax_init_version[] = { + 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, + 0x07, 0x00, 0x00, 0x00 +}; + +/* + This message is the last one sent by the device during initialization. +*/ +static const char variax_init_done[] = { + 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b +}; + +static const char variax_activate[] = { + 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, + 0xf7 +}; + +/* forward declarations: */ +static void variax_startup2(unsigned long data); +static void variax_startup4(unsigned long data); +static void variax_startup5(unsigned long data); + +static void variax_activate_async(struct usb_line6_variax *variax, int a) +{ + variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; + line6_send_raw_message_async(&variax->line6, variax->buffer_activate, + sizeof(variax_activate)); +} + +/* + Variax startup procedure. + This is a sequence of functions with special requirements (e.g., must + not run immediately after initialization, must not run in interrupt + context). After the last one has finished, the device is ready to use. +*/ + +static void variax_startup1(struct usb_line6_variax *variax) +{ + CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); + + /* delay startup procedure: */ + line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, + variax_startup2, (unsigned long)variax); +} + +static void variax_startup2(unsigned long data) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6 *line6 = &variax->line6; + + /* schedule another startup procedure until startup is complete: */ + if (variax->startup_progress >= VARIAX_STARTUP_LAST) + return; + + variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; + line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, + variax_startup2, (unsigned long)variax); + + /* request firmware version: */ + line6_version_request_async(line6); +} + +static void variax_startup3(struct usb_line6_variax *variax) +{ + CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); + + /* delay startup procedure: */ + line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, + variax_startup4, (unsigned long)variax); +} + +static void variax_startup4(unsigned long data) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + + CHECK_STARTUP_PROGRESS(variax->startup_progress, + VARIAX_STARTUP_ACTIVATE); + + /* activate device: */ + variax_activate_async(variax, 1); + line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, + variax_startup5, (unsigned long)variax); +} + +static void variax_startup5(unsigned long data) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + + CHECK_STARTUP_PROGRESS(variax->startup_progress, + VARIAX_STARTUP_WORKQUEUE); + + /* schedule work for global work queue: */ + schedule_work(&variax->startup_work); +} + +static void variax_startup6(struct work_struct *work) +{ + struct usb_line6_variax *variax = + container_of(work, struct usb_line6_variax, startup_work); + + CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); + + /* ALSA audio interface: */ + snd_card_register(variax->line6.card); +} + +/* + Process a completely received message. +*/ +static void line6_variax_process_message(struct usb_line6 *line6) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; + const unsigned char *buf = variax->line6.buffer_message; + + switch (buf[0]) { + case LINE6_RESET: + dev_info(variax->line6.ifcdev, "VARIAX reset\n"); + break; + + case LINE6_SYSEX_BEGIN: + if (memcmp(buf + 1, variax_init_version + 1, + sizeof(variax_init_version) - 1) == 0) { + variax_startup3(variax); + } else if (memcmp(buf + 1, variax_init_done + 1, + sizeof(variax_init_done) - 1) == 0) { + /* notify of complete initialization: */ + variax_startup4((unsigned long)variax); + } + break; + } +} + +/* + Variax destructor. +*/ +static void line6_variax_disconnect(struct usb_line6 *line6) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *)line6; + + del_timer(&variax->startup_timer1); + del_timer(&variax->startup_timer2); + cancel_work_sync(&variax->startup_work); + + kfree(variax->buffer_activate); +} + +/* + Try to init workbench device. +*/ +static int variax_init(struct usb_line6 *line6, + const struct usb_device_id *id) +{ + struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; + int err; + + line6->process_message = line6_variax_process_message; + line6->disconnect = line6_variax_disconnect; + + init_timer(&variax->startup_timer1); + init_timer(&variax->startup_timer2); + INIT_WORK(&variax->startup_work, variax_startup6); + + /* initialize USB buffers: */ + variax->buffer_activate = kmemdup(variax_activate, + sizeof(variax_activate), GFP_KERNEL); + + if (variax->buffer_activate == NULL) + return -ENOMEM; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(&variax->line6); + if (err < 0) + return err; + + /* initiate startup procedure: */ + variax_startup1(variax); + return 0; +} + +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id variax_id_table[] = { + { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, + { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, + {} +}; + +MODULE_DEVICE_TABLE(usb, variax_id_table); + +static const struct line6_properties variax_properties_table[] = { + [LINE6_PODXTLIVE_VARIAX] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CONTROL, + .altsetting = 1, + .ep_ctrl_r = 0x86, + .ep_ctrl_w = 0x05, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_VARIAX] = { + .id = "Variax", + .name = "Variax Workbench", + .capabilities = LINE6_CAP_CONTROL, + .altsetting = 1, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x01, + /* no audio channel */ + } +}; + +/* + Probe USB device. +*/ +static int variax_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + return line6_probe(interface, id, "Line6-Variax", + &variax_properties_table[id->driver_info], + variax_init, sizeof(struct usb_line6_variax)); +} + +static struct usb_driver variax_driver = { + .name = KBUILD_MODNAME, + .probe = variax_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = line6_resume, +#endif + .id_table = variax_id_table, +}; + +module_usb_driver(variax_driver); + +MODULE_DESCRIPTION("Vairax Workbench USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 5bfb695547f8..417ebb11cf48 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2292,14 +2292,13 @@ int snd_usbmidi_create(struct snd_card *card, umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; - init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); init_rwsem(&umidi->disc_rwsem); mutex_init(&umidi->mutex); umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), le16_to_cpu(umidi->dev->descriptor.idProduct)); - umidi->error_timer.function = snd_usbmidi_error_timer; - umidi->error_timer.data = (unsigned long)umidi; + setup_timer(&umidi->error_timer, snd_usbmidi_error_timer, + (unsigned long)umidi); /* detect the endpoint(s) to use */ memset(endpoints, 0, sizeof(endpoints)); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0d8aba5fe1a8..b4ef410e5a98 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1464,6 +1464,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, subs->last_frame_number = usb_get_current_frame_number(subs->dev); subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ + if (subs->trigger_tstamp_pending_update) { + /* this is the first actual URB submitted, + * update trigger timestamp to reflect actual start time + */ + snd_pcm_gettime(runtime, &runtime->trigger_tstamp); + subs->trigger_tstamp_pending_update = false; + } + spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = bytes; if (period_elapsed) @@ -1550,6 +1558,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea switch (cmd) { case SNDRV_PCM_TRIGGER_START: + subs->trigger_tstamp_pending_update = true; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: subs->data_endpoint->prepare_data_urb = prepare_playback_urb; subs->data_endpoint->retire_data_urb = retire_playback_urb; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 0a598af9b38b..67d476548dcf 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2486,6 +2486,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + /* Akai MPC Element */ + USB_DEVICE(0x09e8, 0x0021), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, + /* TerraTec devices */ { USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index a7398412310b..753a47de8459 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1111,6 +1111,11 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, } } +bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) +{ + /* MS Lifecam HD-5000 doesn't support reading the sample rate. */ + return chip->usb_id == USB_ID(0x045E, 0x076D); +} /* Marantz/Denon USB DACs need a vendor cmd to switch * between PCM and native DSD mode @@ -1122,6 +1127,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, int err; switch (subs->stream->chip->usb_id) { + case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ @@ -1201,6 +1207,7 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) { switch (le16_to_cpu(dev->descriptor.idProduct)) { + case 0x1003: /* Denon DA300-USB */ case 0x3005: /* Marantz HD-DAC1 */ case 0x3006: /* Marantz SA-14S1 */ mdelay(20); @@ -1262,6 +1269,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, /* Denon/Marantz devices with USB DAC functionality */ switch (chip->usb_id) { + case USB_ID(0x154e, 0x1003): /* Denon DA300-USB */ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ if (fp->altsetting == 2) diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 1b862386577d..2cd71ed1201f 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -21,6 +21,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, void snd_usb_set_format_quirk(struct snd_usb_substream *subs, struct audioformat *fmt); +bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip); + int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp); diff --git a/sound/usb/usx2y/usb_stream.h b/sound/usb/usx2y/usb_stream.h index 4dd74ab1e9cc..90369001eab6 100644 --- a/sound/usb/usx2y/usb_stream.h +++ b/sound/usb/usx2y/usb_stream.h @@ -1,76 +1,7 @@ -/* - * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +#ifndef __USB_STREAM_H +#define __USB_STREAM_H -#define USB_STREAM_INTERFACE_VERSION 2 - -#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \ - _IOW('H', 0x90, struct usb_stream_config) - -struct usb_stream_packet { - unsigned offset; - unsigned length; -}; - - -struct usb_stream_config { - unsigned version; - unsigned sample_rate; - unsigned period_frames; - unsigned frame_size; -}; - -struct usb_stream { - struct usb_stream_config cfg; - unsigned read_size; - unsigned write_size; - - int period_size; - - unsigned state; - - int idle_insize; - int idle_outsize; - int sync_packet; - unsigned insize_done; - unsigned periods_done; - unsigned periods_polled; - - struct usb_stream_packet outpacket[2]; - unsigned inpackets; - unsigned inpacket_head; - unsigned inpacket_split; - unsigned inpacket_split_at; - unsigned next_inpacket_split; - unsigned next_inpacket_split_at; - struct usb_stream_packet inpacket[0]; -}; - -enum usb_stream_state { - usb_stream_invalid, - usb_stream_stopped, - usb_stream_sync0, - usb_stream_sync1, - usb_stream_ready, - usb_stream_running, - usb_stream_xrun, -}; - -#if __KERNEL__ +#include <uapi/sound/usb_stream.h> #define USB_STREAM_NURBS 4 #define USB_STREAM_URBDEPTH 4 @@ -108,5 +39,4 @@ void usb_stream_free(struct usb_stream_kernel *); int usb_stream_start(struct usb_stream_kernel *); void usb_stream_stop(struct usb_stream_kernel *); - -#endif +#endif /* __USB_STREAM_H */ |