From: Takashi Iwai Subject: ALSA: hda - Add digital beep support Patch-mainline: 2.6.28-rc1 References: bnc#398459, bnc#398455 Add the support of digital beep for devices without analog beep. Signed-off-by: Takashi Iwai --- diff -ruN a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -0,0 +1,134 @@ +/* + * Digital Beep Input Interface for HD-audio codec + * + * Author: Matthew Ranostay + * Copyright (c) 2008 Embedded Alley Solutions Inc + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "hda_beep.h" + +enum { + DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */ + DIGBEEP_HZ_MIN = 93750, /* 93.750 Hz */ + DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */ +}; + +static void snd_hda_generate_beep(struct work_struct *work) +{ + struct hda_beep *beep = + container_of(work, struct hda_beep, beep_work); + struct hda_codec *codec = beep->codec; + + /* generate tone */ + snd_hda_codec_write_cache(codec, beep->nid, 0, + AC_VERB_SET_BEEP_CONTROL, beep->tone); +} + +static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, + unsigned int code, int hz) +{ + struct hda_beep *beep = input_get_drvdata(dev); + + switch (code) { + case SND_BELL: + if (hz) + hz = 1000; + case SND_TONE: + hz *= 1000; /* fixed point */ + hz = hz - DIGBEEP_HZ_MIN; + if (hz < 0) + hz = 0; /* turn off PC beep*/ + else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) + hz = 0xff; + else { + hz /= DIGBEEP_HZ_STEP; + hz++; + } + break; + default: + return -1; + } + beep->tone = hz; + + /* schedule beep event */ + schedule_work(&beep->beep_work); + return 0; +} + +int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) +{ + struct input_dev *input_dev; + struct hda_beep *beep; + int err; + + beep = kzalloc(sizeof(*beep), GFP_KERNEL); + if (beep == NULL) + return -ENOMEM; + snprintf(beep->phys, sizeof(beep->phys), + "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); + input_dev = input_allocate_device(); + + /* setup digital beep device */ + input_dev->name = "HDA Digital PCBeep"; + input_dev->phys = beep->phys; + input_dev->id.bustype = BUS_PCI; + + input_dev->id.vendor = codec->vendor_id >> 16; + input_dev->id.product = codec->vendor_id & 0xffff; + input_dev->id.version = 0x01; + + input_dev->evbit[0] = BIT_MASK(EV_SND); + input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); + input_dev->event = snd_hda_beep_event; + input_dev->dev.parent = &codec->bus->pci->dev; + input_set_drvdata(input_dev, beep); + + err = input_register_device(input_dev); + if (err < 0) { + input_free_device(input_dev); + kfree(beep); + return err; + } + + /* enable linear scale */ + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, 0x01); + + beep->nid = nid; + beep->dev = input_dev; + beep->codec = codec; + codec->beep = beep; + + INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); + return 0; +} + +void snd_hda_detach_beep_device(struct hda_codec *codec) +{ + struct hda_beep *beep = codec->beep; + if (beep) { + cancel_work_sync(&beep->beep_work); + flush_scheduled_work(); + + input_unregister_device(beep->dev); + kfree(beep); + } +} diff -ruN a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -0,0 +1,44 @@ +/* + * Digital Beep Input Interface for HD-audio codec + * + * Author: Matthew Ranostay + * Copyright (c) 2008 Embedded Alley Solutions Inc + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SOUND_HDA_BEEP_H +#define __SOUND_HDA_BEEP_H + +#include "hda_codec.h" + +/* beep information */ +struct hda_beep { + struct input_dev *dev; + struct hda_codec *codec; + char phys[32]; + int tone; + int nid; + struct work_struct beep_work; /* scheduled task for beep event */ +}; + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); +void snd_hda_detach_beep_device(struct hda_codec *codec); +#else +#define snd_hda_attach_beep_device(...) +#define snd_hda_detach_beep_device(...) +#endif +#endif diff -ruN a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -5,6 +5,7 @@ snd-hda-intel-y += hda_codec.o snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o +snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o diff -ruN a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -449,6 +449,7 @@ */ struct hda_bus; +struct hda_beep; struct hda_codec; struct hda_pcm; struct hda_pcm_stream; @@ -634,6 +635,9 @@ /* codec specific info */ void *spec; + /* beep device */ + struct hda_beep *beep; + /* widget capabilities cache */ unsigned int num_nodes; hda_nid_t start_nid; diff -ruN a/sound/pci/Kconfig b/sound/pci/Kconfig --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -517,6 +517,14 @@ This interface can be used for out-of-band communication with codecs for debugging purposes. +config SND_HDA_INPUT_BEEP + bool "Support digital beep via input layer" + depends on SND_HDA_INTEL + depends on INPUT=y || INPUT=SND_HDA_INTEL + help + Say Y here to build a digital beep interface for HD-audio + driver. This interface is used to generate digital beeps. + config SND_HDA_CODEC_REALTEK bool "Build Realtek HD-audio codec support" depends on SND_HDA_INTEL