On Sat, 30 Apr 2016 23:15:34 +0200,
Robert Jarzmik wrote:
> 
> diff --git a/include/sound/ac97/codec.h b/include/sound/ac97/codec.h
> new file mode 100644
> index 000000000000..4b8b3e570892
> --- /dev/null
> +++ b/include/sound/ac97/codec.h
> @@ -0,0 +1,98 @@
> +/*
> + *  Copyright (C) 2016 Robert Jarzmik <robert.jarz...@free.fr>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef AC97_CODEC_H
> +#define AC97_CODEC_H

Let's be careful about the choice of the guard.


> +
> +#include <linux/device.h>
> +
> +#define AC97_ID(vendor_id1, vendor_id2) \
> +     (((vendor_id1 & 0xffff) << 16) | (vendor_id2 & 0xffff))
> +#define AC97_DRIVER_ID(vendor_id1, vendor_id2, mask_id1, mask_id2, _data) \
> +     { .id = ((vendor_id1 & 0xffff) << 16) | (vendor_id2 & 0xffff), \
> +       .mask = ((mask_id1 & 0xffff) << 16) | (mask_id2 & 0xffff), \
> +       .data = _data }

Give parentheses around the macro arguments.


> +
> +#define to_ac97_device(d) container_of(d, struct ac97_codec_device, dev)
> +#define to_ac97_driver(d) container_of(d, struct ac97_codec_driver, driver)
> +
> +struct ac97_controller;
> +
> +/**
> + * struct ac97_id - matches a codec device and driver on an ac97 bus
> + * @id: The significant bits if the codec vendor ID1 and ID2
> + * @mask: Bitmask specifying which bits of the id field are significant when
> + *     matching. A driver binds to a device when :
> + *        ((vendorID1 << 8 | vendorID2) & (mask_id1 << 8 | mask_id2)) == id.
> + * @data: Private data used by the driver.
> + */
> +struct ac97_id {
> +     unsigned int            id;
> +     unsigned int            mask;
> +     void                    *data;
> +};
> +
> +/**
> + * ac97_codec_device - a ac97 codec
> + * @dev: the code device
> + * @vendor_id: the vendor_id of the codec, as sensed on the AC-link
> + * @num: the codec number, 0 is primary, 1 is first slave, etc ...
> + * @ac97_ctrl: ac97 digital controller on the same AC-link
> + *
> + * This is the device instanciated for each codec living on a AC-link. There 
> are
> + * normally 0 to 4 codec devices per AC-link, and all of them are controlled 
> by
> + * an AC97 digital controller.
> + */
> +struct ac97_codec_device {
> +     struct device           dev;    /* Must stay first member */

This doesn't have to be the first element as long as you use container_of().


> +     unsigned int            vendor_id;
> +     unsigned int            num;
> +     struct list_head        list;
> +     struct ac97_controller  *ac97_ctrl;
> +};
> +
> +/**
> + * ac97_codec_driver - a ac97 codec driver
> + * @driver: the device driver structure
> + * @probe: the function called when a ac97_codec_device is matched
> + * @remove: the function called when the device is unbound/removed
> + * @suspend: suspend function (might be NULL)
> + * @resume: resume function (might be NULL)
> + * @shutdown: shutdown function (might be NULL)
> + * @id_table: ac97 vendor_id match table, { } member terminated
> + */
> +struct ac97_codec_driver {
> +     struct device_driver    driver;
> +     int                     (*probe)(struct ac97_codec_device *);
> +     int                     (*remove)(struct ac97_codec_device *);
> +     int                     (*suspend)(struct ac97_codec_device *);
> +     int                     (*resume)(struct ac97_codec_device *);
> +     void                    (*shutdown)(struct ac97_codec_device *);
> +     struct ac97_id          *id_table;

Missing const?

> +};
> +
> +int ac97_codec_driver_register(struct ac97_codec_driver *drv);
> +void ac97_codec_driver_unregister(struct ac97_codec_driver *drv);
> +
> +static inline struct device *
> +ac97_codec_dev2dev(const struct ac97_codec_device *adev)
> +{
> +     return (struct device *)(adev);

What's wrong with the simple &adev->dev ?  Cast looks scary.

> +}
> +
> +static inline void *ac97_get_drvdata(const struct ac97_codec_device *adev)
> +{
> +     return dev_get_drvdata(ac97_codec_dev2dev(adev));
> +}
> +
> +static inline void ac97_set_drvdata(const struct ac97_codec_device *adev,
> +                                 void *data)
> +{
> +     dev_set_drvdata(ac97_codec_dev2dev(adev), data);
> +}
> +
> +#endif
> diff --git a/include/sound/ac97/compat.h b/include/sound/ac97/compat.h
> new file mode 100644
> index 000000000000..bf611f572f2d
> --- /dev/null
> +++ b/include/sound/ac97/compat.h
> @@ -0,0 +1,21 @@
> +/*
> + *  Copyright (C) 2016 Robert Jarzmik <robert.jarz...@free.fr>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This file is for backward compatibility with snd_ac97 structure and its
> + * multiple usages, such as the snd_ac97_bus and snd_ac97_build_ops.
> + *
> + */
> +#ifndef AC97_COMPAT_H
> +#define AC97_COMPAT_H
> +
> +#include <sound/ac97_codec.h>
> +#include <sound/soc.h>
> +
> +struct snd_ac97 *compat_alloc_snd_ac97_codec(struct snd_soc_codec *codec);
> +void compat_release_snd_ac97_codec(struct snd_ac97 *ac97);
> +
> +#endif
> diff --git a/include/sound/ac97/controller.h b/include/sound/ac97/controller.h
> new file mode 100644
> index 000000000000..f1e5e645f5ef
> --- /dev/null
> +++ b/include/sound/ac97/controller.h
> @@ -0,0 +1,39 @@
> +/*
> + *  Copyright (C) 2016 Robert Jarzmik <robert.jarz...@free.fr>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef AC97_CONTROLLER_H
> +#define AC97_CONTROLLER_H
> +
> +#include <linux/list.h>
> +
> +struct device;
> +struct ac97_codec_device;
> +
> +struct ac97_controller_ops {
> +     void (*reset)(struct ac97_codec_device *ac97);
> +     void (*warm_reset)(struct ac97_codec_device *ac97);
> +     int (*write)(struct ac97_codec_device *ac97, unsigned short reg,
> +                  unsigned short val);
> +     int (*read)(struct ac97_codec_device *ac97, unsigned short reg);
> +     void (*wait)(struct ac97_codec_device *ac97);
> +     void (*init)(struct ac97_codec_device *ac97);
> +};
> +
> +struct ac97_controller {
> +     const struct ac97_controller_ops *ops;
> +     struct list_head controllers;
> +     struct device *dev;
> +     int bus_idx;

What is this bus_idx for?


> +     int bound_codecs;
> +     struct list_head codecs;
> +};
> +
> +int ac97_digital_controller_register(const struct ac97_controller_ops *ops,
> +                                  struct device *dev);
> +int ac97_digital_controller_unregister(const struct device *dev);
> +
> +#endif
> diff --git a/sound/ac97/Kconfig b/sound/ac97/Kconfig
> new file mode 100644
> index 000000000000..fd2c2d031e62
> --- /dev/null
> +++ b/sound/ac97/Kconfig
> @@ -0,0 +1,9 @@
> +#
> +# PCI configuration
> +#
 
Still only for PCI? :)


> +
> +config AC97
> +     bool "AC97 bus"
> +     help
> +        Say Y here if you want to have AC97 devices, which are sound oriented
> +        devices around an AC-Link.
> diff --git a/sound/ac97/Makefile b/sound/ac97/Makefile
> new file mode 100644
> index 000000000000..5575909d46e2
> --- /dev/null
> +++ b/sound/ac97/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# make for AC97 bus drivers
> +#
> +
> +obj-y        += bus.o codec.o snd_ac97_compat.o

No possibility for modules?


> diff --git a/sound/ac97/ac97_core.h b/sound/ac97/ac97_core.h
> new file mode 100644
> index 000000000000..db6e27288357
> --- /dev/null
> +++ b/sound/ac97/ac97_core.h
> @@ -0,0 +1,10 @@
> +/*
> + * Copyright (C) 2016 Robert Jarzmik <robert.jarz...@free.fr>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +unsigned int ac97_bus_scan_one(struct ac97_controller *ac97,
> +                            int codec_num);
> diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
> new file mode 100644
> index 000000000000..f9bf5632d4aa
> --- /dev/null
> +++ b/sound/ac97/bus.c
> @@ -0,0 +1,330 @@
> +/*
> + * Copyright (C) 2016 Robert Jarzmik <robert.jarz...@free.fr>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/pm.h>
> +#include <linux/slab.h>
> +#include <sound/ac97/codec.h>
> +#include <sound/ac97/controller.h>
> +#include <sound/ac97/regs.h>
> +
> +#define AC97_BUS_MAX_CODECS 4
> +
> +/*
> + * Protects ac97_controllers and each ac97_controller structure.
> + */
> +static DEFINE_MUTEX(ac97_controllers_mutex);
> +static LIST_HEAD(ac97_controllers);
> +static int ac97_bus_idx;
> +
> +struct bus_type ac97_bus_type;
> +
> +static struct ac97_codec_device *
> +ac97_codec_find(struct ac97_controller *ac97_ctrl, int codec_num)
> +{
> +     struct ac97_codec_device *codec;
> +
> +     list_for_each_entry(codec, &ac97_ctrl->codecs, list)
> +             if (codec->num == codec_num)
> +                     return codec;
> +
> +     return NULL;
> +}

