From 3c59c6b11d8b0b50a8675a2c45983232e18d152b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 26 Sep 2001 13:57:04 +0000 Subject: [PATCH] Added power management functions and defines. --- aserver/aserver.c | 9 +++++++++ include/aserver.h | 1 + include/control.h | 16 ++++++++++++++++ include/pcm.h | 3 +++ src/control/control.c | 27 +++++++++++++++++++++++++++ src/control/control_hw.c | 18 ++++++++++++++++++ src/control/control_local.h | 2 ++ src/control/control_shm.c | 28 ++++++++++++++++++++++++++++ src/pcm/pcm.c | 12 ++++++++++++ src/pcm/pcm_file.c | 7 +++++++ src/pcm/pcm_hooks.c | 7 +++++++ src/pcm/pcm_hw.c | 13 +++++++++++++ src/pcm/pcm_local.h | 1 + src/pcm/pcm_meter.c | 7 +++++++ src/pcm/pcm_multi.c | 16 ++++++++++++++++ src/pcm/pcm_null.c | 6 ++++++ src/pcm/pcm_plugin.c | 7 +++++++ src/pcm/pcm_share.c | 6 ++++++ src/pcm/pcm_shm.c | 9 +++++++++ 19 files changed, 195 insertions(+) diff --git a/aserver/aserver.c b/aserver/aserver.c index 72633a1f..6fccb8a2 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -469,6 +469,9 @@ static int pcm_shm_cmd(client_t *client) case SNDRV_PCM_IOCTL_UNLINK: ctrl->result = snd_pcm_unlink(pcm); break; + case SNDRV_PCM_IOCTL_RESUME: + ctrl->result = snd_pcm_resume(pcm); + break; case SND_PCM_IOCTL_MMAP: { ctrl->result = snd_pcm_mmap(pcm); @@ -669,6 +672,12 @@ static int ctl_shm_cmd(client_t *client) case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: ctrl->result = snd_ctl_rawmidi_prefer_subdevice(ctl, ctrl->u.rawmidi_prefer_subdevice); break; + case SNDRV_CTL_IOCTL_POWER: + ctrl->result = snd_ctl_set_power_state(ctl, ctrl->u.power_state); + break; + case SNDRV_CTL_IOCTL_POWER_STATE: + ctrl->result = snd_ctl_get_power_state(ctl, &ctrl->u.power_state); + break; case SND_CTL_IOCTL_READ: ctrl->result = snd_ctl_read(ctl, &ctrl->u.read); break; diff --git a/include/aserver.h b/include/aserver.h index 344167aa..662e7e9c 100644 --- a/include/aserver.h +++ b/include/aserver.h @@ -113,6 +113,7 @@ typedef struct { int pcm_prefer_subdevice; snd_rawmidi_info_t rawmidi_info; int rawmidi_prefer_subdevice; + unsigned int power_state; snd_ctl_event_t read; } u; char data[0]; diff --git a/include/control.h b/include/control.h index 1c66175f..812699dd 100644 --- a/include/control.h +++ b/include/control.h @@ -142,6 +142,20 @@ typedef enum _snd_ctl_event_type { /** Element name for IEC958 (S/PDIF) */ #define SND_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SND_CTL_NAME_##direction SND_CTL_NAME_IEC958_##what +/** Mask for the major Power State identifier */ +#define SNDRV_CTL_POWER_MASK 0xff00 +/** ACPI/PCI Power State D0 */ +#define SNDRV_CTL_POWER_D0 0x0000 +/** ACPI/PCI Power State D1 */ +#define SNDRV_CTL_POWER_D1 0x0100 +/** ACPI/PCI Power State D2 */ +#define SNDRV_CTL_POWER_D2 0x0200 +/** ACPI/PCI Power State D3 */ +#define SNDRV_CTL_POWERDOWN_D3 0x0300 +/** ACPI/PCI Power State D3hot */ +#define SNDRV_CTL_POWERDOWN_D3hot (SNDRV_CTL_POWERDOWN_D3|0x0000) +/** ACPI/PCI Power State D3cold */ +#define SNDRV_CTL_POWERDOWN_D3cold (SNDRV_CTL_POWERDOWN_D3|0x0001) /** CTL type */ typedef enum _snd_ctl_type { @@ -208,6 +222,8 @@ int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev); int snd_ctl_rawmidi_next_device(snd_ctl_t *ctl, int * device); int snd_ctl_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info); int snd_ctl_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev); +int snd_ctl_set_power_state(snd_ctl_t *ctl, unsigned int state); +int snd_ctl_get_power_state(snd_ctl_t *ctl, unsigned int *state); int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_event_t *event); int snd_ctl_wait(snd_ctl_t *ctl, int timeout); diff --git a/include/pcm.h b/include/pcm.h index 437fe471..d96ae2bd 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -222,6 +222,8 @@ typedef enum _snd_pcm_state { SND_PCM_STATE_DRAINING, /** Paused */ SND_PCM_STATE_PAUSED, + /** Hardware is suspended */ + SND_PCM_STATE_SUSPENDED, SND_PCM_STATE_LAST = SND_PCM_STATE_PAUSED, } snd_pcm_state_t; @@ -367,6 +369,7 @@ int snd_pcm_drain(snd_pcm_t *pcm); int snd_pcm_pause(snd_pcm_t *pcm, int enable); snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm); int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); +int snd_pcm_resume(snd_pcm_t *pcm); snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); diff --git a/src/control/control.c b/src/control/control.c index c505a7ea..d21a7a0f 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -363,6 +363,33 @@ int snd_ctl_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev) return ctl->ops->rawmidi_prefer_subdevice(ctl, subdev); } +/** + * \brief Set Power State to given SND_CTL_POWER_* value and do the power management + * \param ctl CTL handle + * \param state Desired Power State + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_set_power_state(snd_ctl_t *ctl, unsigned int state) +{ + assert(ctl); + if (ctl->ops->set_power_state) + return ctl->ops->set_power_state(ctl, state); + return -ENXIO; +} + +/** + * \brief Get actual Power State + * \param ctl CTL handle + * \param state Destination value + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_get_power_state(snd_ctl_t *ctl, unsigned int *state) +{ + assert(ctl); + if (ctl->ops->get_power_state) + return ctl->ops->get_power_state(ctl, state); + return -ENXIO; +} /** * \brief Read an event diff --git a/src/control/control_hw.c b/src/control/control_hw.c index e880142e..c206dd2e 100644 --- a/src/control/control_hw.c +++ b/src/control/control_hw.c @@ -233,6 +233,22 @@ static int snd_ctl_hw_rawmidi_prefer_subdevice(snd_ctl_t *handle, int subdev) return 0; } +static int snd_ctl_hw_set_power_state(snd_ctl_t *handle, unsigned int state) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_POWER, &state) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_get_power_state(snd_ctl_t *handle, unsigned int *state) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_POWER_STATE, state) < 0) + return -errno; + return 0; +} + static int snd_ctl_hw_read(snd_ctl_t *handle, snd_ctl_event_t *event) { snd_ctl_hw_t *hw = handle->private_data; @@ -263,6 +279,8 @@ snd_ctl_ops_t snd_ctl_hw_ops = { rawmidi_next_device: snd_ctl_hw_rawmidi_next_device, rawmidi_info: snd_ctl_hw_rawmidi_info, rawmidi_prefer_subdevice: snd_ctl_hw_rawmidi_prefer_subdevice, + set_power_state: snd_ctl_hw_set_power_state, + get_power_state: snd_ctl_hw_get_power_state, read: snd_ctl_hw_read, }; diff --git a/src/control/control_local.h b/src/control/control_local.h index b3522cff..75c06886 100644 --- a/src/control/control_local.h +++ b/src/control/control_local.h @@ -41,6 +41,8 @@ typedef struct _snd_ctl_ops { int (*rawmidi_next_device)(snd_ctl_t *handle, int *device); int (*rawmidi_info)(snd_ctl_t *handle, snd_rawmidi_info_t * info); int (*rawmidi_prefer_subdevice)(snd_ctl_t *handle, int subdev); + int (*set_power_state)(snd_ctl_t *handle, unsigned int state); + int (*get_power_state)(snd_ctl_t *handle, unsigned int *state); int (*read)(snd_ctl_t *handle, snd_ctl_event_t *event); } snd_ctl_ops_t; diff --git a/src/control/control_shm.c b/src/control/control_shm.c index 4e7329e8..f4572eb6 100644 --- a/src/control/control_shm.c +++ b/src/control/control_shm.c @@ -345,6 +345,32 @@ static int snd_ctl_shm_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev) return err; } +static int snd_ctl_shm_set_power_state(snd_ctl_t *ctl, unsigned int state) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.power_state = state; + ctrl->cmd = SNDRV_CTL_IOCTL_POWER; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + return err; +} + +static int snd_ctl_shm_get_power_state(snd_ctl_t *ctl, unsigned int *state) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SNDRV_CTL_IOCTL_POWER_STATE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *state = ctrl->u.power_state; + return err; +} + static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event) { snd_ctl_shm_t *shm; @@ -384,6 +410,8 @@ snd_ctl_ops_t snd_ctl_shm_ops = { rawmidi_next_device: snd_ctl_shm_rawmidi_next_device, rawmidi_info: snd_ctl_shm_rawmidi_info, rawmidi_prefer_subdevice: snd_ctl_shm_rawmidi_prefer_subdevice, + set_power_state: snd_ctl_shm_set_power_state, + get_power_state: snd_ctl_shm_get_power_state, read: snd_ctl_shm_read, }; diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 1c79b766..da5e67ce 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -280,6 +280,18 @@ int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) return pcm->fast_ops->delay(pcm->fast_op_arg, delayp); } +/** + * \brief Resume from suspend, no samples are lost + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_resume(snd_pcm_t *pcm) +{ + assert(pcm); + assert(pcm->setup); + return pcm->fast_ops->resume(pcm->fast_op_arg); +} + /** * \brief Prepare PCM for use * \param pcm PCM handle diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index cbd0fdb1..9e21d52f 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -220,6 +220,12 @@ static snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f return err; } +static int snd_pcm_file_resume(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + return snd_pcm_resume(file->slave); +} + static snd_pcm_sframes_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) { snd_pcm_file_t *file = pcm->private_data; @@ -388,6 +394,7 @@ snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { drain: snd_pcm_file_drain, pause: snd_pcm_file_pause, rewind: snd_pcm_file_rewind, + resume: snd_pcm_file_resume, writei: snd_pcm_file_writei, writen: snd_pcm_file_writen, readi: snd_pcm_file_readi, diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index 98879465..47f066f5 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -150,6 +150,12 @@ static snd_pcm_sframes_t snd_pcm_hooks_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t return snd_pcm_rewind(h->slave, frames); } +static int snd_pcm_hooks_resume(snd_pcm_t *pcm) +{ + snd_pcm_hooks_t *h = pcm->private_data; + return snd_pcm_resume(h->slave); +} + static snd_pcm_sframes_t snd_pcm_hooks_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) { snd_pcm_hooks_t *h = pcm->private_data; @@ -280,6 +286,7 @@ snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { drain: snd_pcm_hooks_drain, pause: snd_pcm_hooks_pause, rewind: snd_pcm_hooks_rewind, + resume: snd_pcm_hooks_resume, writei: snd_pcm_hooks_writei, writen: snd_pcm_hooks_writen, readi: snd_pcm_hooks_readi, diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 3148c64c..ebbdedfc 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -298,6 +298,18 @@ static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t fra return frames; } +static int snd_pcm_hw_resume(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd; + if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) { + if (errno != ENXIO) + SYSERR("SNDRV_PCM_IOCTL_RESUME failed"); + return -errno; + } + return 0; +} + static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) { snd_pcm_sframes_t result; @@ -520,6 +532,7 @@ snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { drain: snd_pcm_hw_drain, pause: snd_pcm_hw_pause, rewind: snd_pcm_hw_rewind, + resume: snd_pcm_hw_resume, writei: snd_pcm_hw_writei, writen: snd_pcm_hw_writen, readi: snd_pcm_hw_readi, diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 27d6afae..4acd9588 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -135,6 +135,7 @@ typedef struct { int (*pause)(snd_pcm_t *pcm, int enable); snd_pcm_state_t (*state)(snd_pcm_t *pcm); int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); + int (*resume)(snd_pcm_t *pcm); snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); snd_pcm_sframes_t (*writei)(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t (*writen)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index f0e3e633..54517306 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -395,6 +395,12 @@ static snd_pcm_sframes_t snd_pcm_meter_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t return err; } +static int snd_pcm_meter_resume(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_resume(meter->slave); +} + static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) @@ -601,6 +607,7 @@ snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = { drain: snd_pcm_meter_drain, pause: snd_pcm_meter_pause, rewind: snd_pcm_meter_rewind, + resume: snd_pcm_meter_resume, writei: snd_pcm_mmap_writei, writen: snd_pcm_mmap_writen, readi: snd_pcm_mmap_readi, diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index a8a5003b..0c2f6d1a 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -486,6 +486,21 @@ static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t return frames; } +static int snd_pcm_multi_resume(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int err = 0; + unsigned int i; + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + continue; + err = snd_pcm_resume(multi->slaves[i].pcm); + if (err < 0) + return err; + } + return err; +} + static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) @@ -571,6 +586,7 @@ snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { readi: snd_pcm_mmap_readi, readn: snd_pcm_mmap_readn, rewind: snd_pcm_multi_rewind, + resume: snd_pcm_multi_resume, avail_update: snd_pcm_multi_avail_update, mmap_commit: snd_pcm_multi_mmap_commit, }; diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 6360be38..186766ce 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -166,6 +166,11 @@ static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f } } +static int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + static snd_pcm_sframes_t snd_pcm_null_fwd(snd_pcm_t *pcm, snd_pcm_uframes_t size) { snd_pcm_null_t *null = pcm->private_data; @@ -305,6 +310,7 @@ snd_pcm_fast_ops_t snd_pcm_null_fast_ops = { drain: snd_pcm_null_drain, pause: snd_pcm_null_pause, rewind: snd_pcm_null_rewind, + resume: snd_pcm_null_resume, writei: snd_pcm_null_writei, writen: snd_pcm_null_writen, readi: snd_pcm_null_readi, diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index 0db059a2..2908ff6a 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -191,6 +191,12 @@ snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames return n; } +int snd_pcm_plugin_resume(snd_pcm_t *pcm) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + return snd_pcm_resume(plugin->slave); +} + static snd_pcm_uframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, @@ -446,6 +452,7 @@ snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { drain: snd_pcm_plugin_drain, pause: snd_pcm_plugin_pause, rewind: snd_pcm_plugin_rewind, + resume: snd_pcm_plugin_resume, writei: snd_pcm_plugin_writei, writen: snd_pcm_plugin_writen, readi: snd_pcm_plugin_readi, diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 65fab30e..a91375b6 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -901,6 +901,11 @@ static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRI return -ENOSYS; } +static int snd_pcm_share_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) { snd_pcm_share_t *share = pcm->private_data; @@ -1184,6 +1189,7 @@ snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { readi: snd_pcm_mmap_readi, readn: snd_pcm_mmap_readn, rewind: snd_pcm_share_rewind, + resume: snd_pcm_share_resume, avail_update: snd_pcm_share_avail_update, mmap_commit: snd_pcm_share_mmap_commit, }; diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index 0b1770c5..bbadb255 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -433,6 +433,14 @@ static snd_pcm_sframes_t snd_pcm_shm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t fr return snd_pcm_shm_action(pcm); } +static int snd_pcm_shm_resume(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_RESUME; + return snd_pcm_shm_action(pcm); +} + static snd_pcm_sframes_t snd_pcm_shm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) @@ -506,6 +514,7 @@ snd_pcm_fast_ops_t snd_pcm_shm_fast_ops = { drain: snd_pcm_shm_drain, pause: snd_pcm_shm_pause, rewind: snd_pcm_shm_rewind, + resume: snd_pcm_shm_resume, writei: snd_pcm_mmap_writei, writen: snd_pcm_mmap_writen, readi: snd_pcm_mmap_readi, -- 2.47.1