svn commit: r236750 - in stable/8: share/man/man4 sys/conf
sys/dev/sound/pci/hda sys/modules/sound/driver/hda
Alexander Motin
mav at FreeBSD.org
Fri Jun 8 12:35:44 UTC 2012
Author: mav
Date: Fri Jun 8 12:35:43 2012
New Revision: 236750
URL: http://svn.freebsd.org/changeset/base/236750
Log:
MFC r230130:
Major snd_hda driver rewrite:
- Huge old hdac driver was split into three independent pieces: HDA
controller driver (hdac), HDA CODEC driver (hdacc) and HDA sudio function
driver (hdaa).
- Support for multichannel recording was added. Now, as specification
defines, driver checks input associations for pins with sequence numbers
14 and 15, and if found (usually) -- works as before, mixing signals
together. If it doesn't, it configures input association as multichannel.
- Signal tracer was improved to look for cases where several DACs/ADCs in
CODEC can work with the same audio signal. If such case found, driver
registers additional playback/record stream (channel) for the pcm device.
- New controller streams reservation mechanism was implemented. That
allows to have more pcm devices then streams supported by the controller
(usually 4 in each direction). Now it limits only number of simultaneously
transferred audio streams, that is rarely reachable and properly reported
if happens.
- Codec pins and GPIO signals configuration was exported via set of
writable sysctls. Another sysctl dev.hdaa.X.reconfig allows to trigger
driver reconfiguration in run-time.
- Driver now decodes pins location and connector type names. In some cases
it allows to hint user where on the system case connectors, related to the
pcm device, are located. Number of channels supported by pcm device,
reported now (if it is not 2), should also make search easier.
- Added workaround for digital mic on some Asus laptops/netbooks.
Sponsored by: iXsystems, Inc.
Added:
stable/8/sys/dev/sound/pci/hda/hdaa.c
- copied unchanged from r230130, head/sys/dev/sound/pci/hda/hdaa.c
stable/8/sys/dev/sound/pci/hda/hdaa.h
- copied unchanged from r230130, head/sys/dev/sound/pci/hda/hdaa.h
stable/8/sys/dev/sound/pci/hda/hdaa_patches.c
- copied unchanged from r230130, head/sys/dev/sound/pci/hda/hdaa_patches.c
stable/8/sys/dev/sound/pci/hda/hdac_if.m
- copied unchanged from r230130, head/sys/dev/sound/pci/hda/hdac_if.m
stable/8/sys/dev/sound/pci/hda/hdacc.c
- copied unchanged from r230130, head/sys/dev/sound/pci/hda/hdacc.c
Modified:
stable/8/share/man/man4/snd_hda.4
stable/8/sys/conf/files
stable/8/sys/conf/kmod.mk
stable/8/sys/dev/sound/pci/hda/hda_reg.h
stable/8/sys/dev/sound/pci/hda/hdac.c
stable/8/sys/dev/sound/pci/hda/hdac.h
stable/8/sys/dev/sound/pci/hda/hdac_private.h
stable/8/sys/dev/sound/pci/hda/hdac_reg.h
stable/8/sys/modules/sound/driver/hda/Makefile
Directory Properties:
stable/8/share/man/man4/ (props changed)
stable/8/sys/ (props changed)
Modified: stable/8/share/man/man4/snd_hda.4
==============================================================================
--- stable/8/share/man/man4/snd_hda.4 Fri Jun 8 12:31:49 2012 (r236749)
+++ stable/8/share/man/man4/snd_hda.4 Fri Jun 8 12:35:43 2012 (r236750)
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 22, 2010
+.Dd January 11, 2012
.Dt SND_HDA 4
.Os
.Sh NAME
@@ -53,8 +53,9 @@ support for several logical audio device
.Pp
The
.Nm
-driver is a HDA bus controller driver and HDA codecs audio functions bridge
-driver that allows the generic audio driver,
+driver includes HDA bus controller driver (hdac), HDA codec driver (hdacc)
+and HDA codecs audio functions bridge driver (hdaa) that allows
+the generic audio driver,
.Xr sound 4 ,
to be used with this hardware.
Only audio functions are supported by
@@ -77,7 +78,9 @@ For example, one device for main rear 7.
for independent headset connectors at front and one device for SPDIF or
HDMI audio input/output.
The assignment of audio inputs and outputs may be tuned with
-.Xr device.hints 5 .
+.Xr device.hints 5
+or
+.Xr sysctl 8 .
The driver's verbose boot messages provide a lot of information about
the operation of the driver and present audio setup.
.Pp
@@ -92,19 +95,26 @@ The following variables are available at
file:
.Bl -tag -width ".Va hint.hdac.%d.config"-offset indent
.It Va hint.hdac.%d.config
-Configures a range of possible options.
+Configures a range of possible controller options.
Possible values are:
+.Dq Li 64bit ,
.Dq Li dmapos ,
+.Dq Li msi .
+An option prefixed with
+.Dq Li no ,
+such as
+.Dq Li nomsi ,
+will do the opposite and takes precedence.
+Options can be separated by whitespace and commas.
+.It Va hint.hdac.%d.msi
+Controls MSI (Message Signaled Interrupts) support.
+.It Va hint.hdac.%d.cad%d.nid%d.config
+Same as
+.Va hint.hdaa.%d.nid%d.config
+.It Va hint.hdaa.%d.config
+Configures a range of possible audio function options.
+Possible values are:
.Dq Li eapdinv ,
-.Dq Li gpio0 ,
-.Dq Li gpio1 ,
-.Dq Li gpio2 ,
-.Dq Li gpio3 ,
-.Dq Li gpio4 ,
-.Dq Li gpio5 ,
-.Dq Li gpio6 ,
-.Dq Li gpio7 ,
-.Dq Li gpioflush ,
.Dq Li ivref ,
.Dq Li ivref50 ,
.Dq Li ivref80 ,
@@ -126,22 +136,47 @@ such as
will do the opposite and takes precedence.
Options can be separated by whitespace and commas.
.Pp
+The
+.Dq Li eapdinv
+option inverts External Amplifier Power Down signal.
+The
+.Dq Li fixedrate
+denies all sampling rates except 48KHz.
+The
+.Dq Li forcestereo
+denies mono playback/recording.
+The
+.Dq Li senseinv
+option inverts jack sensing logic.
+The
+.Dq Li ivref Ns Ar X
+and
+.Dq Li ovref Ns Ar X
+options control the voltage used to power external microphones.
+.It Va hint.hdaa.%d.gpio_config
+Overrides audio function GPIO pins configuration set by BIOS.
+May be specified as a set of space-separated
+.Dq Ar num Ns = Ns Ar value
+pairs, where
+.Ar num
+is GPIO line number, and
+.Ar value
+is one of:
+.Dq Li keep ,
+.Dq Li set ,
+.Dq Li clear ,
+.Dq Li disable
+and
+.Dq Li input .
+.Pp
.Dq Li GPIO Ns s
are a codec's General Purpose I/O pins which system integrators sometimes
use to control external muters, amplifiers and so on.
If you have no sound, or sound volume is not adequate, you may have to
experiment a bit with the GPIO setup to find the optimal setup for your
system.
-.Pp
-The
-.Dq Li ivref Ns Ar X
-and
-.Dq Li ovref Ns Ar X
-options control the voltage used to power external microphones.
-.It Va hint.hdac.%d.msi
-Controls MSI (Message Signaled Interrupts) support.
-.It Va hint.hdac.%d.cad%d.nid%d.config
-Overrides codec pin configuration set by BIOS.
+.It Va hint.hdaa.%d.nid%d.config
+Overrides audio function pin configuration set by BIOS.
May be specified as a 32-bit hexadecimal value with a leading
.Dq 0x ,
or as a set of space-separated
@@ -165,7 +200,7 @@ The following options are supported:
Association number.
Associations are used to group individual pins to form a complex multi-pin
device.
-For example, to group 4 connectors for 7.1 output, or to treat several
+For example, to group 4 connectors for 7.1 input/output, or to treat several
input connectors as sources for the same input device.
Association numbers can be specified as numeric values from 0 to 15.
A value of 0 means disabled pin.
@@ -180,16 +215,22 @@ A unique, per-association number used to
particular association.
Sequence numbers can be specified as numeric values from 0 to 15.
.Pp
-For output assotiations sequence numbers encode speaker pairs positions:
-0 - Front, 1 - Center/LFE, 2 - Back, 3 - Front Wide Center, 4 - Side.
-Standard combinations are: (0) - Stereo; (0, 2), (0, 4) - Quadro;
-(0, 1, 2), (0, 1, 4) - 5.1; (0, 1, 2, 4) - 7.1.
-.Pp
The sequence number 15 has a special meaning for output associations.
Output pins with this number and device type
.Dq Ar Headphones
will duplicate (with automatic mute if jack detection is supported) the
first pin in that association.
+.Pp
+The sequence numbers 14 and 15 has a special meaning for input associations.
+Their presence in association defines it as multiplexed or mixed respectively.
+If none of them present and there are more then one pin in association,
+the association will provide multichannel input.
+.Pp
+For multichannel input/output assotiations sequence numbers encode
+channel pairs positions:
+0 - Front, 1 - Center/LFE, 2 - Back, 3 - Front Wide Center, 4 - Side.
+Standard combinations are: (0) - Stereo; (0, 2), (0, 4) - Quadro;
+(0, 1, 2), (0, 1, 4) - 5.1; (0, 1, 2, 4) - 7.1.
.It Va device
Device type.
Can be specified as a number from 0 to 15 or as a name:
@@ -278,7 +319,11 @@ The following
variables are available in addition to those available to all
.Xr sound 4
devices:
-.Bl -tag -width ".Va dev.hdac.%d.polling" -offset indent
+.Bl -tag -width ".Va dev.hdaa.%d.nid%d_original" -offset indent
+.It Va dev.hdac.%d.pindump
+Setting this to a non-zero value dumps the current pin configuration, main
+capabilities and jack sense status of all audio functions on the controller
+to console and syslog.
.It Va dev.hdac.%d.polling
Enables polling mode.
In this mode the driver operates by querying the device state on timer
@@ -288,11 +333,30 @@ instead of interrupts.
Polling is disabled by default.
Do not enable it unless you are facing weird interrupt problems or if the
device cannot generate interrupts at all.
-.It Va dev.hdac.%d.polling_interval
-Controller/Jack Sense polling interval (1-1000 ms)
-.It Va dev.hdac.%d.pindump
-Setting this to a non-zero value dumps the current pin configuration, main
-capabilities and jack sense status to console and syslog.
+.It Va dev.hdaa.%d.config
+Run-time equivalent of the
+.Va hint.hdaa.%d.config
+tunable.
+.It Va dev.hdaa.%d.gpi_state
+Current state of GPI lines.
+.It Va dev.hdaa.%d.gpio_state
+Current state of GPIO lines.
+.It Va dev.hdaa.%d.gpio_config
+Run-time equivalent of the
+.Va hint.hdaa.%d.gpio.config
+tunable.
+.It Va dev.hdaa.%d.gpo_state
+Current state of GPO lines.
+.It Va dev.hdaa.%d.nid%d_config
+Run-time equivalent of the
+.Va hint.hdaa.%d.nid%d.config
+tunable.
+.It Va dev.hdaa.%d.nid%d_original
+Original pin configuration written by BIOS.
+.It Va dev.hdaa.%d.reconfig
+Setting this to a non-zero value makes driver to destroy existing pcm devices
+and process new pins configuration set via
+.Va dev.hdaa.%d.nid%d_config.
.El
.Sh EXAMPLES
Taking HP Compaq DX2300 with Realtek ALC888 HDA codec for example.
@@ -307,22 +371,23 @@ So high codec uniformity and flexibility
different ways, depending on requested pins usage decribed by pins configuration.
The driver reports such default pin configuration when verbose messages enabled:
.Bd -literal
-hdac0: nid 20 0x01014020 as 2 seq 0 Line-out Jack jack 1 loc 1 color Green misc 0
-hdac0: nid 21 0x99130110 as 1 seq 0 Speaker Fixed jack 3 loc 25 color Unknown misc 1
-hdac0: nid 22 0x411111f0 as 15 seq 0 Speaker None jack 1 loc 1 color Black misc 1
-hdac0: nid 23 0x411111f0 as 15 seq 0 Speaker None jack 1 loc 1 color Black misc 1
-hdac0: nid 24 0x01a19830 as 3 seq 0 Mic Jack jack 1 loc 1 color Pink misc 8
-hdac0: nid 25 0x02a1983f as 3 seq 15 Mic Jack jack 1 loc 2 color Pink misc 8
-hdac0: nid 26 0x01813031 as 3 seq 1 Line-in Jack jack 1 loc 1 color Blue misc 0
-hdac0: nid 27 0x0221401f as 1 seq 15 Headphones Jack jack 1 loc 2 color Green misc 0
-hdac0: nid 28 0x411111f0 as 15 seq 0 Speaker None jack 1 loc 1 color Black misc 1
-hdac0: nid 30 0x411111f0 as 15 seq 0 Speaker None jack 1 loc 1 color Black misc 1
-hdac0: nid 31 0x411111f0 as 15 seq 0 Speaker None jack 1 loc 1 color Black misc 1
+hdaa0: nid 0x as seq device conn jack loc color misc
+hdaa0: 20 01014020 2 0 Line-out Jack 1/8 Rear Green 0
+hdaa0: 21 99130110 1 0 Speaker Fixed ATAPI Onboard Unknown 1
+hdaa0: 22 411111f0 15 0 Speaker None 1/8 Rear Black 1 DISA
+hdaa0: 23 411111f0 15 0 Speaker None 1/8 Rear Black 1 DISA
+hdaa0: 24 01a19830 3 0 Mic Jack 1/8 Rear Pink 8
+hdaa0: 25 02a1983f 3 15 Mic Jack 1/8 Front Pink 8
+hdaa0: 26 01813031 3 1 Line-in Jack 1/8 Rear Blue 0
+hdaa0: 27 0221401f 1 15 Headphones Jack 1/8 Front Green 0
+hdaa0: 28 411111f0 15 0 Speaker None 1/8 Rear Black 1 DISA
+hdaa0: 30 411111f0 15 0 Speaker None 1/8 Rear Black 1 DISA
+hdaa0: 31 411111f0 15 0 Speaker None 1/8 Rear Black 1 DISA
.Ed
.Pp
Here we can see, that the nodes with ID (nid) 25 and 27 are front panel
-connectors (Jack, loc 2), nids 20, 24 and 26 are rear panel connectors
-(Jack, loc 1) and nid 21 is a built-in speaker (Fixed, loc 25).
+connectors (Jack, Front), nids 20, 24 and 26 are rear panel connectors
+(Jack, Rear) and nid 21 is a built-in speaker (Fixed, Onboard).
Pins with nids 22, 23, 28, 30 and 31 will be disabled by driver due to "None"
connectivity. So the pin count and description matches to connectors that
we have.
@@ -330,15 +395,15 @@ we have.
Using association (as) and sequence (seq) fields values pins are grouped into
3 associations:
.Bd -literal
-hdac0: Association 0 (1) out:
-hdac0: Pin nid=21 seq=0
-hdac0: Pin nid=27 seq=15
-hdac0: Association 1 (2) out:
-hdac0: Pin nid=20 seq=0
-hdac0: Association 2 (3) in:
-hdac0: Pin nid=24 seq=0
-hdac0: Pin nid=26 seq=1
-hdac0: Pin nid=25 seq=15
+hdaa0: Association 0 (1) out:
+hdaa0: Pin nid=21 seq=0
+hdaa0: Pin nid=27 seq=15
+hdaa0: Association 1 (2) out:
+hdaa0: Pin nid=20 seq=0
+hdaa0: Association 2 (3) in:
+hdaa0: Pin nid=24 seq=0
+hdaa0: Pin nid=26 seq=1
+hdaa0: Pin nid=25 seq=15
.Ed
.Pp
Each
@@ -498,148 +563,14 @@ Most of controls use logarithmic scale.
.Sh HARDWARE
The
.Nm
-driver supports many Intel HDA compatible audio chipsets including the
-following:
-.Pp
-.Bl -bullet -compact
-.It
-ATI SB450
-.It
-ATI SB600
-.It
-Intel 631x/632xESB
-.It
-Intel 82801F (ICH6)
-.It
-Intel 82801G (ICH7)
-.It
-Intel 82801H (ICH8)
-.It
-Intel 82801I (ICH9)
-.It
-Intel 82801J (ICH10)
-.It
-Intel US15W (SCH)
-.It
-nVidia MCP51
-.It
-nVidia MCP55
-.It
-nVidia MCP61A
-.It
-nVidia MCP61B
-.It
-nVidia MCP63
-.It
-nVidia MCP65A
-.It
-nVidia MCP65B
-.It
-nVidia MCP67A
-.It
-nVidia MCP67B
-.It
-nVidia MCP68
-.It
-nVidia MCP69
-.It
-nVidia MCP73
-.It
-nVidia MCP78
-.It
-nVidia MCP79
-.It
-nVidia MCP89
-.It
-SiS 966
-.It
-VIA VT8251/8237A
-.El
-.Pp
-The following and many other codecs have been verified to work:
+driver supports controllers having PCI class 4 (multimedia) and
+subclass 3 (HDA), compatible with Intel HDA specification.
.Pp
-.Bl -bullet -compact
-.It
-Analog Devices AD1981HD
-.It
-Analog Devices AD1983
-.It
-Analog Devices AD1984
-.It
-Analog Devices AD1986A
-.It
-Analog Devices AD1988
-.It
-Analog Devices AD1988B
-.It
-CMedia CMI9880
-.It
-Conexant CX20549 (Venice)
-.It
-Conexant CX20551 (Waikiki)
-.It
-Conexant CX20561 (Hermosa)
-.It
-Realtek ALC260
-.It
-Realtek ALC262
-.It
-Realtek ALC268
-.It
-Realtek ALC660
-.It
-Realtek ALC861
-.It
-Realtek ALC861VD
-.It
-Realtek ALC880
-.It
-Realtek ALC882
-.It
-Realtek ALC883
-.It
-Realtek ALC885
-.It
-Realtek ALC888
-.It
-Realtek ALC889
-.It
-Sigmatel STAC9205
-.It
-Sigmatel STAC9220
-.It
-Sigmatel STAC9220D / 9223D
-.It
-Sigmatel STAC9221
-.It
-Sigmatel STAC9221D
-.It
-Sigmatel STAC9227D
-.It
-Sigmatel STAC9227X
-.It
-Sigmatel STAC9228D
-.It
-Sigmatel STAC9228X
-.It
-Sigmatel STAC9229D
-.It
-Sigmatel STAC9229X
-.It
-Sigmatel STAC9230D
-.It
-Sigmatel STAC9230X
-.It
-Sigmatel STAC9271D
-.It
-Sigmatel STAC9872AK
-.It
-VIA VT1708
-.It
-VIA VT1708B
-.It
-VIA VT1709
-.El
+The
+.Nm
+driver supports more then two hundred different controllers and CODECs.
+There is no sense to list all of them here, as in most cases specific CODEC
+configuration and wiring are more important then type of the CODEC itself.
.Sh SEE ALSO
.Xr sound 4 ,
.Xr snd_ich 4 ,
@@ -666,19 +597,17 @@ This manual page was written by
and
.An Giorgos Keramidas Aq keramida at FreeBSD.org .
.Sh BUGS
-A few Hardware/OEM vendors tend to screw up BIOS settings, thus
-rendering the
-.Nm
-driver useless.
-This usually results in a state where the
+Some Hardware/OEM vendors tend to screw up BIOS settings or use custom
+unusual CODEC wiring that create problems to the driver.
+This may result in missing pcm devices, or a state where the
.Nm
driver seems to attach and work, but no sound is played.
Some cases can be solved by tuning
.Pa loader.conf
variables.
-Before trying to fix problem that way, make sure that there really is a problem
-and that the PCM audio device in use really corresponds to the expected
-audio connector.
+But before trying to fix problem that way, make sure that there really is
+a problem and that the PCM audio device in use really corresponds to the
+expected audio connector.
.Pp
Some vendors use non-standardized General Purpose I/O (GPIO) pins of the codec
to control external amplifiers.
Modified: stable/8/sys/conf/files
==============================================================================
--- stable/8/sys/conf/files Fri Jun 8 12:31:49 2012 (r236749)
+++ stable/8/sys/conf/files Fri Jun 8 12:35:43 2012 (r236750)
@@ -1615,7 +1615,11 @@ dev/sound/pci/t4dwave.c optional snd_t4
dev/sound/pci/via8233.c optional snd_via8233 pci
dev/sound/pci/via82c686.c optional snd_via82c686 pci
dev/sound/pci/vibes.c optional snd_vibes pci
+dev/sound/pci/hda/hdaa.c optional snd_hda pci
+dev/sound/pci/hda/hdaa_patches.c optional snd_hda pci
dev/sound/pci/hda/hdac.c optional snd_hda pci
+dev/sound/pci/hda/hdac_if.m optional snd_hda pci
+dev/sound/pci/hda/hdacc.c optional snd_hda pci
dev/sound/pcm/ac97.c optional sound
dev/sound/pcm/ac97_if.m optional sound
dev/sound/pcm/ac97_patch.c optional sound
Modified: stable/8/sys/conf/kmod.mk
==============================================================================
--- stable/8/sys/conf/kmod.mk Fri Jun 8 12:31:49 2012 (r236749)
+++ stable/8/sys/conf/kmod.mk Fri Jun 8 12:35:43 2012 (r236750)
@@ -339,6 +339,7 @@ MFILES?= dev/acpica/acpi_if.m dev/acpi_s
dev/mii/miibus_if.m dev/mvs/mvs_if.m dev/ofw/ofw_bus_if.m \
dev/pccard/card_if.m dev/pccard/power_if.m dev/pci/pci_if.m \
dev/pci/pcib_if.m dev/ppbus/ppbus_if.m dev/smbus/smbus_if.m \
+ dev/sound/pci/hda/hdac_if.m \
dev/sound/pcm/ac97_if.m dev/sound/pcm/channel_if.m \
dev/sound/pcm/feeder_if.m dev/sound/pcm/mixer_if.m \
dev/sound/midi/mpu_if.m dev/sound/midi/mpufoi_if.m \
Modified: stable/8/sys/dev/sound/pci/hda/hda_reg.h
==============================================================================
--- stable/8/sys/dev/sound/pci/hda/hda_reg.h Fri Jun 8 12:31:49 2012 (r236749)
+++ stable/8/sys/dev/sound/pci/hda/hda_reg.h Fri Jun 8 12:35:43 2012 (r236750)
@@ -400,7 +400,7 @@
HDA_CMD_GET_UNSOLICITED_RESPONSE_TAG_SHIFT)
#define HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE 0x80
-#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK 0x1f
+#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_MASK 0x3f
#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG_SHIFT 0
#define HDA_CMD_SET_UNSOLICITED_RESPONSE_TAG(param) \
@@ -418,14 +418,10 @@
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_SET_PIN_SENSE, (payload)))
-#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT_MASK 0x80000000
-#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT_SHIFT 31
+#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT 0x80000000
#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK 0x7fffffff
#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT 0
-#define HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(rsp) \
- (((rsp) & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT_MASK) >> \
- HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT_SHIFT)
#define HDA_CMD_GET_PIN_SENSE_IMP_SENSE(rsp) \
(((rsp) & HDA_CMD_GET_PIN_SENSE_IMP_SENSE_MASK) >> \
HDA_CMD_GET_PIN_SENSE_IMP_SENSE_SHIFT)
Copied: stable/8/sys/dev/sound/pci/hda/hdaa.c (from r230130, head/sys/dev/sound/pci/hda/hdaa.c)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/8/sys/dev/sound/pci/hda/hdaa.c Fri Jun 8 12:35:43 2012 (r236750, copy of r230130, head/sys/dev/sound/pci/hda/hdaa.c)
@@ -0,0 +1,5901 @@
+/*-
+ * Copyright (c) 2006 Stephane E. Potvin <sepotvin at videotron.ca>
+ * Copyright (c) 2006 Ariff Abdullah <ariff at FreeBSD.org>
+ * Copyright (c) 2008-2012 Alexander Motin <mav at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Intel High Definition Audio (Audio function) driver for FreeBSD.
+ */
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/pcm/sound.h>
+
+#include <sys/ctype.h>
+#include <sys/taskqueue.h>
+
+#include <dev/sound/pci/hda/hdac.h>
+#include <dev/sound/pci/hda/hdaa.h>
+#include <dev/sound/pci/hda/hda_reg.h>
+
+#include "mixer_if.h"
+
+SND_DECLARE_FILE("$FreeBSD$");
+
+#define hdaa_lock(devinfo) snd_mtxlock((devinfo)->lock)
+#define hdaa_unlock(devinfo) snd_mtxunlock((devinfo)->lock)
+#define hdaa_lockassert(devinfo) snd_mtxassert((devinfo)->lock)
+#define hdaa_lockowned(devinfo) mtx_owned((devinfo)->lock)
+
+static const struct {
+ char *key;
+ uint32_t value;
+} hdaa_quirks_tab[] = {
+ { "softpcmvol", HDAA_QUIRK_SOFTPCMVOL },
+ { "fixedrate", HDAA_QUIRK_FIXEDRATE },
+ { "forcestereo", HDAA_QUIRK_FORCESTEREO },
+ { "eapdinv", HDAA_QUIRK_EAPDINV },
+ { "senseinv", HDAA_QUIRK_SENSEINV },
+ { "ivref50", HDAA_QUIRK_IVREF50 },
+ { "ivref80", HDAA_QUIRK_IVREF80 },
+ { "ivref100", HDAA_QUIRK_IVREF100 },
+ { "ovref50", HDAA_QUIRK_OVREF50 },
+ { "ovref80", HDAA_QUIRK_OVREF80 },
+ { "ovref100", HDAA_QUIRK_OVREF100 },
+ { "ivref", HDAA_QUIRK_IVREF },
+ { "ovref", HDAA_QUIRK_OVREF },
+ { "vref", HDAA_QUIRK_VREF },
+};
+#define HDAA_QUIRKS_TAB_LEN \
+ (sizeof(hdaa_quirks_tab) / sizeof(hdaa_quirks_tab[0]))
+
+#define HDA_BDL_MIN 2
+#define HDA_BDL_MAX 256
+#define HDA_BDL_DEFAULT HDA_BDL_MIN
+
+#define HDA_BLK_MIN HDA_DMA_ALIGNMENT
+#define HDA_BLK_ALIGN (~(HDA_BLK_MIN - 1))
+
+#define HDA_BUFSZ_MIN 4096
+#define HDA_BUFSZ_MAX 65536
+#define HDA_BUFSZ_DEFAULT 16384
+
+#define HDA_PARSE_MAXDEPTH 10
+
+MALLOC_DEFINE(M_HDAA, "hdaa", "HDA Audio");
+
+const char *HDA_COLORS[16] = {"Unknown", "Black", "Grey", "Blue", "Green", "Red",
+ "Orange", "Yellow", "Purple", "Pink", "Res.A", "Res.B", "Res.C", "Res.D",
+ "White", "Other"};
+
+const char *HDA_DEVS[16] = {"Line-out", "Speaker", "Headphones", "CD",
+ "SPDIF-out", "Digital-out", "Modem-line", "Modem-handset", "Line-in",
+ "AUX", "Mic", "Telephony", "SPDIF-in", "Digital-in", "Res.E", "Other"};
+
+const char *HDA_CONNS[4] = {"Jack", "None", "Fixed", "Both"};
+
+const char *HDA_CONNECTORS[16] = {
+ "Unknown", "1/8", "1/4", "ATAPI", "RCA", "Optical", "Digital", "Analog",
+ "DIN", "XLR", "RJ-11", "Combo", "0xc", "0xd", "0xe", "Other" };
+
+const char *HDA_LOCS[64] = {
+ "0x00", "Rear", "Front", "Left", "Right", "Top", "Bottom", "Rear-panel",
+ "Drive-bay", "0x09", "0x0a", "0x0b", "0x0c", "0x0d", "0x0e", "0x0f",
+ "Internal", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "Riser",
+ "0x18", "Onboard", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f",
+ "External", "Ext-Rear", "Ext-Front", "Ext-Left", "Ext-Right", "Ext-Top", "Ext-Bottom", "0x07",
+ "0x28", "0x29", "0x2a", "0x2b", "0x2c", "0x2d", "0x2e", "0x2f",
+ "Other", "0x31", "0x32", "0x33", "0x34", "0x35", "Other-Bott", "Lid-In",
+ "Lid-Out", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "0x3f" };
+
+const char *HDA_GPIO_ACTIONS[8] = {
+ "keep", "set", "clear", "disable", "input", "0x05", "0x06", "0x07"};
+
+/* Default */
+static uint32_t hdaa_fmt[] = {
+ SND_FORMAT(AFMT_S16_LE, 2, 0),
+ 0
+};
+
+static struct pcmchan_caps hdaa_caps = {48000, 48000, hdaa_fmt, 0};
+
+static const struct {
+ uint32_t rate;
+ int valid;
+ uint16_t base;
+ uint16_t mul;
+ uint16_t div;
+} hda_rate_tab[] = {
+ { 8000, 1, 0x0000, 0x0000, 0x0500 }, /* (48000 * 1) / 6 */
+ { 9600, 0, 0x0000, 0x0000, 0x0400 }, /* (48000 * 1) / 5 */
+ { 12000, 0, 0x0000, 0x0000, 0x0300 }, /* (48000 * 1) / 4 */
+ { 16000, 1, 0x0000, 0x0000, 0x0200 }, /* (48000 * 1) / 3 */
+ { 18000, 0, 0x0000, 0x1000, 0x0700 }, /* (48000 * 3) / 8 */
+ { 19200, 0, 0x0000, 0x0800, 0x0400 }, /* (48000 * 2) / 5 */
+ { 24000, 0, 0x0000, 0x0000, 0x0100 }, /* (48000 * 1) / 2 */
+ { 28800, 0, 0x0000, 0x1000, 0x0400 }, /* (48000 * 3) / 5 */
+ { 32000, 1, 0x0000, 0x0800, 0x0200 }, /* (48000 * 2) / 3 */
+ { 36000, 0, 0x0000, 0x1000, 0x0300 }, /* (48000 * 3) / 4 */
+ { 38400, 0, 0x0000, 0x1800, 0x0400 }, /* (48000 * 4) / 5 */
+ { 48000, 1, 0x0000, 0x0000, 0x0000 }, /* (48000 * 1) / 1 */
+ { 64000, 0, 0x0000, 0x1800, 0x0200 }, /* (48000 * 4) / 3 */
+ { 72000, 0, 0x0000, 0x1000, 0x0100 }, /* (48000 * 3) / 2 */
+ { 96000, 1, 0x0000, 0x0800, 0x0000 }, /* (48000 * 2) / 1 */
+ { 144000, 0, 0x0000, 0x1000, 0x0000 }, /* (48000 * 3) / 1 */
+ { 192000, 1, 0x0000, 0x1800, 0x0000 }, /* (48000 * 4) / 1 */
+ { 8820, 0, 0x4000, 0x0000, 0x0400 }, /* (44100 * 1) / 5 */
+ { 11025, 1, 0x4000, 0x0000, 0x0300 }, /* (44100 * 1) / 4 */
+ { 12600, 0, 0x4000, 0x0800, 0x0600 }, /* (44100 * 2) / 7 */
+ { 14700, 0, 0x4000, 0x0000, 0x0200 }, /* (44100 * 1) / 3 */
+ { 17640, 0, 0x4000, 0x0800, 0x0400 }, /* (44100 * 2) / 5 */
+ { 18900, 0, 0x4000, 0x1000, 0x0600 }, /* (44100 * 3) / 7 */
+ { 22050, 1, 0x4000, 0x0000, 0x0100 }, /* (44100 * 1) / 2 */
+ { 25200, 0, 0x4000, 0x1800, 0x0600 }, /* (44100 * 4) / 7 */
+ { 26460, 0, 0x4000, 0x1000, 0x0400 }, /* (44100 * 3) / 5 */
+ { 29400, 0, 0x4000, 0x0800, 0x0200 }, /* (44100 * 2) / 3 */
+ { 33075, 0, 0x4000, 0x1000, 0x0300 }, /* (44100 * 3) / 4 */
+ { 35280, 0, 0x4000, 0x1800, 0x0400 }, /* (44100 * 4) / 5 */
+ { 44100, 1, 0x4000, 0x0000, 0x0000 }, /* (44100 * 1) / 1 */
+ { 58800, 0, 0x4000, 0x1800, 0x0200 }, /* (44100 * 4) / 3 */
+ { 66150, 0, 0x4000, 0x1000, 0x0100 }, /* (44100 * 3) / 2 */
+ { 88200, 1, 0x4000, 0x0800, 0x0000 }, /* (44100 * 2) / 1 */
+ { 132300, 0, 0x4000, 0x1000, 0x0000 }, /* (44100 * 3) / 1 */
+ { 176400, 1, 0x4000, 0x1800, 0x0000 }, /* (44100 * 4) / 1 */
+};
+#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
+
+/****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+static int hdaa_pcmchannel_setup(struct hdaa_chan *);
+
+static void hdaa_widget_connection_select(struct hdaa_widget *, uint8_t);
+static void hdaa_audio_ctl_amp_set(struct hdaa_audio_ctl *,
+ uint32_t, int, int);
+static struct hdaa_audio_ctl *hdaa_audio_ctl_amp_get(struct hdaa_devinfo *,
+ nid_t, int, int, int);
+static void hdaa_audio_ctl_amp_set_internal(struct hdaa_devinfo *,
+ nid_t, int, int, int, int, int, int);
+
+static void hdaa_dump_pin_config(struct hdaa_widget *w, uint32_t conf);
+
+static char *
+hdaa_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
+{
+ static char *ossname[] = SOUND_DEVICE_NAMES;
+ int i, first = 1;
+
+ bzero(buf, len);
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+ if (mask & (1 << i)) {
+ if (first == 0)
+ strlcat(buf, ", ", len);
+ strlcat(buf, ossname[i], len);
+ first = 0;
+ }
+ }
+ return (buf);
+}
+
+static struct hdaa_audio_ctl *
+hdaa_audio_ctl_each(struct hdaa_devinfo *devinfo, int *index)
+{
+ if (devinfo == NULL ||
+ index == NULL || devinfo->ctl == NULL ||
+ devinfo->ctlcnt < 1 ||
+ *index < 0 || *index >= devinfo->ctlcnt)
+ return (NULL);
+ return (&devinfo->ctl[(*index)++]);
+}
+
+static struct hdaa_audio_ctl *
+hdaa_audio_ctl_amp_get(struct hdaa_devinfo *devinfo, nid_t nid, int dir,
+ int index, int cnt)
+{
+ struct hdaa_audio_ctl *ctl;
+ int i, found = 0;
+
+ if (devinfo == NULL || devinfo->ctl == NULL)
+ return (NULL);
+
+ i = 0;
+ while ((ctl = hdaa_audio_ctl_each(devinfo, &i)) != NULL) {
+ if (ctl->enable == 0)
+ continue;
+ if (ctl->widget->nid != nid)
+ continue;
+ if (dir && ctl->ndir != dir)
+ continue;
+ if (index >= 0 && ctl->ndir == HDAA_CTL_IN &&
+ ctl->dir == ctl->ndir && ctl->index != index)
+ continue;
+ found++;
+ if (found == cnt || cnt <= 0)
+ return (ctl);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Jack detection (Speaker/HP redirection) event handler.
+ */
+static void
+hdaa_hp_switch_handler(struct hdaa_devinfo *devinfo, int asid)
+{
+ struct hdaa_audio_as *as;
+ struct hdaa_widget *w;
+ struct hdaa_audio_ctl *ctl;
+ uint32_t val, res;
+ int j;
+
+ as = &devinfo->as[asid];
+ if (as->hpredir < 0)
+ return;
+
+ w = hdaa_widget_get(devinfo, as->pins[15]);
+ if (w == NULL || w->enable == 0 || w->type !=
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ return;
+
+ res = hda_command(devinfo->dev,
+ HDA_CMD_GET_PIN_SENSE(0, as->pins[15]));
+
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->dev,
+ "Pin sense: nid=%d sence=0x%08x",
+ as->pins[15], res);
+ );
+
+ res = (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) != 0;
+ if (devinfo->quirks & HDAA_QUIRK_SENSEINV)
+ res ^= 1;
+
+ HDA_BOOTVERBOSE(
+ printf(" %sconnected\n", res == 0 ? "dis" : "");
+ );
+
+ /* (Un)Mute headphone pin. */
+ ctl = hdaa_audio_ctl_amp_get(devinfo,
+ as->pins[15], HDAA_CTL_IN, -1, 1);
+ if (ctl != NULL && ctl->mute) {
+ /* If pin has muter - use it. */
+ val = (res != 0) ? 0 : 1;
+ if (val != ctl->forcemute) {
+ ctl->forcemute = val;
+ hdaa_audio_ctl_amp_set(ctl,
+ HDAA_AMP_MUTE_DEFAULT,
+ HDAA_AMP_VOL_DEFAULT, HDAA_AMP_VOL_DEFAULT);
+ }
+ } else {
+ /* If there is no muter - disable pin output. */
+ w = hdaa_widget_get(devinfo, as->pins[15]);
+ if (w != NULL && w->type ==
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
+ if (res != 0)
+ val = w->wclass.pin.ctrl |
+ HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
+ else
+ val = w->wclass.pin.ctrl &
+ ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
+ if (val != w->wclass.pin.ctrl) {
+ w->wclass.pin.ctrl = val;
+ hda_command(devinfo->dev,
+ HDA_CMD_SET_PIN_WIDGET_CTRL(0,
+ w->nid, w->wclass.pin.ctrl));
+ }
+ }
+ }
+ /* (Un)Mute other pins. */
+ for (j = 0; j < 15; j++) {
+ if (as->pins[j] <= 0)
+ continue;
+ ctl = hdaa_audio_ctl_amp_get(devinfo,
+ as->pins[j], HDAA_CTL_IN, -1, 1);
+ if (ctl != NULL && ctl->mute) {
+ /* If pin has muter - use it. */
+ val = (res != 0) ? 1 : 0;
+ if (val == ctl->forcemute)
+ continue;
+ ctl->forcemute = val;
+ hdaa_audio_ctl_amp_set(ctl,
+ HDAA_AMP_MUTE_DEFAULT,
+ HDAA_AMP_VOL_DEFAULT, HDAA_AMP_VOL_DEFAULT);
+ continue;
+ }
+ /* If there is no muter - disable pin output. */
+ w = hdaa_widget_get(devinfo, as->pins[j]);
+ if (w != NULL && w->type ==
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
+ if (res != 0)
+ val = w->wclass.pin.ctrl &
+ ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
+ else
+ val = w->wclass.pin.ctrl |
+ HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
+ if (val != w->wclass.pin.ctrl) {
+ w->wclass.pin.ctrl = val;
+ hda_command(devinfo->dev,
+ HDA_CMD_SET_PIN_WIDGET_CTRL(0,
+ w->nid, w->wclass.pin.ctrl));
+ }
+ }
+ }
+}
+
+/*
+ * Callback for poll based jack detection.
+ */
+static void
+hdaa_jack_poll_callback(void *arg)
+{
+ struct hdaa_devinfo *devinfo = arg;
+ int i;
+
+ hdaa_lock(devinfo);
+ if (devinfo->poll_ival == 0) {
+ hdaa_unlock(devinfo);
+ return;
+ }
+ for (i = 0; i < devinfo->ascnt; i++) {
+ if (devinfo->as[i].hpredir < 0)
+ continue;
+ hdaa_hp_switch_handler(devinfo, i);
+ }
+ callout_reset(&devinfo->poll_jack, devinfo->poll_ival,
+ hdaa_jack_poll_callback, devinfo);
+ hdaa_unlock(devinfo);
+}
+
+/*
+ * Jack detection initializer.
+ */
+static void
+hdaa_hp_switch_init(struct hdaa_devinfo *devinfo)
+{
+ struct hdaa_audio_as *as = devinfo->as;
+ struct hdaa_widget *w;
+ int i, poll = 0;
+
+ for (i = 0; i < devinfo->ascnt; i++) {
+ if (as[i].hpredir < 0)
+ continue;
+
+ w = hdaa_widget_get(devinfo, as[i].pins[15]);
+ if (w == NULL || w->enable == 0 || w->type !=
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+ (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
+ device_printf(devinfo->dev,
+ "No jack detection support at pin %d\n",
+ as[i].pins[15]);
+ continue;
+ }
+ if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
+ as[i].unsol = HDAC_UNSOL_ALLOC(
+ device_get_parent(devinfo->dev), devinfo->dev,
+ w->nid);
+ hda_command(devinfo->dev,
+ HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid,
+ HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
+ as[i].unsol));
+ } else
+ poll = 1;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->dev,
+ "Headphones redirection "
+ "for as=%d nid=%d using %s.\n",
+ i, w->nid,
+ (poll != 0) ? "polling" : "unsolicited responses");
+ );
+ hdaa_hp_switch_handler(devinfo, i);
+ }
+ if (poll) {
+ callout_reset(&devinfo->poll_jack, 1,
+ hdaa_jack_poll_callback, devinfo);
+ }
+}
+
+static void
+hdaa_hp_switch_deinit(struct hdaa_devinfo *devinfo)
+{
+ struct hdaa_audio_as *as = devinfo->as;
+ struct hdaa_widget *w;
+ int i;
+
+ for (i = 0; i < devinfo->ascnt; i++) {
+ if (as[i].unsol < 0)
+ continue;
+ w = hdaa_widget_get(devinfo, as[i].pins[15]);
+ if (w == NULL || w->enable == 0 || w->type !=
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ hda_command(devinfo->dev,
+ HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid, 0));
+ HDAC_UNSOL_FREE(
+ device_get_parent(devinfo->dev), devinfo->dev,
+ as[i].unsol);
+ as[i].unsol = -1;
+ }
+}
+
+uint32_t
+hdaa_widget_pin_patch(uint32_t config, const char *str)
+{
+ char buf[256];
+ char *key, *value, *rest, *bad;
+ int ival, i;
+
+ strlcpy(buf, str, sizeof(buf));
+ rest = buf;
+ while ((key = strsep(&rest, "=")) != NULL) {
+ value = strsep(&rest, " \t");
+ if (value == NULL)
+ break;
+ ival = strtol(value, &bad, 10);
+ if (strcmp(key, "seq") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK);
+ } else if (strcmp(key, "as") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK);
+ } else if (strcmp(key, "misc") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_MISC_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_MISC_MASK);
+ } else if (strcmp(key, "color") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_COLOR_MASK;
+ if (bad[0] == 0) {
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_COLOR_MASK);
+ };
+ for (i = 0; i < 16; i++) {
+ if (strcasecmp(HDA_COLORS[i], value) == 0) {
+ config |= (i << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT);
+ break;
+ }
+ }
+ } else if (strcmp(key, "ctype") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list