[alsa-devel] [PATCH 0/4] ALSA: hdac: add codec driver support
This patch adds the core framework support for adding hdac extended devices and drivers. We introduce a minimal hdac extended device and driver and APIs for registration This series also ads extended device cleanup API and refresh sysfs tree API
Vinod Koul (4): ALSA: hdac: Add API for removing hdac extended device ALSA: hdac: add hdac extended device ALSA: hdac: add extended device driver registration ALSA: hdac: add snd_hdac_refresh_widget_sysfs()
include/sound/hdaudio.h | 1 + include/sound/hdaudio_ext.h | 60 +++++++++++++++++++++++++++ sound/hda/ext/hdac_ext_bus.c | 98 ++++++++++++++++++++++++++++++++++++++++++-- sound/hda/hdac_device.c | 28 +++++++++++++ 4 files changed, 183 insertions(+), 4 deletions(-)
The HDAC extended device objects are created by HDAC extended bus on probe. When controller is removed they should be removed as well, so add API snd_hdac_ext_bus_device_remove for this
Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hdaudio_ext.h | 1 + sound/hda/ext/hdac_ext_bus.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+)
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 0f89df1511dc..148267b76ab7 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -34,6 +34,7 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev, void snd_hdac_ext_bus_exit(struct hdac_ext_bus *sbus); int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *sbus, int addr); void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev); +void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
#define ebus_to_hbus(ebus) (&(ebus)->bus) #define hbus_to_ebus(_bus) \ diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 0aa5d9eb6c3f..cf69202f7da0 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -172,3 +172,22 @@ void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev) kfree(hdev); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit); + +/** + * snd_hdac_ext_bus_device_remove - remove HD-audio extended codec base devices + * + * @ebus: HD-audio extended bus + */ +void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus) +{ + struct hdac_device *codec, *__codec; + /* + * we need to remove all the codec devices objects created in the + * snd_hdac_ext_bus_device_init + */ + list_for_each_entry_safe(codec, __codec, &ebus->bus.codec_list, list) { + snd_hdac_device_unregister(codec); + put_device(&codec->dev); + } +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
This adds based hdac extended device object which will be used by ASoC HDAC codecs
Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hdaudio_ext.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ sound/hda/ext/hdac_ext_bus.c | 13 +++++++++---- 2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 148267b76ab7..0641d00e2a94 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -130,4 +130,48 @@ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, writew(((readw(addr + reg) & ~(mask)) | (val)), \ addr + reg)
+ +struct hdac_ext_device; + +/* ops common to all codec drivers */ +struct hdac_ext_codec_ops { + int (*build_controls)(struct hdac_ext_device *dev); + int (*init)(struct hdac_ext_device *dev); + void (*free)(struct hdac_ext_device *dev); +}; + +struct hda_dai_map { + char *dai_name; + hda_nid_t nid; + u32 maxbps; +}; + +#define HDA_MAX_NIDS 16 + +/** + * struct hdac_ext_device - HDAC Ext device + * + * @hdac: hdac core device + * @nid_list - the dai map which matches the dai-name with the nid + * @map_cur_idx - the idx in use in dai_map + * @ops - the hda codec ops common to all codec drivers + * @pvt_data - private data, for asoc contains asoc codec object + */ +struct hdac_ext_device { + struct hdac_device hdac; + struct hdac_ext_bus *ebus; + + /* soc-dai to nid map */ + struct hda_dai_map nid_list[HDA_MAX_NIDS]; + unsigned int map_cur_idx; + + /* codec ops */ + struct hdac_ext_codec_ops ops; + + void *private_data; +}; + +#define to_ehdac_device(dev) (container_of((dev), \ + struct hdac_ext_device, hdac)) + #endif /* __SOUND_HDAUDIO_EXT_H */ diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index cf69202f7da0..94fb9878f5cb 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -125,7 +125,7 @@ static void default_release(struct device *dev) }
/** - * snd_hdac_ext_device_init - initialize the HDA extended codec base device + * snd_hdac_ext_bus_device_init - initialize the HDA extended codec base device * @ebus: hdac extended bus to attach to * @addr: codec address * @@ -133,14 +133,16 @@ static void default_release(struct device *dev) */ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr) { + struct hdac_ext_device *edev; struct hdac_device *hdev = NULL; struct hdac_bus *bus = ebus_to_hbus(ebus); char name[15]; int ret;
- hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); - if (!hdev) + edev = kzalloc(sizeof(*hdev), GFP_KERNEL); + if (!edev) return -ENOMEM; + hdev = &edev->hdac;
snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
@@ -158,6 +160,7 @@ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr) snd_hdac_ext_bus_device_exit(hdev); return ret; } + return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init); @@ -168,8 +171,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init); */ void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev) { + struct hdac_ext_device *edev = to_ehdac_device(hdev); + snd_hdac_device_exit(hdev); - kfree(hdev); + kfree(edev); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
This adds new extended driver objects and API for registering the extended devices.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hdaudio_ext.h | 15 ++++++++++ sound/hda/ext/hdac_ext_bus.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 0641d00e2a94..55e2fc36177f 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -173,5 +173,20 @@ struct hdac_ext_device {
#define to_ehdac_device(dev) (container_of((dev), \ struct hdac_ext_device, hdac)) +/* + * HD-audio codec base driver + */ +struct hdac_ext_driver { + struct hdac_driver hdac; + + int (*probe)(struct hdac_ext_device *dev); + int (*remove)(struct hdac_ext_device *dev); + void (*shutdown)(struct hdac_ext_device *dev); +}; + +int snd_hda_ext_driver_register(struct hdac_ext_driver *drv); +void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv); + +#define to_ehdac_driver(_drv) container_of(_drv, struct hdac_ext_driver, hdac)
#endif /* __SOUND_HDAUDIO_EXT_H */ diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 94fb9878f5cb..8544e4fb1cd3 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -196,3 +196,69 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus) } } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove); +#define dev_to_hdac(dev) (container_of((dev), \ + struct hdac_device, dev)) + +static inline struct hdac_ext_driver *get_edrv(struct device *dev) +{ + struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver); + struct hdac_ext_driver *edrv = to_ehdac_driver(hdrv); + + return edrv; +} + +static inline struct hdac_ext_device *get_edev(struct device *dev) +{ + struct hdac_device *hdev = dev_to_hdac_dev(dev); + struct hdac_ext_device *edev = to_ehdac_device(hdev); + + return edev; +} + +static int hda_ext_drv_probe(struct device *dev) +{ + return (get_edrv(dev))->probe(get_edev(dev)); +} + +static int hdac_ext_drv_remove(struct device *dev) +{ + return (get_edrv(dev))->remove(get_edev(dev)); +} + +static void hdac_ext_drv_shutdown(struct device *dev) +{ + return (get_edrv(dev))->shutdown(get_edev(dev)); +} + +/** + * snd_hda_ext_driver_register - register a driver for ext hda devices + * + * @drv: ext hda driver structure + */ +int snd_hda_ext_driver_register(struct hdac_ext_driver *drv) +{ + drv->hdac.type = HDA_DEV_ASOC; + drv->hdac.driver.bus = &snd_hda_bus_type; + /* we use default match */ + + if (drv->probe) + drv->hdac.driver.probe = hda_ext_drv_probe; + if (drv->remove) + drv->hdac.driver.remove = hdac_ext_drv_remove; + if (drv->shutdown) + drv->hdac.driver.shutdown = hdac_ext_drv_shutdown; + + return driver_register(&drv->hdac.driver); +} +EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register); + +/** + * snd_hda_ext_driver_unregister - unregister a driver for ext hda devices + * + * @drv: ext hda driver structure + */ +void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv) +{ + driver_unregister(&drv->hdac.driver); +} +EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);
Some codecs like Intel HDMI by default do not show up all the pins, they have to be manually enabled, so we need to refresh the codec widgets and then recreate the sysfs tree. So add new API snd_hdac_refresh_widget_sysfs() to do this. It should be be used by codec driver after sending magic verbs to codec
Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hdaudio.h | 1 + sound/hda/hdac_device.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+)
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 4caf1fde8a4f..e37c3355ae8a 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -119,6 +119,7 @@ int snd_hdac_device_register(struct hdac_device *codec); void snd_hdac_device_unregister(struct hdac_device *codec);
int snd_hdac_refresh_widgets(struct hdac_device *codec); +int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec);
unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, unsigned int verb, unsigned int parm); diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index cdee7103f649..8abba3f85784 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -372,6 +372,34 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec) } EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
+/** + * snd_hdac_refresh_widget_sysfs - Reset the codec widgets and reinit the + * codec sysfs + * @codec: the codec object + * + * first we need to remove sysfs, then refresh widgets and lastly + * recreate it + */ +int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec) +{ + int ret; + + hda_widget_sysfs_exit(codec); + ret = snd_hdac_refresh_widgets(codec); + if (ret) { + dev_err(&codec->dev, "failed to refresh widget: %d\n", ret); + return ret; + } + ret = hda_widget_sysfs_init(codec); + if (ret) { + dev_err(&codec->dev, "failed to init sysfs: %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_hdac_refresh_widget_sysfs); + /* return CONNLIST_LEN parameter of the given widget */ static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) {
On Fri, 21 Aug 2015 12:17:39 +0200, Vinod Koul wrote:
This patch adds the core framework support for adding hdac extended devices and drivers. We introduce a minimal hdac extended device and driver and APIs for registration This series also ads extended device cleanup API and refresh sysfs tree API
Vinod Koul (4): ALSA: hdac: Add API for removing hdac extended device ALSA: hdac: add hdac extended device ALSA: hdac: add extended device driver registration ALSA: hdac: add snd_hdac_refresh_widget_sysfs()
I applied them now, but the last patch had trivial coding style problems. Please do run checkpatch.pl once before submission at the next time.
thanks,
Takashi
include/sound/hdaudio.h | 1 + include/sound/hdaudio_ext.h | 60 +++++++++++++++++++++++++++ sound/hda/ext/hdac_ext_bus.c | 98 ++++++++++++++++++++++++++++++++++++++++++-- sound/hda/hdac_device.c | 28 +++++++++++++ 4 files changed, 183 insertions(+), 4 deletions(-)
-- 1.9.1
On Fri, Aug 21, 2015 at 12:37:24PM +0200, Takashi Iwai wrote:
On Fri, 21 Aug 2015 12:17:39 +0200, Vinod Koul wrote:
This patch adds the core framework support for adding hdac extended devices and drivers. We introduce a minimal hdac extended device and driver and APIs for registration This series also ads extended device cleanup API and refresh sysfs tree API
Vinod Koul (4): ALSA: hdac: Add API for removing hdac extended device ALSA: hdac: add hdac extended device ALSA: hdac: add extended device driver registration ALSA: hdac: add snd_hdac_refresh_widget_sysfs()
I applied them now, but the last patch had trivial coding style problems. Please do run checkpatch.pl once before submission at the next time.
Thanks a bunch, I usually do run it but missed it this time. my bad :(
participants (2)
-
Takashi Iwai
-
Vinod Koul