diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-03-16 14:41:33 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-03-16 14:43:29 +0100 |
commit | 047aa0ea8e65d07c321e895b11d5f92c12ddc02f (patch) | |
tree | e2ed7153f712b3be75a028c22b5cef4e933b6421 | |
parent | 512deee4523161571e723a565d9c0123635765da (diff) | |
download | hda-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.ac | 50 | ||||
-rw-r--r-- | hda-emu.c | 114 | ||||
-rw-r--r-- | include/linux/atomic.h | 19 | ||||
-rw-r--r-- | include/linux/device.h | 63 | ||||
-rw-r--r-- | include/linux/kref.h | 24 | ||||
-rw-r--r-- | include/linux/pm.h | 24 | ||||
-rw-r--r-- | include/linux/pm_runtime.h | 23 | ||||
-rw-r--r-- | include/sound/core.h | 15 | ||||
-rw-r--r-- | include/sound/pcm.h | 3 | ||||
-rw-r--r-- | include/wrapper.h | 40 | ||||
-rw-r--r-- | kernel/Makefile.am | 4 | ||||
-rw-r--r-- | kernel/hda_bind.c | 1 | ||||
-rw-r--r-- | snd-wrapper.c | 134 |
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) @@ -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, ®istered_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, ®istered_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); +} |