[alsa-devel] [PATCH 1/1] ALC889A chip identification
With this patch the ALC889A chip will be identified correctly. The functions patch_alc882() and patch_alc883() have been altered to set the stream names correctly. Without this patch 'aplay -l' would identify an ALC889A chip as ALC885 for example. Apart from that a kernel info message will be printed if ALC885 or ALC889A chips are handled by the wrong patch function.
Signed-off by: Torben Schulz public@letorbi.de
--- alsa-driver/alsa-kernel/pci/hda/patch_realtek.c 2009-05-14 18:23:17.000000000 +0200 +++ alsa-driver-mod/alsa-kernel/pci/hda/patch_realtek.c 2009-05-15 01:08:16.000000000 +0200 @@ -7338,8 +7338,17 @@ setup_preset(spec, &alc882_presets[board_config]);
if (codec->vendor_id == 0x10ec0885) { - spec->stream_name_analog = "ALC885 Analog"; - spec->stream_name_digital = "ALC885 Digital"; + if ((codec->revision_id == 0x100101) || + (codec->revision_id == 0x100103)) { + spec->stream_name_analog = "ALC889A Analog"; + spec->stream_name_digital = "ALC889A Digital"; + printk(KERN_INFO + "hda_codec: ALC889A handled by patch_alc882()," + " should be handled by patch_alc883()\n"); + } else { + spec->stream_name_analog = "ALC885 Analog"; + spec->stream_name_digital = "ALC885 Digital"; + } } else { spec->stream_name_analog = "ALC882 Analog"; spec->stream_name_digital = "ALC882 Digital"; @@ -9231,6 +9240,27 @@ setup_preset(spec, &alc883_presets[board_config]);
switch (codec->vendor_id) { + case 0x10ec0885: + if ((codec->revision_id == 0x100101) || + (codec->revision_id == 0x100103)) { + spec->stream_name_analog = "ALC889A Analog"; + spec->stream_name_digital = "ALC889A Digital"; + if (!spec->num_adc_nids) { + spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); + spec->adc_nids = alc883_adc_nids; + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc883_capsrc_nids; + spec->capture_style = CAPT_MIX; /* matrix-style capture */ + spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ + } else { + spec->stream_name_analog = "ALC885 Analog"; + spec->stream_name_digital = "ALC885 Digital"; + printk(KERN_INFO + "hda_codec: ALC885 handled by patch_alc883()," + " should be handled by patch_alc882()\n"); + } + break; case 0x10ec0888: if (codec->revision_id == 0x100101) { spec->stream_name_analog = "ALC1200 Analog";
At Fri, 15 May 2009 02:34:07 +0200, Torben Schulz wrote:
With this patch the ALC889A chip will be identified correctly. The functions patch_alc882() and patch_alc883() have been altered to set the stream names correctly. Without this patch 'aplay -l' would identify an ALC889A chip as ALC885 for example. Apart from that a kernel info message will be printed if ALC885 or ALC889A chips are handled by the wrong patch function.
Signed-off by: Torben Schulz public@letorbi.de
Thanks for the patch! Just a few comments below...
--- alsa-driver/alsa-kernel/pci/hda/patch_realtek.c 2009-05-14 18:23:17.000000000 +0200 +++ alsa-driver-mod/alsa-kernel/pci/hda/patch_realtek.c 2009-05-15 01:08:16.000000000 +0200 @@ -7338,8 +7338,17 @@ setup_preset(spec, &alc882_presets[board_config]);
if (codec->vendor_id == 0x10ec0885) {
spec->stream_name_analog = "ALC885 Analog";
spec->stream_name_digital = "ALC885 Digital";
if ((codec->revision_id == 0x100101) ||
(codec->revision_id == 0x100103)) {
spec->stream_name_analog = "ALC889A Analog";
spec->stream_name_digital = "ALC889A Digital";
printk(KERN_INFO
"hda_codec: ALC889A handled by patch_alc882(),"
" should be handled by patch_alc883()\n");
It's rather a driver internal thing and not necessarily to be told to each user :) If any, let it be a verbose debug print with snd_printdd().
} else {
spec->stream_name_analog = "ALC885 Analog";
spec->stream_name_digital = "ALC885 Digital";
} else { spec->stream_name_analog = "ALC882 Analog"; spec->stream_name_digital = "ALC882 Digital";}
@@ -9231,6 +9240,27 @@ setup_preset(spec, &alc883_presets[board_config]);
switch (codec->vendor_id) {
- case 0x10ec0885:
if ((codec->revision_id == 0x100101) ||
(codec->revision_id == 0x100103)) {
This if block can be skipped (thus less indent level) by ...
spec->stream_name_analog = "ALC889A Analog";
spec->stream_name_digital = "ALC889A Digital";
if (!spec->num_adc_nids) {
spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
spec->adc_nids = alc883_adc_nids;
}
if (!spec->capsrc_nids)
spec->capsrc_nids = alc883_capsrc_nids;
spec->capture_style = CAPT_MIX; /* matrix-style capture */
spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
} else {
spec->stream_name_analog = "ALC885 Analog";
spec->stream_name_digital = "ALC885 Digital";
printk(KERN_INFO
"hda_codec: ALC885 handled by patch_alc883(),"
" should be handled by patch_alc882()\n");
... checking the ALC889A at the beginning of patch_alc883() since using patch_alc883() for ALC885 is an error indeed.
Could you fix and repost?
BTW, regarding the strings: basically we can do a better clean-up by using already existing strings. For example, make new fields, hda_codec.vendor_name and hda_codec.chip_name, which points the vendor id string in hda_codec.c and the chip name string in snd_hda_codec_preset struct respectively. Then all PCM name strings can be created automatically.
But, it's another level of clean-up to be done later, after your fixes.
thanks,
Takashi
At Fri, 15 May 2009 07:50:46 +0200, I wrote:
BTW, regarding the strings: basically we can do a better clean-up by using already existing strings. For example, make new fields, hda_codec.vendor_name and hda_codec.chip_name, which points the vendor id string in hda_codec.c and the chip name string in snd_hda_codec_preset struct respectively. Then all PCM name strings can be created automatically.
The patch is something like below. It's just compile tested.
Takashi
--- diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b91f6ed..77385de 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -623,7 +623,10 @@ static int get_codec_name(struct hda_codec *codec) const struct hda_vendor_id *c; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; - char tmp[16], name[32]; + char tmp[16]; + + if (codec->vendor_name) + goto get_chip_name;
for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { @@ -635,14 +638,21 @@ static int get_codec_name(struct hda_codec *codec) sprintf(tmp, "Generic %04x", vendor_id); vendor = tmp; } + codec->vendor_name = kstrdup(vendor, GFP_KERNEL); + if (!codec->vendor_name) + return -ENOMEM; + + get_chip_name: + if (codec->chip_name) + return 0; + if (codec->preset && codec->preset->name) - snprintf(name, sizeof(name), "%s %s", vendor, - codec->preset->name); - else - snprintf(name, sizeof(name), "%s ID %x", vendor, - codec->vendor_id & 0xffff); - codec->name = kstrdup(name, GFP_KERNEL); - if (!codec->name) + codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL); + else { + sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); + codec->chip_name = kstrdup(tmp, GFP_KERNEL); + } + if (!codec->chip_name) return -ENOMEM; return 0; } @@ -848,7 +858,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); - kfree(codec->name); + kfree(codec->vendor_name); + kfree(codec->chip_name); kfree(codec->modelname); kfree(codec->wcaps); kfree(codec); @@ -989,15 +1000,16 @@ int snd_hda_codec_configure(struct hda_codec *codec) int err;
codec->preset = find_codec_preset(codec); - if (!codec->name) { + if (!codec->vendor_name || !codec->chip_name) { err = get_codec_name(codec); if (err < 0) return err; } /* audio codec should override the mixer name */ if (codec->afg || !*codec->bus->card->mixername) - strlcpy(codec->bus->card->mixername, codec->name, - sizeof(codec->bus->card->mixername)); + snprintf(codec->bus->card->mixername, + sizeof(codec->bus->card->mixername), + "%s %s", codec->vendor_name, codec->chip_name);
if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index cd8979c..c5bd40f 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -748,7 +748,8 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; struct module *owner; - const char *name; /* codec name */ + const char *vendor_name; /* codec vendor name */ + const char *chip_name; /* codec chip name */ const char *modelname; /* model name for preset */
/* set by patch */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 1c57505..6812fbe 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -242,7 +242,8 @@ CODEC_INFO_SHOW(subsystem_id); CODEC_INFO_SHOW(revision_id); CODEC_INFO_SHOW(afg); CODEC_INFO_SHOW(mfg); -CODEC_INFO_STR_SHOW(name); +CODEC_INFO_STR_SHOW(vendor_name); +CODEC_INFO_STR_SHOW(chip_name); CODEC_INFO_STR_SHOW(modelname);
#define CODEC_INFO_STORE(type) \ @@ -275,7 +276,8 @@ static ssize_t type##_store(struct device *dev, \ CODEC_INFO_STORE(vendor_id); CODEC_INFO_STORE(subsystem_id); CODEC_INFO_STORE(revision_id); -CODEC_INFO_STR_STORE(name); +CODEC_INFO_STR_STORE(vendor_name); +CODEC_INFO_STR_STORE(chip_name); CODEC_INFO_STR_STORE(modelname);
#define CODEC_ACTION_STORE(type) \ @@ -499,7 +501,8 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RW(revision_id), CODEC_ATTR_RO(afg), CODEC_ATTR_RO(mfg), - CODEC_ATTR_RW(name), + CODEC_ATTR_RW(vendor_name), + CODEC_ATTR_RW(chip_name), CODEC_ATTR_RW(modelname), CODEC_ATTR_RW(init_verbs), CODEC_ATTR_RW(hints), diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 93d7499..418c5d1 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -466,8 +466,12 @@ static void print_codec_info(struct snd_info_entry *entry, hda_nid_t nid; int i, nodes;
- snd_iprintf(buffer, "Codec: %s\n", - codec->name ? codec->name : "Not Set"); + snd_iprintf(buffer, "Codec: "); + if (codec->vendor_name && codec->chip_name) + snd_iprintf(buffer, "%s %s\n", + codec->vendor_name, codec->chip_name); + else + snd_iprintf(buffer, "Not Set\n"); snd_iprintf(buffer, "Address: %d\n", codec->addr); snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1bf9d05..4bc3e7e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -277,13 +277,13 @@ struct alc_spec { */ unsigned int num_init_verbs;
- char *stream_name_analog; /* analog PCM stream */ + char stream_name_analog[16]; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; struct hda_pcm_stream *stream_analog_capture; struct hda_pcm_stream *stream_analog_alt_playback; struct hda_pcm_stream *stream_analog_alt_capture;
- char *stream_name_digital; /* digital PCM stream */ + char stream_name_digital[16]; /* digital PCM stream */ struct hda_pcm_stream *stream_digital_playback; struct hda_pcm_stream *stream_digital_capture;
@@ -3169,7 +3169,10 @@ static int alc_build_pcms(struct hda_codec *codec) if (spec->no_analog) goto skip_analog;
+ snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), + "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; + if (spec->stream_analog_playback) { if (snd_BUG_ON(!spec->multiout.dac_nids)) return -EINVAL; @@ -3195,6 +3198,9 @@ static int alc_build_pcms(struct hda_codec *codec) skip_analog: /* SPDIF for stream index #1 */ if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + snprintf(spec->stream_name_digital, + sizeof(spec->stream_name_digital), + "%s Digital", codec->chip_name); codec->num_pcms = 2; codec->slave_dig_outs = spec->multiout.slave_dig_outs; info = spec->pcm_rec + 1; @@ -4432,12 +4438,10 @@ static int patch_alc880(struct hda_codec *codec) if (board_config != ALC880_AUTO) setup_preset(spec, &alc880_presets[board_config]);
- spec->stream_name_analog = "ALC880 Analog"; spec->stream_analog_playback = &alc880_pcm_analog_playback; spec->stream_analog_capture = &alc880_pcm_analog_capture; spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
- spec->stream_name_digital = "ALC880 Digital"; spec->stream_digital_playback = &alc880_pcm_digital_playback; spec->stream_digital_capture = &alc880_pcm_digital_capture;
@@ -6078,11 +6082,9 @@ static int patch_alc260(struct hda_codec *codec) if (board_config != ALC260_AUTO) setup_preset(spec, &alc260_presets[board_config]);
- spec->stream_name_analog = "ALC260 Analog"; spec->stream_analog_playback = &alc260_pcm_analog_playback; spec->stream_analog_capture = &alc260_pcm_analog_capture;
- spec->stream_name_digital = "ALC260 Digital"; spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture;
@@ -7337,14 +7339,6 @@ static int patch_alc882(struct hda_codec *codec) if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]);
- if (codec->vendor_id == 0x10ec0885) { - spec->stream_name_analog = "ALC885 Analog"; - spec->stream_name_digital = "ALC885 Digital"; - } else { - spec->stream_name_analog = "ALC882 Analog"; - spec->stream_name_digital = "ALC882 Digital"; - } - spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; /* FIXME: setup DAC5 */ @@ -9232,13 +9226,6 @@ static int patch_alc883(struct hda_codec *codec)
switch (codec->vendor_id) { case 0x10ec0888: - if (codec->revision_id == 0x100101) { - spec->stream_name_analog = "ALC1200 Analog"; - spec->stream_name_digital = "ALC1200 Digital"; - } else { - spec->stream_name_analog = "ALC888 Analog"; - spec->stream_name_digital = "ALC888 Digital"; - } if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; @@ -9249,8 +9236,6 @@ static int patch_alc883(struct hda_codec *codec) spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ break; case 0x10ec0889: - spec->stream_name_analog = "ALC889 Analog"; - spec->stream_name_digital = "ALC889 Digital"; if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids); spec->adc_nids = alc889_adc_nids; @@ -9261,8 +9246,6 @@ static int patch_alc883(struct hda_codec *codec) capture */ break; default: - spec->stream_name_analog = "ALC883 Analog"; - spec->stream_name_digital = "ALC883 Digital"; if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; @@ -11087,11 +11070,9 @@ static int patch_alc262(struct hda_codec *codec) if (board_config != ALC262_AUTO) setup_preset(spec, &alc262_presets[board_config]);
- spec->stream_name_analog = "ALC262 Analog"; spec->stream_analog_playback = &alc262_pcm_analog_playback; spec->stream_analog_capture = &alc262_pcm_analog_capture;
- spec->stream_name_digital = "ALC262 Digital"; spec->stream_digital_playback = &alc262_pcm_digital_playback; spec->stream_digital_capture = &alc262_pcm_digital_capture;
@@ -12117,14 +12098,6 @@ static int patch_alc268(struct hda_codec *codec) if (board_config != ALC268_AUTO) setup_preset(spec, &alc268_presets[board_config]);
- if (codec->vendor_id == 0x10ec0267) { - spec->stream_name_analog = "ALC267 Analog"; - spec->stream_name_digital = "ALC267 Digital"; - } else { - spec->stream_name_analog = "ALC268 Analog"; - spec->stream_name_digital = "ALC268 Digital"; - } - spec->stream_analog_playback = &alc268_pcm_analog_playback; spec->stream_analog_capture = &alc268_pcm_analog_capture; spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; @@ -12979,7 +12952,6 @@ static int patch_alc269(struct hda_codec *codec) if (board_config != ALC269_AUTO) setup_preset(spec, &alc269_presets[board_config]);
- spec->stream_name_analog = "ALC269 Analog"; if (codec->subsystem_id == 0x17aa3bf8) { /* Due to a hardware problem on Lenovo Ideadpad, we need to * fix the sample rate of analog I/O to 44.1kHz @@ -12990,7 +12962,6 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_analog_playback = &alc269_pcm_analog_playback; spec->stream_analog_capture = &alc269_pcm_analog_capture; } - spec->stream_name_digital = "ALC269 Digital"; spec->stream_digital_playback = &alc269_pcm_digital_playback; spec->stream_digital_capture = &alc269_pcm_digital_capture;
@@ -14080,11 +14051,9 @@ static int patch_alc861(struct hda_codec *codec) if (board_config != ALC861_AUTO) setup_preset(spec, &alc861_presets[board_config]);
- spec->stream_name_analog = "ALC861 Analog"; spec->stream_analog_playback = &alc861_pcm_analog_playback; spec->stream_analog_capture = &alc861_pcm_analog_capture;
- spec->stream_name_digital = "ALC861 Digital"; spec->stream_digital_playback = &alc861_pcm_digital_playback; spec->stream_digital_capture = &alc861_pcm_digital_capture;
@@ -15007,13 +14976,8 @@ static int patch_alc861vd(struct hda_codec *codec) setup_preset(spec, &alc861vd_presets[board_config]);
if (codec->vendor_id == 0x10ec0660) { - spec->stream_name_analog = "ALC660-VD Analog"; - spec->stream_name_digital = "ALC660-VD Digital"; /* always turn on EAPD */ add_verb(spec, alc660vd_eapd_verbs); - } else { - spec->stream_name_analog = "ALC861VD Analog"; - spec->stream_name_digital = "ALC861VD Digital"; }
spec->stream_analog_playback = &alc861vd_pcm_analog_playback; @@ -16936,17 +16900,6 @@ static int patch_alc662(struct hda_codec *codec) if (board_config != ALC662_AUTO) setup_preset(spec, &alc662_presets[board_config]);
- if (codec->vendor_id == 0x10ec0663) { - spec->stream_name_analog = "ALC663 Analog"; - spec->stream_name_digital = "ALC663 Digital"; - } else if (codec->vendor_id == 0x10ec0272) { - spec->stream_name_analog = "ALC272 Analog"; - spec->stream_name_digital = "ALC272 Digital"; - } else { - spec->stream_name_analog = "ALC662 Analog"; - spec->stream_name_digital = "ALC662 Digital"; - } - spec->stream_analog_playback = &alc662_pcm_analog_playback; spec->stream_analog_capture = &alc662_pcm_analog_capture;
Takashi Iwai wrote:
At Fri, 15 May 2009 07:50:46 +0200, I wrote:
BTW, regarding the strings: basically we can do a better clean-up by using already existing strings. For example, make new fields, hda_codec.vendor_name and hda_codec.chip_name, which points the vendor id string in hda_codec.c and the chip name string in snd_hda_codec_preset struct respectively. Then all PCM name strings can be created automatically.
The patch is something like below. It's just compile tested.
I just applied your patch the latest snapshot and it works perfect. My chipset is now identified correctly, so my patch seems to be obsolete now, I guess ^^ However, I have three (main) questions:
1.: What are the next steps now? Will you post your patch again to the ML under an own topic or will it stay in this thread?
2.: Can I do anything to help bringing your patch into the official repository? When will it be part of an official snapshot?
3.: Why doesn't hda_codec_preset.patch point to patch_alc883, but to patch_alc882 which later redirects to patch_alc883 (see patch_realtek.c line 7305 and 16958 (patched version))?
It's quite essential for me to bring this patch into an official snapshot, since a lot of the changes interact with my MacBook3,1 patch and I would like to diff against a snapshot which includes your patch already. (or is this - for some reason - bad style?)
Bai Torben
At Fri, 15 May 2009 19:52:55 +0200, Torben Schulz wrote:
Takashi Iwai wrote:
At Fri, 15 May 2009 07:50:46 +0200, I wrote:
BTW, regarding the strings: basically we can do a better clean-up by using already existing strings. For example, make new fields, hda_codec.vendor_name and hda_codec.chip_name, which points the vendor id string in hda_codec.c and the chip name string in snd_hda_codec_preset struct respectively. Then all PCM name strings can be created automatically.
The patch is something like below. It's just compile tested.
I just applied your patch the latest snapshot and it works perfect. My chipset is now identified correctly, so my patch seems to be obsolete now, I guess ^^ However, I have three (main) questions:
1.: What are the next steps now? Will you post your patch again to the ML under an own topic or will it stay in this thread?
I already merged to sound git tree below. git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
The snapshot tarball is: ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/alsa-driver-snapshot.tar.gz
Now please rebase your patches against these.
2.: Can I do anything to help bringing your patch into the official repository? When will it be part of an official snapshot?
It's done :)
3.: Why doesn't hda_codec_preset.patch point to patch_alc883, but to patch_alc882 which later redirects to patch_alc883 (see patch_realtek.c line 7305 and 16958 (patched version))?
It was a kind of hack. As codec id shows, it's supposed to be rather compatible with ALC885. But, the automatic probing did work better with alc883-parser at the this hack was introduced. OTOH, moving all for ALC889A to patch_alc883 is dangerous because we actually don't know exactly which of ALC885_* model correspond to ALC889A actually.
Possibly, the hack no longer needed. But, maybe a better way would be to merge patch_alc88x() together as a long term solution.
It's quite essential for me to bring this patch into an official snapshot, since a lot of the changes interact with my MacBook3,1 patch and I would like to diff against a snapshot which includes your patch already. (or is this - for some reason - bad style?)
Make a diff against the latest snapshot or GIT tree above please. Then I'll merge it for the next 2.6.31 kernel.
thanks,
Takashi
Your patch has cleared my long standing struggle to get sound. Excellent! Please can you inform the Fedora team? It would great to have it incorporated into release 12.
Acer Aspire 6935g
Regards Phil
participants (3)
-
Runbox
-
Takashi Iwai
-
Torben Schulz