diff options
Diffstat (limited to 'drivers/staging/vc04_services/bcm2835-audio/bcm2835.c')
-rw-r--r-- | drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | 222 |
1 files changed, 54 insertions, 168 deletions
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c index da0fa34501fa..87d56ab1ffa0 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c @@ -22,38 +22,6 @@ module_param(enable_compat_alsa, bool, 0444); MODULE_PARM_DESC(enable_compat_alsa, "Enables ALSA compatibility virtual audio device"); -static void snd_devm_unregister_child(struct device *dev, void *res) -{ - struct device *childdev = *(struct device **)res; - struct bcm2835_chip *chip = dev_get_drvdata(childdev); - struct snd_card *card = chip->card; - - snd_card_free(card); - - device_unregister(childdev); -} - -static int snd_devm_add_child(struct device *dev, struct device *child) -{ - struct device **dr; - int ret; - - dr = devres_alloc(snd_devm_unregister_child, sizeof(*dr), GFP_KERNEL); - if (!dr) - return -ENOMEM; - - ret = device_add(child); - if (ret) { - devres_free(dr); - return ret; - } - - *dr = child; - devres_add(dev, dr); - - return 0; -} - static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res) { struct bcm2835_vchi_ctx *vchi_ctx = res; @@ -73,7 +41,7 @@ static int bcm2835_devm_add_vchi_ctx(struct device *dev) memset(vchi_ctx, 0, sizeof(*vchi_ctx)); - ret = bcm2835_new_vchi_ctx(vchi_ctx); + ret = bcm2835_new_vchi_ctx(dev, vchi_ctx); if (ret) { devres_free(vchi_ctx); return ret; @@ -84,101 +52,6 @@ static int bcm2835_devm_add_vchi_ctx(struct device *dev) return 0; } -static void snd_bcm2835_release(struct device *dev) -{ - struct bcm2835_chip *chip = dev_get_drvdata(dev); - - kfree(chip); -} - -static struct device * -snd_create_device(struct device *parent, - struct device_driver *driver, - const char *name) -{ - struct device *device; - int ret; - - device = devm_kzalloc(parent, sizeof(*device), GFP_KERNEL); - if (!device) - return ERR_PTR(-ENOMEM); - - device_initialize(device); - device->parent = parent; - device->driver = driver; - device->release = snd_bcm2835_release; - - dev_set_name(device, "%s", name); - - ret = snd_devm_add_child(parent, device); - if (ret) - return ERR_PTR(ret); - - return device; -} - -/* component-destructor - * (see "Management of Cards and Components") - */ -static int snd_bcm2835_dev_free(struct snd_device *device) -{ - struct bcm2835_chip *chip = device->device_data; - struct snd_card *card = chip->card; - - snd_device_free(card, chip); - - return 0; -} - -/* chip-specific constructor - * (see "Management of Cards and Components") - */ -static int snd_bcm2835_create(struct snd_card *card, - struct bcm2835_chip **rchip) -{ - struct bcm2835_chip *chip; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_bcm2835_dev_free, - }; - - *rchip = NULL; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->card = card; - - chip->vchi_ctx = devres_find(card->dev->parent, - bcm2835_devm_free_vchi_ctx, NULL, NULL); - if (!chip->vchi_ctx) { - kfree(chip); - return -ENODEV; - } - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err) { - kfree(chip); - return err; - } - - *rchip = chip; - return 0; -} - -static struct snd_card *snd_bcm2835_card_new(struct device *dev) -{ - struct snd_card *card; - int ret; - - ret = snd_card_new(dev, -1, NULL, THIS_MODULE, 0, &card); - if (ret) - return ERR_PTR(ret); - - return card; -} - typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip, const char *name, enum snd_bcm2835_route route, @@ -203,17 +76,26 @@ static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip, { int err; - err = snd_bcm2835_new_pcm(chip, numchannels - 1); + err = snd_bcm2835_new_pcm(chip, "bcm2835 ALSA", 0, AUDIO_DEST_AUTO, + numchannels - 1, false); if (err) return err; - err = snd_bcm2835_new_spdif_pcm(chip); + err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true); if (err) return err; return 0; } +static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip, + const char *name, + enum snd_bcm2835_route route, + u32 numchannels) +{ + return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false); +} + static struct bcm2835_audio_driver bcm2835_audio_alsa = { .driver = { .name = "bcm2835_alsa", @@ -234,7 +116,7 @@ static struct bcm2835_audio_driver bcm2835_audio_hdmi = { .shortname = "bcm2835 HDMI", .longname = "bcm2835 HDMI", .minchannels = 1, - .newpcm = snd_bcm2835_new_simple_pcm, + .newpcm = bcm2835_audio_simple_newpcm, .newctl = snd_bcm2835_new_hdmi_ctl, .route = AUDIO_DEST_HDMI }; @@ -247,7 +129,7 @@ static struct bcm2835_audio_driver bcm2835_audio_headphones = { .shortname = "bcm2835 Headphones", .longname = "bcm2835 Headphones", .minchannels = 1, - .newpcm = snd_bcm2835_new_simple_pcm, + .newpcm = bcm2835_audio_simple_newpcm, .newctl = snd_bcm2835_new_headphones_ctl, .route = AUDIO_DEST_HEADPHONES }; @@ -272,71 +154,75 @@ static struct bcm2835_audio_drivers children_devices[] = { }, }; -static int snd_add_child_device(struct device *device, +static void bcm2835_card_free(void *data) +{ + snd_card_free(data); +} + +static int snd_add_child_device(struct device *dev, struct bcm2835_audio_driver *audio_driver, u32 numchans) { struct snd_card *card; - struct device *child; struct bcm2835_chip *chip; - int err, i; - - child = snd_create_device(device, &audio_driver->driver, - audio_driver->driver.name); - if (IS_ERR(child)) { - dev_err(device, - "Unable to create child device %p, error %ld", - audio_driver->driver.name, - PTR_ERR(child)); - return PTR_ERR(child); + int err; + + err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card); + if (err < 0) { + dev_err(dev, "Failed to create card"); + return err; } - card = snd_bcm2835_card_new(child); - if (IS_ERR(card)) { - dev_err(child, "Failed to create card"); - return PTR_ERR(card); + chip = card->private_data; + chip->card = card; + chip->dev = dev; + mutex_init(&chip->audio_mutex); + + chip->vchi_ctx = devres_find(dev, + bcm2835_devm_free_vchi_ctx, NULL, NULL); + if (!chip->vchi_ctx) { + err = -ENODEV; + goto error; } - snd_card_set_dev(card, child); strcpy(card->driver, audio_driver->driver.name); strcpy(card->shortname, audio_driver->shortname); strcpy(card->longname, audio_driver->longname); - err = snd_bcm2835_create(card, &chip); - if (err) { - dev_err(child, "Failed to create chip, error %d\n", err); - return err; - } - - chip->dev = child; - err = audio_driver->newpcm(chip, audio_driver->shortname, audio_driver->route, numchans); if (err) { - dev_err(child, "Failed to create pcm, error %d\n", err); - return err; + dev_err(dev, "Failed to create pcm, error %d\n", err); + goto error; } err = audio_driver->newctl(chip); if (err) { - dev_err(child, "Failed to create controls, error %d\n", err); - return err; + dev_err(dev, "Failed to create controls, error %d\n", err); + goto error; } - for (i = 0; i < numchans; i++) - chip->avail_substreams |= (1 << i); - err = snd_card_register(card); if (err) { - dev_err(child, "Failed to register card, error %d\n", err); - return err; + dev_err(dev, "Failed to register card, error %d\n", err); + goto error; } - dev_set_drvdata(child, chip); - dev_info(child, "card created with %d channels\n", numchans); + dev_set_drvdata(dev, chip); + + err = devm_add_action(dev, bcm2835_card_free, card); + if (err < 0) { + dev_err(dev, "Failed to add devm action, err %d\n", err); + goto error; + } + dev_info(dev, "card created with %d channels\n", numchans); return 0; + + error: + snd_card_free(card); + return err; } static int snd_add_child_devices(struct device *device, u32 numchans) |