It's a question whether we need to manage the codecs in the linked
list.  There can be at most 4 codecs, so it fits in an array well,
too.  Then some codes like this would be simpler. (And it'll even
reduce the footprint, too.)


> +
> +static void ac97_codec_release(struct device *dev)
> +{
> +     struct ac97_codec_device *codec;
> +
> +     codec = container_of(dev, struct ac97_codec_device, dev);
> +     list_del(&codec->list);
> +     kfree(codec);
> +}
> +
> +static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
> +                unsigned int vendor_id)
> +{
> +     struct ac97_codec_device *codec;
> +     char *codec_name;
> +     int ret;
> +
> +     codec = kzalloc(sizeof(*codec), GFP_KERNEL);
> +     if (!codec)
> +             return -ENOMEM;
> +
> +     codec->vendor_id = vendor_id;
> +     codec->dev.release = ac97_codec_release;
> +     codec->dev.bus = &ac97_bus_type;
> +     codec->dev.parent = ac97_ctrl->dev;
> +     codec->num = idx;
> +     codec->ac97_ctrl = ac97_ctrl;
> +     INIT_LIST_HEAD(&codec->list);
> +     list_move_tail(&codec->list, &ac97_ctrl->codecs);
> +
> +     codec_name = kasprintf(GFP_KERNEL, "%s:%d", dev_name(ac97_ctrl->dev),
> +                            idx);
> +     codec->dev.init_name = codec_name;
> +
> +     ret = device_register(&codec->dev);
> +     kfree(codec_name);
> +
> +     return ret;
> +}
> +
> +unsigned int ac97_bus_scan_one(struct ac97_controller *ac97,
> +                                   int codec_num)
> +{
> +     struct ac97_codec_device codec;
> +     unsigned short vid1, vid2;
> +     int ret;
> +
> +     codec.dev = *ac97->dev;
> +     codec.num = codec_num;
> +     ret = ac97->ops->read(&codec, AC97_VENDOR_ID1);
> +     vid1 = (ret & 0xffff);
> +     if (ret < 0)
> +             return 0;

Hmm.  This looks pretty hackish and dangerous.



> +     ret = ac97->ops->read(&codec, AC97_VENDOR_ID2);
> +     vid2 = (ret & 0xffff);
> +     if (ret < 0)
> +             return 0;
> +
> +     dev_dbg(&codec.dev, "%s(codec_num=%d): vendor_id=0x%08x\n",
> +             __func__, codec_num, AC97_ID(vid1, vid2));
> +     return AC97_ID(vid1, vid2);
> +}
> +
> +static int ac97_bus_scan(struct ac97_controller *ac97_ctrl)
> +{
> +     int ret, i;
> +     unsigned int vendor_id;
> +
> +     for (i = 0; i < AC97_BUS_MAX_CODECS; i++) {
> +             if (ac97_codec_find(ac97_ctrl, i))
> +                     continue;
> +             vendor_id = ac97_bus_scan_one(ac97_ctrl, i);
> +             if (!vendor_id)
> +                     continue;
> +
> +             ret = ac97_codec_add(ac97_ctrl, i, vendor_id);
> +             if (ret < 0)
> +                     return ret;

This is one of concerns: we don't know whether the device really
reacts well if you access to a non-existing slot.  At least, it'd be
safer to have the masks for the devices we already know the slots.


> +     }
> +     return 0;
> +}
> +
> +void ac97_rescan_all_controllers(void)
> +{
> +     struct ac97_controller *ac97_ctrl;
> +     int ret;
> +
> +     mutex_lock(&ac97_controllers_mutex);
> +     list_for_each_entry(ac97_ctrl, &ac97_controllers, controllers) {
> +             ret = ac97_bus_scan(ac97_ctrl);
> +             if (ret)
> +                     dev_warn(ac97_ctrl->dev, "scan failed: %d\n", ret);
> +     }
> +     mutex_unlock(&ac97_controllers_mutex);
> +}
> +EXPORT_SYMBOL(ac97_rescan_all_controllers);
> +
> +static int ac97_bus_reset(struct ac97_controller *ac97_ctrl)
> +{
> +     struct ac97_codec_device codec;
> +
> +     memset(&codec, 0, sizeof(codec));
> +     codec.dev = *ac97_ctrl->dev;
> +
> +     ac97_ctrl->ops->reset(&codec);

So, this assumes that reset ops is mandatory?  Then document it at
least.


thanks,

Takashi

> +     return 0;
> +}
> +
> +/**
> + * ac97_codec_driver_register - register an AC97 codec driver
> + * @dev: AC97 driver codec to register
> + *
> + * Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 
> digital
> + * controller.
> + *
> + * Returns 0 on success or error code
> + */
> +int ac97_codec_driver_register(struct ac97_codec_driver *drv)
> +{
> +     int ret;
> +
> +     drv->driver.bus = &ac97_bus_type;
> +
> +     ret = driver_register(&drv->driver);
> +     if (!ret)
> +             ac97_rescan_all_controllers();
> +
> +     return ret;
> +}
> +EXPORT_SYMBOL(ac97_codec_driver_register);
> +
> +/**
> + * ac97_codec_driver_unregister - unregister an AC97 codec driver
> + * @dev: AC97 codec driver to unregister
> + *
> + * Unregister a previously registered ac97 codec driver.
> + */
> +void ac97_codec_driver_unregister(struct ac97_codec_driver *drv)
> +{
> +     driver_unregister(&drv->driver);
> +}
> +EXPORT_SYMBOL(ac97_codec_driver_unregister);
> +
> +static int ac97_dc_codecs_unregister(struct ac97_controller *ac97_ctrl)
> +{
> +     struct ac97_codec_device *codec, *tmp;
> +
> +     list_for_each_entry_safe(codec, tmp, &ac97_ctrl->codecs, list)
> +             put_device(&codec->dev);
> +
> +     return 0;
> +}
> +
> +/**
> + * ac97_digital_controller_register - register an ac97 controller
> + * @ops: the ac97 bus operations
> + * @dev: the device providing the ac97 DC function
> + *
> + * Register a digital controller which can control up to 4 ac97 codecs. This 
> is
> + * the controller side of the AC97 AC-link, while the slave side are the 
> codecs.
> + *
> + * Returns a positive bus index upon success, negative value upon error
> + */
> +int ac97_digital_controller_register(const struct ac97_controller_ops *ops,
> +                                  struct device *dev)
> +{
> +     struct ac97_controller *ac97_ctrl;
> +
> +     ac97_ctrl = kzalloc(sizeof(*ac97_ctrl), GFP_KERNEL);
> +     if (!ac97_ctrl)
> +             return -ENOMEM;
> +
> +     mutex_lock(&ac97_controllers_mutex);
> +     ac97_ctrl->ops = ops;
> +     ac97_ctrl->bus_idx = ac97_bus_idx++;
> +     ac97_ctrl->dev = dev;
> +     INIT_LIST_HEAD(&ac97_ctrl->codecs);
> +     list_add(&ac97_ctrl->controllers, &ac97_controllers);
> +     mutex_unlock(&ac97_controllers_mutex);
> +
> +     ac97_bus_reset(ac97_ctrl);
> +     ac97_bus_scan(ac97_ctrl);
> +
> +     return ac97_ctrl->bus_idx;
> +}
> +EXPORT_SYMBOL(ac97_digital_controller_register);
> +
> +/**
> + * ac97_digital_controller_unregister - unregister an ac97 controller
> + * @dev: the device previously provided to ac97_digital_controller_register()
> + *
> + * Returns 0 on success, negative upon error
> + */
> +int ac97_digital_controller_unregister(const struct device *dev)
> +{
> +     struct ac97_controller *ac97_ctrl, *tmp;
> +     int ret = -ENODEV;
> +
> +     mutex_lock(&ac97_controllers_mutex);
> +     list_for_each_entry_safe(ac97_ctrl, tmp, &ac97_controllers,
> +                              controllers) {
> +             if (ac97_ctrl->dev != dev)
> +                     continue;
> +             if (ac97_ctrl->bound_codecs)
> +                     ret = -EBUSY;
> +             else
> +                     ret = ac97_dc_codecs_unregister(ac97_ctrl);
> +             if (!ret)
> +                     list_del(&ac97_ctrl->controllers);
> +     }
> +
> +     mutex_unlock(&ac97_controllers_mutex);
> +     return ret;
> +}
> +EXPORT_SYMBOL(ac97_digital_controller_unregister);
> +
> +static const struct dev_pm_ops ac97_pm = {
> +     .suspend        = pm_generic_suspend,
> +     .resume         = pm_generic_resume,
> +     .freeze         = pm_generic_freeze,
> +     .thaw           = pm_generic_thaw,
> +     .poweroff       = pm_generic_poweroff,
> +     .restore        = pm_generic_restore,
> +};
> +
> +static ssize_t vendor_id_show(struct device *dev,
> +                           struct device_attribute *attr, char *buf)
> +{
> +     struct ac97_codec_device *codec = to_ac97_device(dev);
> +
> +     return sprintf(buf, "%08x", codec->vendor_id);
> +}
> +
> +static struct device_attribute ac97_dev_attrs[] = {
> +     __ATTR_RO(vendor_id),
> +     __ATTR_NULL,
> +};
> +
> +int ac97_bus_match(struct device *dev, struct device_driver *drv)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(dev);
> +     struct ac97_codec_driver *adrv = to_ac97_driver(drv);
> +     struct ac97_id *id = adrv->id_table;
> +
> +     if (adev->vendor_id == 0x0 || adev->vendor_id == 0xffffffff)
> +             return false;
> +
> +     do {
> +             if ((id->id & id->mask) == (adev->vendor_id & id->mask))
> +                     return true;
> +     } while (++id->id);
> +
> +     return false;
> +}
> +
> +static int ac97_bus_probe(struct device *dev)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(dev);
> +     struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
> +
> +     return adrv->probe(adev);
> +}
> +
> +static int ac97_bus_remove(struct device *dev)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(dev);
> +     struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
> +
> +     return adrv->remove(adev);
> +}
> +
> +struct bus_type ac97_bus_type = {
> +     .name           = "ac97",
> +     .dev_attrs      = ac97_dev_attrs,
> +     .match          = ac97_bus_match,
> +     .pm             = &ac97_pm,
> +     .probe          = ac97_bus_probe,
> +     .remove         = ac97_bus_remove,
> +};
> +EXPORT_SYMBOL(ac97_bus_type);
> +
> +static int __init ac97_bus_init(void)
> +{
> +     return bus_register(&ac97_bus_type);
> +}
> +subsys_initcall(ac97_bus_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Robert Jarzmik <robert.jarz...@free.fr>");
> diff --git a/sound/ac97/codec.c b/sound/ac97/codec.c
> new file mode 100644
> index 000000000000..a835f03744bf
> --- /dev/null
> +++ b/sound/ac97/codec.c
> @@ -0,0 +1,15 @@
> +/*
> + *  Copyright (C) 2016 Robert Jarzmik <robert.jarz...@free.fr>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <sound/ac97_codec.h>
> +#include <sound/ac97/codec.h>
> +#include <sound/ac97/controller.h>
> +#include <linux/device.h>
> +#include <linux/slab.h>
> +#include <sound/soc.h>       /* For compat_ac97_* */
> +
> diff --git a/sound/ac97/snd_ac97_compat.c b/sound/ac97/snd_ac97_compat.c
> new file mode 100644
> index 000000000000..7e2f01c96fc9
> --- /dev/null
> +++ b/sound/ac97/snd_ac97_compat.c
> @@ -0,0 +1,104 @@
> +/*
> + *  Copyright (C) 2016 Robert Jarzmik <robert.jarz...@free.fr>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/list.h>
> +#include <linux/slab.h>
> +#include <sound/ac97/codec.h>
> +#include <sound/ac97/controller.h>
> +#include <sound/soc.h>
> +
> +#include "ac97_core.h"
> +
> +static void compat_ac97_reset(struct snd_ac97 *ac97)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
> +     struct ac97_controller *actrl = adev->ac97_ctrl;
> +
> +     if (actrl->ops->reset)
> +             actrl->ops->reset(adev);
> +}
> +
> +static void compat_ac97_warm_reset(struct snd_ac97 *ac97)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
> +     struct ac97_controller *actrl = adev->ac97_ctrl;
> +
> +     if (actrl->ops->warm_reset)
> +             actrl->ops->warm_reset(adev);
> +}
> +
> +static void compat_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
> +                           unsigned short val)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
> +     struct ac97_controller *actrl = adev->ac97_ctrl;
> +
> +     actrl->ops->write(adev, reg, val);
> +}
> +
> +static unsigned short compat_ac97_read(struct snd_ac97 *ac97,
> +                                    unsigned short reg)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
> +     struct ac97_controller *actrl = adev->ac97_ctrl;
> +
> +     return actrl->ops->read(adev, reg);
> +}
> +
> +static struct snd_ac97_bus_ops compat_snd_ac97_bus_ops = {
> +     .reset = compat_ac97_reset,
> +     .warm_reset = compat_ac97_warm_reset,
> +     .write = compat_ac97_write,
> +     .read = compat_ac97_read,
> +};
> +
> +static struct snd_ac97_bus compat_soc_ac97_bus = {
> +     .ops = &compat_snd_ac97_bus_ops,
> +};
> +
> +struct snd_ac97 *compat_alloc_snd_ac97_codec(struct snd_soc_codec *codec)
> +{
> +     struct snd_ac97 *ac97;
> +
> +     ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
> +     if (ac97 == NULL)
> +             return ERR_PTR(-ENOMEM);
> +
> +     ac97->dev = *codec->dev;
> +     ac97->private_data = codec->dev;
> +     ac97->bus = &compat_soc_ac97_bus;
> +     return ac97;
> +}
> +EXPORT_SYMBOL_GPL(compat_alloc_snd_ac97_codec);
> +
> +void compat_release_snd_ac97_codec(struct snd_ac97 *ac97)
> +{
> +     kfree(ac97);
> +}
> +EXPORT_SYMBOL_GPL(compat_release_snd_ac97_codec);
> +
> +int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
> +     unsigned int id_mask)
> +{
> +     struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
> +     struct ac97_controller *actrl = adev->ac97_ctrl;
> +
> +     if (try_warm) {
> +             compat_ac97_warm_reset(ac97);
> +             if (ac97_bus_scan_one(actrl, adev->num) == adev->vendor_id)
> +                     return 1;
> +     }
> +
> +     compat_ac97_reset(ac97);
> +     compat_ac97_warm_reset(ac97);
> +     if (ac97_bus_scan_one(actrl, adev->num) == adev->vendor_id)
> +             return 0;
> +
> +     return -ENODEV;
> +}
> +EXPORT_SYMBOL_GPL(snd_ac97_reset);
> -- 
> 2.1.4
> 
> 

Reply via email to