aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-03-16 14:41:33 +0100
committerTakashi Iwai <tiwai@suse.de>2015-03-16 14:43:29 +0100
commit047aa0ea8e65d07c321e895b11d5f92c12ddc02f (patch)
treee2ed7153f712b3be75a028c22b5cef4e933b6421
parent512deee4523161571e723a565d9c0123635765da (diff)
downloadhda-emu-047aa0ea8e65d07c321e895b11d5f92c12ddc02f.tar.gz
Support for the new HD-audio infrastructure for 4.1 kernel
The HD-audio driver is now using the standard bus to bind with devices, and there have been a lot of code changes along with it. Adapt hda-emu to follow the changes. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--configure.ac50
-rw-r--r--hda-emu.c114
-rw-r--r--include/linux/atomic.h19
-rw-r--r--include/linux/device.h63
-rw-r--r--include/linux/kref.h24
-rw-r--r--include/linux/pm.h24
-rw-r--r--include/linux/pm_runtime.h23
-rw-r--r--include/sound/core.h15
-rw-r--r--include/sound/pcm.h3
-rw-r--r--include/wrapper.h40
-rw-r--r--kernel/Makefile.am4
-rw-r--r--kernel/hda_bind.c1
-rw-r--r--snd-wrapper.c134
13 files changed, 453 insertions, 61 deletions
diff --git a/configure.ac b/configure.ac
index 5d10a64..9a75225 100644
--- a/configure.ac
+++ b/configure.ac
@@ -110,6 +110,7 @@ CHECK_HELPER([hda_auto_parser.c], [HAVE_HDA_AUTO_PARSER])
CHECK_HELPER([hda_jack.c], [HAVE_HDA_JACK])
CHECK_HELPER([hda_eld.c], [HAVE_HDA_ELD])
CHECK_HELPER([hda_beep.c], [HAVE_HDA_BEEP])
+CHECK_HELPER([hda_bind.c], [HAVE_HDA_BIND])
AC_ARG_ENABLE(own-proc,
AS_HELP_STRING([--enable-own-proc],
@@ -119,11 +120,23 @@ AM_CONDITIONAL(USE_OWN_PROC, test "$own_proc" = "yes")
echo "Generating kernel/init_hooks.h..."
rm -f kernel/init_hooks.h
+if test -f hda/hda_bind.c; then
+cat hda/hda_bind.c | grep '^module_init(' | \
+ sed -e's/^module_init(\(.*\))/void call_init_\1(void);/g' >> kernel/init_hooks.h
+fi
cat hda/patch_*.c | grep '^module_init(' | \
- sed -e's/^module_init(\(.*\))/void call_init_\1(void);/g' > kernel/init_hooks.h
+ sed -e's/^module_init(\(.*\))/void call_init_\1(void);/g' >> kernel/init_hooks.h
+cat hda/patch_*.c | grep '^module_hda_codec_driver(' | \
+ sed -e's/^module_hda_codec_driver(\(.*\))/void call_init_\1_init(void);/g' >> kernel/init_hooks.h
echo 'static void gather_codec_hooks(void) {' >> kernel/init_hooks.h
+if test -f hda/hda_bind.c; then
+cat hda/hda_bind.c | grep '^module_init(' | \
+ sed -e's/^module_init(\(.*\))/call_init_\1();/g' >> kernel/init_hooks.h
+fi
cat hda/patch_*.c | grep '^module_init(' | \
sed -e's/^module_init(\(.*\))/call_init_\1();/g' >> kernel/init_hooks.h
+cat hda/patch_*.c | grep '^module_hda_codec_driver(' | \
+ sed -e's/^module_hda_codec_driver(\(.*\))/call_init_\1_init();/g' >> kernel/init_hooks.h
echo '}' >> kernel/init_hooks.h
AC_MSG_CHECKING(for presence of power_save option)
@@ -153,6 +166,18 @@ if test "$OLD_POWER_SAVE" = "1"; then
fi
fi
+NEW_HDA_INFRA=
+AC_MSG_CHECKING(for new hda structure)
+if grep -q hda_bus_template hda/hda_codec.h; then
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ NEW_HDA_INFRA=yes
+fi
+if test "$NEW_HDA_INFRA" = "yes"; then
+ AC_DEFINE(NEW_HDA_INFRA)
+fi
+
AC_MSG_CHECKING(for old bus callbacks)
ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Iinclude"
@@ -251,6 +276,13 @@ if test "$HAVE_GET_RESPONSE_WITH_CADDR" = "1"; then
fi
fi # HAVE_HDA_ATTACH_PCM=1
+if test "$NEW_HDA_INFRA" = "yes"; then
+
+AC_DEFINE(CONFIG_SND_HDA_RECONFIG)
+AC_DEFINE(HAVE_HDA_PATCH_LOADER)
+
+else
+
AC_MSG_CHECKING(for old snd_hda_codec_new)
ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Iinclude"
@@ -289,6 +321,8 @@ if test "$HAVE_HDA_PATCH_LOADER" = "yes"; then
AC_DEFINE(HAVE_HDA_PATCH_LOADER)
fi
+fi # NEW_HDA_INFRA
+
AC_MSG_CHECKING(for new HDA PCM)
ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Iinclude"
@@ -405,6 +439,7 @@ if test "$HAVE_BOOLEAN_INFO" = "1"; then
AC_DEFINE(HAVE_BOOLEAN_INFO)
fi
+if test "$NEW_HDA_INFRA" != "yes"; then
AC_MSG_CHECKING(for snd_hda_suspend with pmsg)
ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Iinclude"
@@ -427,6 +462,7 @@ CFLAGS=$ac_save_CFLAGS
if test "$HAVE_HDA_SUSPEND_PMSG" = "1"; then
AC_DEFINE(HAVE_HDA_SUSPEND_PMSG)
fi
+fi # !NEW_HDA_INFRA
HAVE_SND_HDA_JACK=
AC_MSG_CHECKING(for snd_hda_jack_xxx)
@@ -547,17 +583,5 @@ if test "$HAVE_CODEC_USER_MUTEX" = "1"; then
AC_DEFINE(HAVE_CODEC_USER_MUTEX)
fi
-HAVE_HDA_BUS_TEMPLATE=
-AC_MSG_CHECKING(for hda_bus_template)
-if grep -q hda_bus_template hda/hda_codec.h; then
- AC_MSG_RESULT(yes)
- HAVE_HDA_BUS_TEMPLATE=yes
-else
- AC_MSG_RESULT(no)
-fi
-if test "$HAVE_HDA_BUS_TEMPLATE" = "yes"; then
- AC_DEFINE(HAVE_HDA_BUS_TEMPLATE)
-fi
-
AC_OUTPUT(Makefile kernel/Makefile include/Makefile)
diff --git a/hda-emu.c b/hda-emu.c
index 96a82d8..7a90dd9 100644
--- a/hda-emu.c
+++ b/hda-emu.c
@@ -60,6 +60,8 @@ static struct snd_card card = {
};
static struct xhda_codec proc;
+static struct hda_bus *bus;
+
static struct hda_codec *_codec;
static int ignore_invalid_ftype;
@@ -196,11 +198,15 @@ int hda_get_power_save(void)
void hda_set_power_save(int val)
{
+#ifdef NEW_HDA_INFRA
+ snd_hda_set_power_save(bus, val * 1000);
+#else /* !NEW_HDA_INFRA */
#ifdef HDA_OLD_POWER_SAVE
*power_save_parameter = val;
#else
power_save = val;
#endif
+#endif /* NEW_HDA_INFRA */
}
/*
@@ -404,20 +410,30 @@ void hda_log_issue_unsol(int nid)
* suspend/resume simulation
*/
-static struct hda_bus *bus;
-
void hda_test_suspend(void)
{
+#ifdef NEW_HDA_INFRA
+ struct device *dev = hda_codec_dev(_codec);
+ if (dev->driver && dev->driver->pm)
+ dev->driver->pm->suspend(dev);
+#else /* !NEW_HDA_INFRA */
#ifdef HAVE_HDA_SUSPEND_PMSG
snd_hda_suspend(bus, PMSG_SUSPEND);
#else
snd_hda_suspend(bus);
#endif
+#endif /* NEW_HDA_INFRA */
}
void hda_test_resume(void)
{
+#ifdef NEW_HDA_INFRA
+ struct device *dev = hda_codec_dev(_codec);
+ if (dev->driver && dev->driver->pm)
+ dev->driver->pm->resume(dev);
+#else /* !NEW_HDA_INFRA */
snd_hda_resume(bus);
+#endif /* NEW_HDA_INFRA */
}
static inline unsigned int random_bit(unsigned int pincap, unsigned int mask,
@@ -523,12 +539,14 @@ int hda_codec_reconfig(void)
err = snd_hda_codec_configure(_codec);
if (err < 0)
goto error;
+#ifndef NEW_HDA_INFRA
/* rebuild PCMs */
err = snd_hda_build_pcms(bus);
if (err < 0)
goto error;
/* rebuild mixers */
err = snd_hda_codec_build_controls(_codec);
+#endif /* !NEW_HDA_INFRA */
error:
snd_hda_power_down(_codec);
return err;
@@ -936,6 +954,7 @@ static int azx_pcm_create(struct hda_codec *codec)
* power management
*/
+#ifndef NEW_HDA_INFRA
#ifdef HAVE_NEW_PM_NOTIFY
static void new_pm_notify(struct hda_bus *bus, bool power_up)
{
@@ -955,6 +974,7 @@ static void old_pm_notify(struct hda_codec *codec)
}
#endif
#endif /* HAVE_NEW_PM_NOTIFY */
+#endif /* !NEW_HDA_INFRA */
/*
@@ -1281,14 +1301,44 @@ static FILE *file_open(const char *fname)
return fopen(fname, "r");
}
-#ifndef HAVE_HDA_BUS_TEMPLATE
+#ifdef NEW_HDA_INFRA
static struct hda_bus_ops bus_ops = {
.command = cmd_send,
.get_response = resp_get_caddr,
.attach_pcm = attach_pcm,
- .pm_notify = new_pm_notify,
};
-#endif /* HAVE_HDA_BUS_TEMPLATE */
+#else /* !NEW_HDA_INFRA */
+static void setup_bus_template(struct hda_bus_template *temp)
+{
+#ifdef HAVE_POWER_SAVE
+#ifndef OLD_POWER_SAVE
+ temp->power_save = &power_save;
+#endif
+#endif
+#ifdef OLD_HDA_CMD
+ temp->ops.command = old_cmd_send;
+ temp->ops.get_response = old_resp_get;
+#ifdef HAVE_POWER_SAVE
+ temp->ops.pm_notify = old_pm_notify;
+#endif
+#else /* !OLD_HDA_CMD */
+ temp.ops.command = cmd_send;
+#ifdef HAVE_GET_RESPONSE_WITH_CADDR
+ temp->ops.get_response = resp_get_caddr;
+#else
+ temp->ops.get_response = resp_get;
+#endif
+#ifdef HAVE_HDA_ATTACH_PCM
+ temp->ops.attach_pcm = attach_pcm;
+#endif
+#ifdef HAVE_NEW_PM_NOTIFY
+ temp->ops.pm_notify = new_pm_notify;
+#else
+ temp->ops.pm_notify = pm_notify;
+#endif
+#endif /* OLD_HDA_CMD */
+}
+#endif /* NEW_HDA_INFRA */
int main(int argc, char **argv)
{
@@ -1301,7 +1351,7 @@ int main(int argc, char **argv)
char *logfile = NULL;
unsigned int log_flags = HDA_LOG_FLAG_COLOR;
struct pci_dev mypci;
-#ifdef HAVE_HDA_BUS_TEMPLATE
+#ifndef NEW_HDA_INFRA
struct hda_bus_template temp;
#endif
struct hda_codec *codec;
@@ -1425,66 +1475,42 @@ int main(int argc, char **argv)
pci_subvendor, pci_subdevice);
}
-#ifdef HAVE_HDA_BUS_TEMPLATE
+#ifndef NEW_HDA_INFRA
memset(&temp, 0, sizeof(temp));
-
temp.pci = &mypci;
- temp.modelname = opt_model;
+ temp->modelname = opt_model;
if (opt_model)
hda_log(HDA_LOG_INFO, "Using model option '%s'\n", opt_model);
-#ifdef HAVE_POWER_SAVE
-#ifndef OLD_POWER_SAVE
- temp.power_save = &power_save;
-#endif
-#endif
-#ifdef OLD_HDA_CMD
- temp.ops.command = old_cmd_send;
- temp.ops.get_response = old_resp_get;
-#ifdef HAVE_POWER_SAVE
- temp.ops.pm_notify = old_pm_notify;
-#endif
-#else /* !OLD_HDA_CMD */
- temp.ops.command = cmd_send;
-#ifdef HAVE_GET_RESPONSE_WITH_CADDR
- temp.ops.get_response = resp_get_caddr;
-#else
- temp.ops.get_response = resp_get;
-#endif
-#ifdef HAVE_HDA_ATTACH_PCM
- temp.ops.attach_pcm = attach_pcm;
-#endif
-#ifdef HAVE_NEW_PM_NOTIFY
- temp.ops.pm_notify = new_pm_notify;
-#else
- temp.ops.pm_notify = pm_notify;
-#endif
-#endif /* OLD_HDA_CMD */
-#endif /* HAVE_HDA_BUS_TEMPLATE */
+ setup_bus_template(&temp);
+#endif /* !NEW_HDA_INFRA */
gather_codec_hooks();
-#ifdef HAVE_HDA_BUS_TEMPLATE
- err = snd_hda_bus_new(&card, &temp, &bus);
-#else
+#ifdef NEW_HDA_INFRA
err = snd_hda_bus_new(&card, &bus);
+#else
+ err = snd_hda_bus_new(&card, &temp, &bus);
#endif
if (err < 0) {
hda_log(HDA_LOG_ERR, "cannot create snd_hda_bus\n");
return 1;
}
-#ifndef HAVE_HDA_BUS_TEMPLATE
+#ifdef NEW_HDA_INFRA
bus->pci = &mypci;
bus->ops = bus_ops;
- bus->power_save = &power_save;
bus->modelname = opt_model;
-#endif /* HAVE_HDA_BUS_TEMPLATE */
+#endif /* NEW_HDA_INFRA */
ignore_invalid_ftype = 1;
+#ifdef NEW_HDA_INFRA
+ err = snd_hda_codec_new(bus, &card, proc.addr, &codec);
+#else /* !NEW_HDA_INFRA */
#ifdef OLD_HDA_CODEC_NEW
err = snd_hda_codec_new(bus, proc.addr, &codec);
#else
err = snd_hda_codec_new(bus, proc.addr, 1, &codec);
#endif
+#endif /* NEW_HDA_INFRA */
ignore_invalid_ftype = 0;
if (err) {
hda_log(HDA_LOG_ERR, "cannot create codec\n");
@@ -1513,6 +1539,7 @@ int main(int argc, char **argv)
snd_hda_codec_configure(codec);
#endif
+#ifndef NEW_HDA_INFRA
if (!no_configure) {
hda_log(HDA_LOG_INFO, "# Building PCMs...\n");
snd_hda_build_pcms(bus);
@@ -1527,6 +1554,7 @@ int main(int argc, char **argv)
snd_hda_build_controls(codec->bus);
#endif
}
+#endif /* !NEW_HDA_INFRA */
/* power-down after init phase */
snd_hda_power_down(codec);
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
new file mode 100644
index 0000000..cffeb6a
--- /dev/null
+++ b/include/linux/atomic.h
@@ -0,0 +1,19 @@
+#ifndef _LINUX_ATOMIC_H
+#define _LINUX_ATOMIC_H
+
+typedef struct {
+ int counter;
+} atomic_t;
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_add_return(n, v) ((v)->counter += (n))
+#define atomic_sub_return(n, v) ((v)->counter -= (n))
+#define atomic_inc(v) atomic_add_return(1, v)
+#define atomic_dec(v) atomic_sub_return(1, v)
+#define atomic_inc_return(v) atomic_add_return(1, v)
+#define atomic_dec_return(v) atomic_sub_return(1, v)
+#define atomic_set(v, i) (((v)->counter) = (i))
+#define ATOMIC_INIT(i) { (i) }
+
+#endif /* _LINUX_ATOMIC_H */
+
diff --git a/include/linux/device.h b/include/linux/device.h
index fc4108e..fd9b6f1 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1,18 +1,30 @@
#ifndef __LINUX_DEVICE_H
#define __LINUX_DEVICE_H
+#include <linux/list.h>
+#include <linux/pm.h>
+
+struct device;
+struct device_driver;
+struct bus_type;
struct class;
struct attribute_group;
struct device {
struct device *parent;
void *driver_data;
+ struct bus_type *bus;
+ struct device_driver *driver;
struct class *class;
void (*release)(struct device *);
const struct attribute_group **groups;
- /* XXX */
+ /* hda-emu specific */
void *device_data;
+ bool registered;
+ bool pmsuspended;
+ bool pmallow;
+ int pmcnt;
};
/* dev_err() & co */
@@ -29,12 +41,55 @@ struct device {
struct device;
#define get_device(dev) /* NOP */
#define put_device(dev) /* NOP */
-static inline int device_add(struct device *dev) { return 0; }
-static inline void device_del(struct device *dev) {}
-static inline void device_initialize(struct device *dev) {}
+
+void device_initialize(struct device *dev);
+int device_add(struct device *dev);
+void device_del(struct device *dev);
+
+#define device_is_registered(dev) ((dev)->registered)
+#define device_enable_async_suspend(dev) /* NOP */
#define dev_set_name(dev, name, fmt, args...)
#define dev_set_drvdata(dev, data) do { (dev)->device_data = (data); } while (0)
#define dev_get_drvdata(dev) (dev)->device_data
+struct device_driver {
+ const char *name;
+ struct bus_type *bus;
+ struct module *owner;
+ const char *mod_name; /* used for built-in modules */
+ int (*probe) (struct device *dev);
+ int (*remove) (struct device *dev);
+ void (*shutdown) (struct device *dev);
+ int (*suspend) (struct device *dev, pm_message_t state);
+ int (*resume) (struct device *dev);
+ const struct attribute_group **groups;
+ const struct dev_pm_ops *pm;
+
+ /* hda-emu specific */
+ struct list_head list;
+};
+
+int driver_register(struct device_driver *drv);
+void driver_unregister(struct device_driver *drv);
+int device_attach(struct device *dev);
+
+struct bus_type {
+ const char *name;
+
+ int (*match)(struct device *dev, struct device_driver *drv);
+ int (*probe)(struct device *dev);
+ int (*remove)(struct device *dev);
+ void (*shutdown)(struct device *dev);
+
+ int (*online)(struct device *dev);
+ int (*offline)(struct device *dev);
+
+ int (*suspend)(struct device *dev, pm_message_t state);
+ int (*resume)(struct device *dev);
+};
+
+int bus_register(struct bus_type *bus);
+void bus_unregister(struct bus_type *bus);
+
#endif /* __LINUX_DEVICE_H */
diff --git a/include/linux/kref.h b/include/linux/kref.h
new file mode 100644
index 0000000..bbbec77
--- /dev/null
+++ b/include/linux/kref.h
@@ -0,0 +1,24 @@
+#ifndef __LINUX_KREF_H
+#define __LINUX_KREF_H
+
+struct kref {
+ int refcount;
+};
+
+#define kref_init(kref) do { (kref)->refcount = 1; } while (0)
+#define kref_get(kref) do { (kref)->refcount++; } while (0)
+
+static inline int kref_sub(struct kref *kref, unsigned int count,
+ void (*release)(struct kref *kref))
+{
+ kref->refcount -= count;
+ if (!kref->refcount) {
+ release(kref);
+ return 1;
+ }
+ return 0;
+}
+
+#define kref_put(kref, release) kref_sub(kref, 1, release)
+
+#endif /* __LINUX_KREF_H */
diff --git a/include/linux/pm.h b/include/linux/pm.h
new file mode 100644
index 0000000..3cbfba7
--- /dev/null
+++ b/include/linux/pm.h
@@ -0,0 +1,24 @@
+#ifndef __LINUX_PM_H
+#define __LINUX_PM_H
+
+struct device;
+
+/* stripped version */
+struct dev_pm_ops {
+ int (*suspend)(struct device *dev);
+ int (*resume)(struct device *dev);
+ int (*runtime_suspend)(struct device *dev);
+ int (*runtime_resume)(struct device *dev);
+ int (*runtime_idle)(struct device *dev);
+};
+
+#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
+ .suspend = suspend_fn, \
+ .resume = resume_fn,
+
+#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
+ .runtime_suspend = suspend_fn, \
+ .runtime_resume = resume_fn, \
+ .runtime_idle = idle_fn,
+
+#endif /* __LINUX_PM_H */
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
new file mode 100644
index 0000000..4091ea9
--- /dev/null
+++ b/include/linux/pm_runtime.h
@@ -0,0 +1,23 @@
+#ifndef __LINUX_PM_RUNTIME_H
+#define __LINUX_PM_RUNTIME_H
+
+#include <linux/device.h>
+
+static inline void pm_runtime_enable(struct device *dev) {}
+static inline void pm_runtime_set_active(struct device *dev) {}
+static inline void pm_runtime_set_autosuspend_delay(struct device *dev, int delay) {}
+static inline void pm_runtime_use_autosuspend(struct device *dev) {}
+static inline void pm_runtime_dont_use_autosuspend(struct device *dev) {}
+static inline void pm_runtime_mark_last_busy(struct device *dev) {}
+
+static inline bool pm_runtime_suspended(struct device *dev) { return dev->pmsuspended; }
+
+static inline void pm_runtime_get_noresume(struct device *dev) { dev->pmcnt++; }
+int pm_runtime_get_sync(struct device *dev);
+int pm_runtime_put_autosuspend(struct device *dev);
+int pm_runtime_force_suspend(struct device *dev);
+int pm_runtime_force_resume(struct device *dev);
+void pm_runtime_allow(struct device *dev);
+void pm_runtime_forbid(struct device *dev);
+
+#endif /* __LINUX_PM_RUNTIME_H */
diff --git a/include/sound/core.h b/include/sound/core.h
index a4c15de..56a64da 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -53,6 +53,8 @@ struct snd_card {
struct device *dev;
struct device card_dev;
+
+ bool registered;
};
struct snd_device {
@@ -96,6 +98,19 @@ int snd_device_free(struct snd_card *card, void *device_data)
return 0;
}
+static inline
+int snd_device_disconnect(struct snd_card *card, void *device_data)
+{
+ return 0;
+}
+
+static inline
+int snd_card_register(struct snd_card *card)
+{
+ card->registered = true;
+ return 0;
+}
+
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pci.h>
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index f4f45c0..c060488 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -314,5 +314,6 @@ struct snd_dma_buffer {
void *private_data; /* private for allocator; don't touch */
};
-#endif /* __SOUND_PCM_H */
+#define snd_pcm_suspend_all(pcm)
+#endif /* __SOUND_PCM_H */
diff --git a/include/wrapper.h b/include/wrapper.h
index 53c3cfd..c5bbc2f 100644
--- a/include/wrapper.h
+++ b/include/wrapper.h
@@ -4,6 +4,8 @@
#ifndef __HDA_WRAPPER_H
#define __HDA_WRAPPER_H
+#include <stdarg.h>
+
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
@@ -237,6 +239,7 @@ void mylock_read_unlock(int *lock, const char *file, int line);
void mylock_write_lock(int *lock, const char *file, int line);
void mylock_write_unlock(int *lock, const char *file, int line);
+#include "linux/atomic.h"
#include "linux/spinlock.h"
#include "linux/pci_ids.h"
#include "linux/workqueue.h"
@@ -265,4 +268,41 @@ static inline long copy_to_user(void __user *to, const void *from, unsigned long
return 0;
}
+
+static inline char *kvasprintf(int gfp, const char *fmt, va_list ap)
+{
+ char tmp;
+ va_list app;
+ int len;
+ char *buf;
+
+ va_copy(app, ap);
+ len = vsnprintf(&tmp, 1, fmt, app);
+ va_end(app);
+ if (len < 0)
+ return NULL;
+ buf = malloc(len + 1);
+ if (!buf)
+ return NULL;
+ vsnprintf(buf, len + 1, fmt, ap);
+ return buf;
+}
+
+#define KBUILD_MODNAME __FILE__
+
+#define module_driver(__driver, __register, __unregister, ...) \
+static int __init __driver##_init(void) \
+{ \
+ return __register(&(__driver) , ##__VA_ARGS__); \
+} \
+module_init(__driver##_init); \
+static void __exit __driver##_exit(void) \
+{ \
+ __unregister(&(__driver) , ##__VA_ARGS__); \
+} \
+module_exit(__driver##_exit);
+
+/* attributes */
+#define __printf(a, b) __attribute__((format(printf, a, b)))
+
#endif /* __HDA_WRAPPER_H */
diff --git a/kernel/Makefile.am b/kernel/Makefile.am
index c76fe84..f9aea79 100644
--- a/kernel/Makefile.am
+++ b/kernel/Makefile.am
@@ -67,6 +67,10 @@ if HAVE_HDA_BEEP
HELPERS += hda_beep.c
endif
+if HAVE_HDA_BIND
+HELPERS += hda_bind.c
+endif
+
noinst_LIBRARIES = libhda.a
libhda_a_SOURCES = hda_codec.c hda_generic.c misc_wrapper.c \
$(PATCHES) $(HELPERS)
diff --git a/kernel/hda_bind.c b/kernel/hda_bind.c
new file mode 100644
index 0000000..8a4f6b6
--- /dev/null
+++ b/kernel/hda_bind.c
@@ -0,0 +1 @@
+#include "../hda/hda_bind.c"
diff --git a/snd-wrapper.c b/snd-wrapper.c
index 986c91d..7a0ccd2 100644
--- a/snd-wrapper.c
+++ b/snd-wrapper.c
@@ -741,3 +741,137 @@ void snd_hda_sysfs_clear(struct hda_codec *codec) {}
struct class *sound_class;
const struct attribute_group *snd_hda_dev_attr_groups[1];
+/*
+ * for device binding
+ */
+
+static LIST_HEAD(registered_drivers);
+
+int driver_register(struct device_driver *drv)
+{
+ list_add_tail(&drv->list, &registered_drivers);
+ return 0;
+}
+
+void driver_unregister(struct device_driver *drv)
+{
+ list_del(&drv->list);
+}
+
+static struct bus_type *_bus;
+
+int bus_register(struct bus_type *bus)
+{
+ _bus = bus;
+ return 0;
+}
+
+void bus_unregister(struct bus_type *bus)
+{
+}
+
+void device_initialize(struct device *dev)
+{
+ dev->pmcnt = 0;
+}
+
+int device_add(struct device *dev)
+{
+ dev->registered = true;
+ return device_attach(dev);
+}
+
+void device_del(struct device *dev)
+
+{
+ dev->registered = false;
+ dev->driver->remove(dev);
+ dev->driver = NULL;
+}
+
+int device_attach(struct device *dev)
+{
+ struct device_driver *drv;
+ int err;
+
+ if (!_bus) {
+ hda_log(HDA_LOG_ERR, "Bus not registered!!\n");
+ return -ENXIO;
+ }
+
+ list_for_each_entry(drv, &registered_drivers, list) {
+ if (!_bus->match(dev, drv))
+ continue;
+ dev->driver = drv;
+ err = drv->probe(dev);
+ if (!err)
+ return 1; /* bound */
+ dev->driver = NULL;
+ if (err < 0) {
+ hda_log(HDA_LOG_INFO, "Driver %s not bound\n", drv->name);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ */
+static void check_resume(struct device *dev)
+{
+ if (dev->pmcnt > 0 && dev->pmsuspended) {
+ hda_log(HDA_LOG_INFO, "Codec resuming...\n");
+ dev->pmsuspended = false;
+ dev->driver->pm->runtime_resume(dev);
+ }
+}
+
+int pm_runtime_get_sync(struct device *dev)
+{
+ dev->pmcnt++;
+ check_resume(dev);
+ return 0;
+}
+
+static void check_suspend(struct device *dev)
+{
+ if (!dev->pmcnt && !dev->pmsuspended && dev->pmallow) {
+ hda_log(HDA_LOG_INFO, "Codec suspending...\n");
+ dev->driver->pm->runtime_suspend(dev);
+ dev->pmsuspended = true;
+ }
+}
+
+int pm_runtime_put_autosuspend(struct device *dev)
+{
+ dev->pmcnt--;
+ check_suspend(dev);
+ return 0;
+}
+
+int pm_runtime_force_suspend(struct device *dev)
+{
+ if (!dev->driver || !dev->driver->pm)
+ return -ENODEV;
+ return dev->driver->pm->runtime_suspend(dev);
+}
+
+int pm_runtime_force_resume(struct device *dev)
+{
+ if (!dev->driver || !dev->driver->pm)
+ return -ENODEV;
+ return dev->driver->pm->runtime_resume(dev);
+}
+
+void pm_runtime_allow(struct device *dev)
+{
+ dev->pmallow = 1;
+ check_suspend(dev);
+}
+
+void pm_runtime_forbid(struct device *dev)
+{
+ dev->pmallow = 0;
+ check_resume(dev);
+}