The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Глава 13. Управление питанием

Глава 13. Управление питанием

Предыдущая  Содержание  Следующая V*D*V

Если чип допускает работу с функциями приостановки/возобновления работы, необходимо добавить в драйвер код управления питанием. Дополнительный код для управления питанием должен использовать ifdef с CONFIG_PM.

 

Если драйвер полностью поддерживает приостановку/возобновление, то есть устройство может правильно восстановить своё состояние после вызова приостановки, можно установить в поле PCM info флаг SNDRV_PCM_INFO_RESUME. Как правило, это возможно, если регистры чипа могут быть безопасно сохранены и восстановлены из ОЗУ. Если флаг установлен, после завершения обратного вызова resume вызывается обратный вызов trigger с SNDRV_PCM_TRIGGER_RESUME.

 

Даже если драйвер не поддерживает полностью управление питанием, но частичная приостановка/возобновление всё же возможна, обратные вызовы приостановки/возобновления по-прежнему стоит реализовать. В таком случае приложения сбрасывали бы состояние вызывая snd_pcm_prepare() и надлежащим образом перезапускали поток. Таким образом, можно в дальнейшем определить обратные вызовы приостановки/возобновления, но не устанавливать в PCM в поле info флаг SNDRV_PCM_INFO_RESUME.

 

Обратите внимание, что независимо от флага SNDRV_PCM_INFO_RESUME, если  вызвана snd_pcm_suspend_all, всегда может быть вызван trigger с SUSPEND. Флаг RESUME влияет только на поведение snd_pcm_resume(). (Таким образом, в теории, когда флаг SNDRV_PCM_INFO_RESUME не установлен, в обратном вызове trigger нет необходимости обрабатывать SNDRV_PCM_TRIGGER_RESUME. Но лучше сохранить его по соображениям совместимости.)

 

В более ранней версии драйверов ALSA предоставлялся универсальный уровень управления питанием, но он был удалён. Драйвер должен определить обработку приостановки/возобновления в соответствии с шиной, к которой подключено устройство. В случае драйверов PCI обратные вызовы выглядят следующим образом:

 

#ifdef CONFIG_PM

static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)

{

    .... /* делаем что-нибудь для приостановки */

    return 0;

}

static int snd_my_resume(struct pci_dev *pci)

{

    .... /* делаем что-нибудь для возобновления */

    return 0;

}

#endif

 

Последовательность реальной приостановки работы следующая:

 

1.Получить данные карты и чипа.

2.Вызвать snd_power_change_state() с SNDRV_CTL_POWER_D3hot для изменения состояния питания.

3.Вызвать snd_pcm_suspend_all(), чтобы приостановить работающие потоки PCM.

4.Если используются кодеки AC97, вызвать для каждого кодека snd_ac97_suspend().

5.Сохранить значения регистров, если необходимо.

6.Остановить оборудования, если это необходимо.

7.Отключить устройство PCI вызовом pci_disable_device(). Затем, наконец, вызвать pci_save_state().

 

Типичный код будет таким:

 

static int mychip_suspend(struct pci_dev *pci, pm_message_t state)

{

    /* (1) */

    struct snd_card *card = pci_get_drvdata(pci);

    struct mychip *chip = card->private_data;

    /* (2) */

    snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);

    /* (3) */

    snd_pcm_suspend_all(chip->pcm);

    /* (4) */

    snd_ac97_suspend(chip->ac97);

    /* (5) */

    snd_mychip_save_registers(chip);

    /* (6) */

    snd_mychip_stop_hardware(chip);

    /* (7) */

    pci_disable_device(pci);

    pci_save_state(pci);

    return 0;

}

 

Последовательность реального возобновления работы следующая:

 

1.Получить данные карты и чипа.

2.Настроить PCI. Во-первых, вызвать pci_restore_state(). Затем снова включить устройство PCI, вызвав pci_enable_device().  При необходимости также вызвать pci_set_master().

3.Переинициализировать чип.

4.Восстановить сохранённые регистры, если необходимо.

5.Возобновить работу микшера, вызвав, например, snd_ac97_resume().

6.Перезапустить оборудование (если это надо).

7.Вызвать snd_power_change_state() с SNDRV_CTL_POWER_D0 для уведомления процессов.

 

Типичный код будет таким:

 

static int mychip_resume(struct pci_dev *pci)

{

    /* (1) */

    struct snd_card *card = pci_get_drvdata(pci);

    struct mychip *chip = card->private_data;

    /* (2) */

    pci_restore_state(pci);

    pci_enable_device(pci);

    pci_set_master(pci);

    /* (3) */

    snd_mychip_reinit_chip(chip);

    /* (4) */

    snd_mychip_restore_registers(chip);

    /* (5) */

    snd_ac97_resume(chip->ac97);

    /* (6) */

    snd_mychip_restart_chip(chip);

    /* (7) */

    snd_power_change_state(card, SNDRV_CTL_POWER_D0);

    return 0;

}

 

Как показано выше, лучше сохранять регистры после приостановления операций PCM через snd_pcm_suspend_all() или snd_pcm_suspend(). Это означает, что при получении снимка состояния регистров потоки PCM уже остановлены. Но помните, что  в обратном вызове resume нет необходимости перезапускать PCM поток. Он будет перезапущен через вызов trigger с SNDRV_PCM_TRIGGER_RESUME, когда это необходимо.

 

Хорошо, сейчас у нас есть все обратные вызовы. Давайте установим их. При инициализации карты убедитесь, что вы можете получить данные чипа из экземпляра карты, обычно через поле private_data, в случае, если вы самостоятельно создали объект чипа.

 

static int __devinit snd_mychip_probe(struct pci_dev *pci,

                        const struct pci_device_id *pci_id)

{

    ....

    struct snd_card *card;

    struct mychip *chip;

    int err;

    ....

    err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);

    ....

    chip = kzalloc(sizeof(*chip), GFP_KERNEL);

    ....

    card->private_data = chip;

    ....

}

 

Если объект чипа создан с помощью snd_card_create(), он всё равно доступен через поле private_data.

 

static int __devinit snd_mychip_probe(struct pci_dev *pci,

                        const struct pci_device_id *pci_id)

{

    ....

    struct snd_card *card;

    struct mychip *chip;

    int err;

    ....

    err = snd_card_create(index[dev], id[dev], THIS_MODULE,

                          sizeof(struct mychip), &card);

    ....

    chip = card->private_data;

    ....

}

 

Если необходимо место для сохранения регистров, также выделите буфер для этого здесь, поскольку было бы смертельным, если вы бы не смогли выделить память в фазе приостановки работы. Выделенный буфер должен быть освобождён в соответствующем деструкторе.

 

И, наконец, устанавливаем функции обратного вызова приостановки/возобновления в pci_driver.

 

static struct pci_driver driver = {

    .name     = "My Chip",

    .id_table = snd_my_ids,

    .probe    = snd_my_probe,

    .remove   = __devexit_p(snd_my_remove),

#ifdef CONFIG_PM

    .suspend  = snd_my_suspend,

    .resume   = snd_my_resume,

#endif

};

 

Предыдущая  Содержание  Следующая