/*1* Device management routines2* Copyright (c) by Jaroslav Kysela <[email protected]>3*4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*19*/2021#include <linux/slab.h>22#include <linux/time.h>23#include <linux/errno.h>24#include <sound/core.h>2526/**27* snd_device_new - create an ALSA device component28* @card: the card instance29* @type: the device type, SNDRV_DEV_XXX30* @device_data: the data pointer of this device31* @ops: the operator table32*33* Creates a new device component for the given data pointer.34* The device will be assigned to the card and managed together35* by the card.36*37* The data pointer plays a role as the identifier, too, so the38* pointer address must be unique and unchanged.39*40* Returns zero if successful, or a negative error code on failure.41*/42int snd_device_new(struct snd_card *card, snd_device_type_t type,43void *device_data, struct snd_device_ops *ops)44{45struct snd_device *dev;4647if (snd_BUG_ON(!card || !device_data || !ops))48return -ENXIO;49dev = kzalloc(sizeof(*dev), GFP_KERNEL);50if (dev == NULL) {51snd_printk(KERN_ERR "Cannot allocate device\n");52return -ENOMEM;53}54dev->card = card;55dev->type = type;56dev->state = SNDRV_DEV_BUILD;57dev->device_data = device_data;58dev->ops = ops;59list_add(&dev->list, &card->devices); /* add to the head of list */60return 0;61}6263EXPORT_SYMBOL(snd_device_new);6465/**66* snd_device_free - release the device from the card67* @card: the card instance68* @device_data: the data pointer to release69*70* Removes the device from the list on the card and invokes the71* callbacks, dev_disconnect and dev_free, corresponding to the state.72* Then release the device.73*74* Returns zero if successful, or a negative error code on failure or if the75* device not found.76*/77int snd_device_free(struct snd_card *card, void *device_data)78{79struct snd_device *dev;8081if (snd_BUG_ON(!card || !device_data))82return -ENXIO;83list_for_each_entry(dev, &card->devices, list) {84if (dev->device_data != device_data)85continue;86/* unlink */87list_del(&dev->list);88if (dev->state == SNDRV_DEV_REGISTERED &&89dev->ops->dev_disconnect)90if (dev->ops->dev_disconnect(dev))91snd_printk(KERN_ERR92"device disconnect failure\n");93if (dev->ops->dev_free) {94if (dev->ops->dev_free(dev))95snd_printk(KERN_ERR "device free failure\n");96}97kfree(dev);98return 0;99}100snd_printd("device free %p (from %pF), not found\n", device_data,101__builtin_return_address(0));102return -ENXIO;103}104105EXPORT_SYMBOL(snd_device_free);106107/**108* snd_device_disconnect - disconnect the device109* @card: the card instance110* @device_data: the data pointer to disconnect111*112* Turns the device into the disconnection state, invoking113* dev_disconnect callback, if the device was already registered.114*115* Usually called from snd_card_disconnect().116*117* Returns zero if successful, or a negative error code on failure or if the118* device not found.119*/120int snd_device_disconnect(struct snd_card *card, void *device_data)121{122struct snd_device *dev;123124if (snd_BUG_ON(!card || !device_data))125return -ENXIO;126list_for_each_entry(dev, &card->devices, list) {127if (dev->device_data != device_data)128continue;129if (dev->state == SNDRV_DEV_REGISTERED &&130dev->ops->dev_disconnect) {131if (dev->ops->dev_disconnect(dev))132snd_printk(KERN_ERR "device disconnect failure\n");133dev->state = SNDRV_DEV_DISCONNECTED;134}135return 0;136}137snd_printd("device disconnect %p (from %pF), not found\n", device_data,138__builtin_return_address(0));139return -ENXIO;140}141142/**143* snd_device_register - register the device144* @card: the card instance145* @device_data: the data pointer to register146*147* Registers the device which was already created via148* snd_device_new(). Usually this is called from snd_card_register(),149* but it can be called later if any new devices are created after150* invocation of snd_card_register().151*152* Returns zero if successful, or a negative error code on failure or if the153* device not found.154*/155int snd_device_register(struct snd_card *card, void *device_data)156{157struct snd_device *dev;158int err;159160if (snd_BUG_ON(!card || !device_data))161return -ENXIO;162list_for_each_entry(dev, &card->devices, list) {163if (dev->device_data != device_data)164continue;165if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {166if ((err = dev->ops->dev_register(dev)) < 0)167return err;168dev->state = SNDRV_DEV_REGISTERED;169return 0;170}171snd_printd("snd_device_register busy\n");172return -EBUSY;173}174snd_BUG();175return -ENXIO;176}177178EXPORT_SYMBOL(snd_device_register);179180/*181* register all the devices on the card.182* called from init.c183*/184int snd_device_register_all(struct snd_card *card)185{186struct snd_device *dev;187int err;188189if (snd_BUG_ON(!card))190return -ENXIO;191list_for_each_entry(dev, &card->devices, list) {192if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {193if ((err = dev->ops->dev_register(dev)) < 0)194return err;195dev->state = SNDRV_DEV_REGISTERED;196}197}198return 0;199}200201/*202* disconnect all the devices on the card.203* called from init.c204*/205int snd_device_disconnect_all(struct snd_card *card)206{207struct snd_device *dev;208int err = 0;209210if (snd_BUG_ON(!card))211return -ENXIO;212list_for_each_entry(dev, &card->devices, list) {213if (snd_device_disconnect(card, dev->device_data) < 0)214err = -ENXIO;215}216return err;217}218219/*220* release all the devices on the card.221* called from init.c222*/223int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)224{225struct snd_device *dev;226int err;227unsigned int range_low, range_high, type;228229if (snd_BUG_ON(!card))230return -ENXIO;231range_low = (__force unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE;232range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;233__again:234list_for_each_entry(dev, &card->devices, list) {235type = (__force unsigned int)dev->type;236if (type >= range_low && type <= range_high) {237if ((err = snd_device_free(card, dev->device_data)) < 0)238return err;239goto __again;240}241}242return 0;243}244245246