From ca9c1aaec4187fc9922cfb6b283fffef89286943 Mon Sep 17 00:00:00 2001 From: Ian Molton Date: Tue, 6 Jan 2009 20:11:51 +0000 Subject: ASoC: dapm: Allow explictly named mixer controls This patch allows you to define the mixer paths as having the same name as the paths they represent. This is required to support codecs such as the wm9705 neatly without extra controls in the alsa mixer. Signed-off-by: Ian Molton --- Documentation/sound/alsa/soc/dapm.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt index 46f9684d0b2..9e6763264a2 100644 --- a/Documentation/sound/alsa/soc/dapm.txt +++ b/Documentation/sound/alsa/soc/dapm.txt @@ -116,6 +116,9 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, ARRAY_SIZE(wm8731_output_mixer_controls)), +If you dont want the mixer elements prefixed with the name of the mixer widget, +you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same +as for SND_SOC_DAPM_MIXER. 2.3 Platform/Machine domain Widgets ----------------------------------- -- cgit v1.2.3 From d453379bc5d34d7f55b55931245de5ac1896fd8d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 28 Dec 2008 16:45:34 +0100 Subject: ALSA: Update description of snd_card_create() in documents Signed-off-by: Takashi Iwai --- .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 44 ++++++++++++---------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 87a7c07ab65..320384c1791 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -492,9 +492,9 @@ } /* (2) */ - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); - if (card == NULL) - return -ENOMEM; + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + if (err < 0) + return err; /* (3) */ err = snd_mychip_create(card, pci, &chip); @@ -590,8 +590,9 @@ @@ -809,26 +810,28 @@ As mentioned above, to create a card instance, call - snd_card_new(). + snd_card_create(). - The function takes four arguments, the card-index number, the + The function takes five arguments, the card-index number, the id string, the module pointer (usually THIS_MODULE), - and the size of extra-data space. The last argument is used to + the size of extra-data space, and the pointer to return the + card instance. The extra_size argument is used to allocate card->private_data for the chip-specific data. Note that these data - are allocated by snd_card_new(). + are allocated by snd_card_create(). @@ -915,15 +918,16 @@
- 1. Allocating via <function>snd_card_new()</function>. + 1. Allocating via <function>snd_card_create()</function>. As mentioned above, you can pass the extra-data-length - to the 4th argument of snd_card_new(), i.e. + to the 4th argument of snd_card_create(), i.e. @@ -952,8 +956,8 @@ After allocating a card instance via - snd_card_new() (with - NULL on the 4th arg), call + snd_card_create() (with + 0 on the 4th arg), call kzalloc(). @@ -961,7 +965,7 @@ @@ -5750,8 +5754,9 @@ struct _snd_pcm_runtime { .... struct snd_card *card; struct mychip *chip; + int err; .... - card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL); + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); .... chip = kzalloc(sizeof(*chip), GFP_KERNEL); .... @@ -5763,7 +5768,7 @@ struct _snd_pcm_runtime { When you created the chip data with - snd_card_new(), it's anyway accessible + snd_card_create(), it's anyway accessible via private_data field. @@ -5775,9 +5780,10 @@ struct _snd_pcm_runtime { .... struct snd_card *card; struct mychip *chip; + int err; .... - card = snd_card_new(index[dev], id[dev], THIS_MODULE, - sizeof(struct mychip)); + err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct mychip), &card); .... chip = card->private_data; .... -- cgit v1.2.3 From 08989930f91e4802b94e03eb54e5385bac112811 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 21 Jan 2009 07:43:23 +0100 Subject: ALSA: hda - Remove old models for STAC9872 from the document Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 64eb1100eec..75914bcdce7 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -352,5 +352,4 @@ STAC92HD83* STAC9872 ======== - vaio Setup for VAIO FE550G/SZ110 - vaio-ar Setup for VAIO AR + N/A -- cgit v1.2.3 From d9a4268ee92ba1a2355c892a3add1fa66856b510 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Jan 2009 17:40:18 +0100 Subject: ALSA: hda - Add quirk for Gateway %1616 laptop Gateway T1616 laptop needs EAPD always on while the current STAC9205 code turns off per HP plug. Added a new model "eapd" to keep it on. Reference: Novell bnc#467597 https://bugzilla.novell.com/show_bug.cgi?id=467597 Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 75914bcdce7..ef6b22e2541 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -285,6 +285,7 @@ STAC9205/9254 dell-m42 Dell (unknown) dell-m43 Dell Precision dell-m44 Dell Inspiron + eapd Keep EAPD on (e.g. Gateway T1616) STAC9220/9221 ============= -- cgit v1.2.3 From c96330b083ce88b9fea428df99b4631f1b6410ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Jan 2009 08:23:03 +0100 Subject: ALSA: Add description of new snd-msnd-* drivers Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 841a9365d5f..ba7b14a13ab 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1185,6 +1185,54 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple devices and PnP. + Module snd-msnd-classic + ----------------------- + + Module for Turtle Beach MultiSound Classic, Tahiti or Monterey + soundcards. + + io - Port # for msnd-classic card + irq - IRQ # for msnd-classic card + mem - Memory address (0xb0000, 0xc8000, 0xd0000, 0xd8000, + 0xe0000 or 0xe8000) + write_ndelay - enable write ndelay (default = 1) + calibrate_signal - calibrate signal (default = 0) + isapnp - ISA PnP detection - 0 = disable, 1 = enable (default) + digital - Digital daughterboard present (default = 0) + cfg - Config port (0x250, 0x260 or 0x270) default = PnP + reset - Reset all devices + mpu_io - MPU401 I/O port + mpu_irq - MPU401 irq# + ide_io0 - IDE port #0 + ide_io1 - IDE port #1 + ide_irq - IDE irq# + joystick_io - Joystick I/O port + + The driver requires firmware files "turtlebeach/msndinit.bin" and + "turtlebeach/msndperm.bin" in the proper firmware directory. + + See Documentation/sound/oss/MultiSound for important information + about this driver. Note that it has been discontinued, but the + Voyetra Turtle Beach knowledge base entry for it is still available + at + http://www.turtlebeach.com/site/kb_ftp/790.asp + + Module snd-msnd-pinnacle + ------------------------ + + Module for Turtle Beach MultiSound Pinnacle/Fiji soundcards. + + io - Port # for pinnacle/fiji card + irq - IRQ # for pinnalce/fiji card + mem - Memory address (0xb0000, 0xc8000, 0xd0000, 0xd8000, + 0xe0000 or 0xe8000) + write_ndelay - enable write ndelay (default = 1) + calibrate_signal - calibrate signal (default = 0) + isapnp - ISA PnP detection - 0 = disable, 1 = enable (default) + + The driver requires firmware files "turtlebeach/pndspini.bin" and + "turtlebeach/pndsperm.bin" in the proper firmware directory. + Module snd-mtpav ---------------- -- cgit v1.2.3 From 9e128fddcc589db4e7d9e8328f656ae4a21a2808 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 29 Jan 2009 11:49:10 +0100 Subject: ALSA: Add missing description of snd-cmi8330 module parameters Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 841a9365d5f..7134a8f7044 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -346,6 +346,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. sbirq - IRQ # for CMI8330 chip (SB16) sbdma8 - 8bit DMA # for CMI8330 chip (SB16) sbdma16 - 16bit DMA # for CMI8330 chip (SB16) + fmport - (optional) OPL3 I/O port + mpuport - (optional) MPU401 I/O port + mpuirq - (optional) MPU401 irq # This module supports multiple cards and autoprobe. -- cgit v1.2.3 From 504a06d8b05cb5b214c9b97752d8451e88d9ef81 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 30 Jan 2009 19:59:10 +0100 Subject: ALSA: Add description of new fm_port option for snd-es1688 driver Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7134a8f7044..a763b76afe5 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -609,6 +609,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for ESS AudioDrive ES-1688 and ES-688 sound cards. port - port # for ES-1688 chip (0x220,0x240,0x260) + fm_port - port # for OPL3 (option; share the same port as default) mpu_port - port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default) irq - IRQ # for ES-1688 chip (5,7,9,10) mpu_irq - IRQ # for MPU-401 port (5,7,9,10) -- cgit v1.2.3 From 123848e77623b9996288e85433985439c157fcd0 Mon Sep 17 00:00:00 2001 From: Tony Vroon Date: Tue, 3 Feb 2009 11:13:34 +0000 Subject: ALSA: Document tyan model for Realtek ALC262 As just pointed out to me, the new tyan model for ALC262 was implemented but not documented. This adds the board to the list, using both its marketing name (Thunder n6650W) and its model number (S2915-E). Signed-off-by: Tony Vroon Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index c9df9db5835..8f40999a456 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -56,6 +56,7 @@ ALC262 sony-assamd Sony ASSAMD toshiba-s06 Toshiba S06 toshiba-rx1 Toshiba RX1 + tyan Tyan Thunder n6650W (S2915-E) ultra Samsung Q1 Ultra Vista model lenovo-3000 Lenovo 3000 y410 nec NEC Versa S9100 -- cgit v1.2.3 From 6146f0d5e47ca4047ffded0fb79b6c25359b386c Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 4 Feb 2009 09:06:57 -0500 Subject: integrity: IMA hooks This patch replaces the generic integrity hooks, for which IMA registered itself, with IMA integrity hooks in the appropriate places directly in the fs directory. Signed-off-by: Mimi Zohar Acked-by: Serge Hallyn Signed-off-by: James Morris --- Documentation/kernel-parameters.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a2d8805c03d..7c67b94d182 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -44,6 +44,7 @@ parameter is applicable: FB The frame buffer device is enabled. HW Appropriate hardware is enabled. IA-64 IA-64 architecture is enabled. + IMA Integrity measurement architecture is enabled. IOSCHED More than one I/O scheduler is enabled. IP_PNP IP DHCP, BOOTP, or RARP is enabled. ISAPNP ISA PnP code is enabled. -- cgit v1.2.3 From 3323eec921efd815178a23107ab63588c605c0b2 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 4 Feb 2009 09:06:58 -0500 Subject: integrity: IMA as an integrity service provider IMA provides hardware (TPM) based measurement and attestation for file measurements. As the Trusted Computing (TPM) model requires, IMA measures all files before they are accessed in any way (on the integrity_bprm_check, integrity_path_check and integrity_file_mmap hooks), and commits the measurements to the TPM. Once added to the TPM, measurements can not be removed. In addition, IMA maintains a list of these file measurements, which can be used to validate the aggregate value stored in the TPM. The TPM can sign these measurements, and thus the system can prove, to itself and to a third party, the system's integrity in a way that cannot be circumvented by malicious or compromised software. - alloc ima_template_entry before calling ima_store_template() - log ima_add_boot_aggregate() failure - removed unused IMA_TEMPLATE_NAME_LEN - replaced hard coded string length with #define name Signed-off-by: Mimi Zohar Signed-off-by: James Morris --- Documentation/kernel-parameters.txt | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7c67b94d182..31e0c2c3c6e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -895,6 +895,15 @@ and is between 256 and 4096 characters. It is defined in the file ihash_entries= [KNL] Set number of hash buckets for inode cache. + ima_audit= [IMA] + Format: { "0" | "1" } + 0 -- integrity auditing messages. (Default) + 1 -- enable informational integrity auditing messages. + + ima_hash= [IMA] + Formt: { "sha1" | "md5" } + default: "sha1" + in2000= [HW,SCSI] See header of drivers/scsi/in2000.c. -- cgit v1.2.3 From 4af4662fa4a9dc62289c580337ae2506339c4729 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 4 Feb 2009 09:07:00 -0500 Subject: integrity: IMA policy Support for a user loadable policy through securityfs with support for LSM specific policy data. - free invalid rule in ima_parse_add_rule() Signed-off-by: Mimi Zohar Acked-by: Serge Hallyn Signed-off-by: James Morris --- Documentation/ABI/testing/ima_policy | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/ABI/testing/ima_policy (limited to 'Documentation') diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy new file mode 100644 index 00000000000..6434f0df012 --- /dev/null +++ b/Documentation/ABI/testing/ima_policy @@ -0,0 +1,61 @@ +What: security/ima/policy +Date: May 2008 +Contact: Mimi Zohar +Description: + The Trusted Computing Group(TCG) runtime Integrity + Measurement Architecture(IMA) maintains a list of hash + values of executables and other sensitive system files + loaded into the run-time of this system. At runtime, + the policy can be constrained based on LSM specific data. + Policies are loaded into the securityfs file ima/policy + by opening the file, writing the rules one at a time and + then closing the file. The new policy takes effect after + the file ima/policy is closed. + + rule format: action [condition ...] + + action: measure | dont_measure + condition:= base | lsm + base: [[func=] [mask=] [fsmagic=] [uid=]] + lsm: [[subj_user=] [subj_role=] [subj_type=] + [obj_user=] [obj_role=] [obj_type=]] + + base: func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION] + mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] + fsmagic:= hex value + uid:= decimal value + lsm: are LSM specific + + default policy: + # PROC_SUPER_MAGIC + dont_measure fsmagic=0x9fa0 + # SYSFS_MAGIC + dont_measure fsmagic=0x62656572 + # DEBUGFS_MAGIC + dont_measure fsmagic=0x64626720 + # TMPFS_MAGIC + dont_measure fsmagic=0x01021994 + # SECURITYFS_MAGIC + dont_measure fsmagic=0x73636673 + + measure func=BPRM_CHECK + measure func=FILE_MMAP mask=MAY_EXEC + measure func=INODE_PERM mask=MAY_READ uid=0 + + The default policy measures all executables in bprm_check, + all files mmapped executable in file_mmap, and all files + open for read by root in inode_permission. + + Examples of LSM specific definitions: + + SELinux: + # SELINUX_MAGIC + dont_measure fsmagic=0xF97CFF8C + + dont_measure obj_type=var_log_t + dont_measure obj_type=auditd_log_t + measure subj_user=system_u func=INODE_PERM mask=MAY_READ + measure subj_role=system_r func=INODE_PERM mask=MAY_READ + + Smack: + measure subj_user=_ func=INODE_PERM mask=MAY_READ -- cgit v1.2.3 From ae374d667a54fb5e2c9c0c4e87b206bd665f3ad6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Feb 2009 08:33:55 +0100 Subject: ALSA: hda - Update documentation Update documentation regarding codec probing; the new probe_only option and the new probe_mask usage. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 3 +++ Documentation/sound/alsa/HD-Audio.txt | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 841a9365d5f..012afd7afb1 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -757,6 +757,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. model - force the model name position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) + When the bit 8 (0x100) is set, the lower 8 bits are used + as the "fixed" codec slots; i.e. the driver probes the + slots regardless what hardware reports back probe_only - Only probing and no codec initialization (default=off); Useful to check the initial codec status for debugging bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 8d68fff7183..99f7fbbe3e6 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -109,6 +109,13 @@ slot, pass `probe_mask=1`. For the first and the third slots, pass Since 2.6.29 kernel, the driver has a more robust probing method, so this error might happen rarely, though. +On a machine with a broken BIOS, sometimes you need to force the +driver to probe the codec slots the hardware doesn't report for use. +In such a case, turn the bit 8 (0x100) of `probe_mask` option on. +Then the rest 8 bits are passed as the codec slots to probe +unconditionally. For example, `probe_mask=0x103` will force to probe +the codec slots 0 and 1 no matter what the hardware reports. + Interrupt Handling ~~~~~~~~~~~~~~~~~~ @@ -461,6 +468,16 @@ run with `--no-upload` option, and attach the generated file. There are some other useful options. See `--help` option output for details. +When a probe error occurs or when the driver obviously assigns a +mismatched model, it'd be helpful to load the driver with +`probe_only=1` option (at best after the cold reboot) and run +alsa-info at this state. With this option, the driver won't configure +the mixer and PCM but just tries to probe the codec slot. After +probing, the proc file is available, so you can get the raw codec +information before modified by the driver. Of course, the driver +isn't usable with `probe_only=1`. But you can continue the +configuration via hwdep sysfs file if hda-reconfig option is enabled. + hda-verb ~~~~~~~~ -- cgit v1.2.3 From 27e089888fb1a3d1d13892262f9d522b03985044 Mon Sep 17 00:00:00 2001 From: Aristeu Sergio Rozanski Filho Date: Thu, 12 Feb 2009 17:50:37 -0500 Subject: ALSA: hda: add quirk for Lenovo X200 laptop dock Currently the HP connector on X200 dock doesn't detect when a HP is connected nor allows sound to be played using it. This patch fixes the problem by adding a quirk for this specific model. It's possible that others have the same NID (0x19) to report when dock HP is connected, but I don't have access to any. Please Cc me in the reply since I'm not subscribed to alsa-devel@. Signed-off-by: Aristeu Rozanski Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 8f40999a456..0e52d273ce9 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -262,6 +262,7 @@ Conexant 5051 ============= laptop Basic Laptop config (default) hp HP Spartan laptop + lenovo-x200 Lenovo X200 laptop STAC9200 ======== -- cgit v1.2.3 From c844a5d38e4247fc71e371221cf762a2a44d565b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Feb 2009 23:17:33 +0100 Subject: ALSA: Fix documentation for snd-cs4236 driver Updated; removal of snd-cs4232 entry. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 30 +++++-------------------- 1 file changed, 5 insertions(+), 25 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index a763b76afe5..57fe4f3ca2c 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -391,34 +391,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. - Module snd-cs4232 - ----------------- - - Module for sound cards based on CS4232/CS4232A ISA chips. - - isapnp - ISA PnP detection - 0 = disable, 1 = enable (default) - - with isapnp=0, the following options are available: - - port - port # for CS4232 chip (PnP setup - 0x534) - cport - control port # for CS4232 chip (PnP setup - 0x120,0x210,0xf00) - mpu_port - port # for MPU-401 UART (PnP setup - 0x300), -1 = disable - fm_port - FM port # for CS4232 chip (PnP setup - 0x388), -1 = disable - irq - IRQ # for CS4232 chip (5,7,9,11,12,15) - mpu_irq - IRQ # for MPU-401 UART (9,11,12,15) - dma1 - first DMA # for CS4232 chip (0,1,3) - dma2 - second DMA # for Yamaha CS4232 chip (0,1,3), -1 = disable - - This module supports multiple cards. This module does not support autoprobe - (if ISA PnP is not used) thus main port must be specified!!! Other ports are - optional. - - The power-management is supported. - Module snd-cs4236 ----------------- - Module for sound cards based on CS4235/CS4236/CS4236B/CS4237B/ + Module for sound cards based on CS4232/CS4232A, + CS4235/CS4236/CS4236B/CS4237B/ CS4238B/CS4239 ISA chips. isapnp - ISA PnP detection - 0 = disable, 1 = enable (default) @@ -440,6 +417,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. + This module is aliased as snd-cs4232 since it provides the old + snd-cs4232 functionality, too. + Module snd-cs4281 ----------------- -- cgit v1.2.3 From 4dd3a29f295799295eac819bbf540690fbe30c16 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 18 Feb 2009 19:09:23 +0900 Subject: sound: fix opensound URL in oss Introduction Signed-off-by: Yoichi Yuasa Signed-off-by: Takashi Iwai --- Documentation/sound/oss/Introduction | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/oss/Introduction b/Documentation/sound/oss/Introduction index f04ba6bb739..75d967ff926 100644 --- a/Documentation/sound/oss/Introduction +++ b/Documentation/sound/oss/Introduction @@ -80,7 +80,7 @@ Notes: additional features. 2. The commercial OSS driver may be obtained from the site: - http://www/opensound.com. This may be used for cards that + http://www.opensound.com. This may be used for cards that are unsupported by the kernel driver, or may be used by other operating systems. -- cgit v1.2.3 From eca985d28e1a8092ba2686ec5485fd688df5cfb3 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 18 Feb 2009 19:07:18 +0100 Subject: sound: Remove documentation for OSS CS4232 driver There is no OSS cs4232 driver in the kernel any more and this documentation does not contain any info useful for ALSA driver. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- Documentation/sound/oss/CS4232 | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 Documentation/sound/oss/CS4232 (limited to 'Documentation') diff --git a/Documentation/sound/oss/CS4232 b/Documentation/sound/oss/CS4232 deleted file mode 100644 index 7d6af7a5c1c..00000000000 --- a/Documentation/sound/oss/CS4232 +++ /dev/null @@ -1,23 +0,0 @@ -To configure the Crystal CS423x sound chip and activate its DSP functions, -modules may be loaded in this order: - - modprobe sound - insmod ad1848 - insmod uart401 - insmod cs4232 io=* irq=* dma=* dma2=* - -This is the meaning of the parameters: - - io--I/O address of the Windows Sound System (normally 0x534) - irq--IRQ of this device - dma and dma2--DMA channels (DMA2 may be 0) - -On some cards, the board attempts to do non-PnP setup, and fails. If you -have problems, use Linux' PnP facilities. - -To get MIDI facilities add - - insmod opl3 io=* - -where "io" is the I/O address of the OPL3 synthesizer. This will be shown -in /proc/sys/pnp and is normally 0x388. -- cgit v1.2.3 From f1085c4f319f1e43c95718045a235f276cc4b615 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2009 14:50:35 +0100 Subject: ALSA: hda - Update documentation for pincfg sysfs entries Added the brief descriptions of new sysfs entries for pint default config values. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 99f7fbbe3e6..9c51e104546 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -365,10 +365,22 @@ modelname:: to this file. init_verbs:: The extra verbs to execute at initialization. You can add a verb by - writing to this file. Pass tree numbers, nid, verb and parameter. + writing to this file. Pass three numbers: nid, verb and parameter. hints:: Shows hint strings for codec parsers for any use. Right now it's not used. +init_pin_configs:: + Shows the initial pin default config values set by BIOS. +override_pin_configs:: + Shows the pin default config values to override the BIOS setup. + Writing this (with two numbers, NID and value) appends the new + value. The given will be used instead of the initial BIOS value at + the next reconfiguration time. +cur_pin_configs:: + Shows the pin default values set by the codec parser explicitly. + This doesn't show all pin values but only the changed values by + the parser. That is, if the parser doesn't change the pin default + config values by itself, this will contain nothing. reconfig:: Triggers the codec re-configuration. When any value is written to this file, the driver re-initialize and parses the codec tree -- cgit v1.2.3 From 346ff70fdbe9093947b9494fe714c89cafcceade Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Feb 2009 09:42:57 +0100 Subject: ALSA: hda - Rename {override,cur}_pin with {user,driver}_pin Rename from override_pin and cur_pin with user_pin and driver_pin, respectively, to be a bit more intuitive. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 9c51e104546..f590850c149 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -371,16 +371,16 @@ hints:: not used. init_pin_configs:: Shows the initial pin default config values set by BIOS. -override_pin_configs:: - Shows the pin default config values to override the BIOS setup. - Writing this (with two numbers, NID and value) appends the new - value. The given will be used instead of the initial BIOS value at - the next reconfiguration time. -cur_pin_configs:: +driver_pin_configs:: Shows the pin default values set by the codec parser explicitly. This doesn't show all pin values but only the changed values by the parser. That is, if the parser doesn't change the pin default config values by itself, this will contain nothing. +user_pin_configs:: + Shows the pin default config values to override the BIOS setup. + Writing this (with two numbers, NID and value) appends the new + value. The given will be used instead of the initial BIOS value at + the next reconfiguration time. reconfig:: Triggers the codec re-configuration. When any value is written to this file, the driver re-initialize and parses the codec tree -- cgit v1.2.3 From 5e7b8e0d87091ae21b291588817b5359a5e00795 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Feb 2009 09:45:59 +0100 Subject: ALSA: hda - Make user_pin overriding the driver setup Make user_pin overriding even the driver pincfg, e.g. the static / fixed pin config table in patch_sigmatel.c. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index f590850c149..a4e5ef87af6 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -380,7 +380,8 @@ user_pin_configs:: Shows the pin default config values to override the BIOS setup. Writing this (with two numbers, NID and value) appends the new value. The given will be used instead of the initial BIOS value at - the next reconfiguration time. + the next reconfiguration time. Note that this config will override + even the driver pin configs, too. reconfig:: Triggers the codec re-configuration. When any value is written to this file, the driver re-initialize and parses the codec tree -- cgit v1.2.3 From 39c2871eeaeeddcbecee29ec905ec528a057ca52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Feb 2009 14:14:51 +0100 Subject: ALSA: hda - Add an example about pin reconfiguration Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index a4e5ef87af6..99958be7b45 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -391,6 +391,14 @@ clear:: Resets the codec, removes the mixer elements and PCM stuff of the specified codec, and clear all init verbs and hints. +For example, when you want to change the pin default configuration +value of the pin widget 0x14 to 0x9993013f, and let the driver +re-configure based on that state, run like below: +------------------------------------------------------------------------ + # echo 0x14 0x9993013f > /sys/class/sound/hwC0D0/user_pin_configs + # echo 1 > /sys/class/sound/hwC0D0/reconfig +------------------------------------------------------------------------ + Power-Saving ~~~~~~~~~~~~ -- cgit v1.2.3 From ed12978453a3845c947695e7ad32bb3ede444813 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Wed, 4 Feb 2009 01:17:41 +0100 Subject: [CPUFREQ] Introduce /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_transition_latency It's not only useful for the ondemand and conservative governors, but also for userspace daemons to know about the HW transition latency of the CPU. It is especially useful for userspace to know about this value when the ondemand or conservative governors are run. The sampling rate control value depends on it and for userspace being able to set sane tuning values there it has to know about the transition latency. Signed-off-by: Thomas Renninger Signed-off-by: Dave Jones --- Documentation/cpu-freq/user-guide.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt index 917918f84fc..75f41193f3e 100644 --- a/Documentation/cpu-freq/user-guide.txt +++ b/Documentation/cpu-freq/user-guide.txt @@ -152,6 +152,18 @@ cpuinfo_min_freq : this file shows the minimum operating frequency the processor can run at(in kHz) cpuinfo_max_freq : this file shows the maximum operating frequency the processor can run at(in kHz) +cpuinfo_transition_latency The time it takes on this CPU to + switch between two frequencies in nano + seconds. If unknown or known to be + that high that the driver does not + work with the ondemand governor, -1 + (CPUFREQ_ETERNAL) will be returned. + Using this information can be useful + to choose an appropriate polling + frequency for a kernel governor or + userspace daemon. Make sure to not + switch the frequency too often + resulting in performance loss. scaling_driver : this file shows what cpufreq driver is used to set the frequency on this CPU -- cgit v1.2.3 From 9411b4ef7fcb534fe1582fe02738254e398dd931 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Wed, 4 Feb 2009 11:54:04 +0100 Subject: [CPUFREQ] ondemand/conservative: deprecate sampling_rate{min,max} The same info can be obtained via the transition_latency sysfs file Signed-off-by: Thomas Renninger Signed-off-by: Dave Jones --- Documentation/cpu-freq/governors.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt index 5b0cfa67aff..9b1851297d4 100644 --- a/Documentation/cpu-freq/governors.txt +++ b/Documentation/cpu-freq/governors.txt @@ -119,8 +119,14 @@ want the kernel to look at the CPU usage and to make decisions on what to do about the frequency. Typically this is set to values of around '10000' or more. -show_sampling_rate_(min|max): the minimum and maximum sampling rates -available that you may set 'sampling_rate' to. +show_sampling_rate_(min|max): THIS INTERFACE IS DEPRECATED, DON'T USE IT. +You can use wider ranges now and the general +cpuinfo_transition_latency variable (cmp. with user-guide.txt) can be +used to obtain exactly the same info: +show_sampling_rate_min = transtition_latency * 500 / 1000 +show_sampling_rate_max = transtition_latency * 500000 / 1000 +(divided by 1000 is to illustrate that sampling rate is in us and +transition latency is exported ns). up_threshold: defines what the average CPU usage between the samplings of 'sampling_rate' needs to be for the kernel to make a decision on -- cgit v1.2.3 From 112124ab0a9f507a0d7fdbb1e1ed2b9a24f8c4ea Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Wed, 4 Feb 2009 11:55:12 +0100 Subject: [CPUFREQ] ondemand/conservative: sanitize sampling_rate restrictions Limit sampling rate to transition_latency * 100 or kernel limits. If sampling_rate is tried to be set too low, set the lowest allowed value. Signed-off-by: Thomas Renninger Signed-off-by: Dave Jones --- Documentation/cpu-freq/governors.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt index 9b1851297d4..ce73f3eb5dd 100644 --- a/Documentation/cpu-freq/governors.txt +++ b/Documentation/cpu-freq/governors.txt @@ -117,7 +117,19 @@ accessible parameters: sampling_rate: measured in uS (10^-6 seconds), this is how often you want the kernel to look at the CPU usage and to make decisions on what to do about the frequency. Typically this is set to values of -around '10000' or more. +around '10000' or more. It's default value is (cmp. with users-guide.txt): +transition_latency * 1000 +The lowest value you can set is: +transition_latency * 100 or it may get restricted to a value where it +makes not sense for the kernel anymore to poll that often which depends +on your HZ config variable (HZ=1000: max=20000us, HZ=250: max=5000). +Be aware that transition latency is in ns and sampling_rate is in us, so you +get the same sysfs value by default. +Sampling rate should always get adjusted considering the transition latency +To set the sampling rate 750 times as high as the transition latency +in the bash (as said, 1000 is default), do: +echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) \ + >ondemand/sampling_rate show_sampling_rate_(min|max): THIS INTERFACE IS DEPRECATED, DON'T USE IT. You can use wider ranges now and the general -- cgit v1.2.3 From 930738de602d2ceb0d1c1b368fe2a8d2a974ab72 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 26 Feb 2009 09:27:20 +0100 Subject: sound: virtuoso: add Xonar Essence STX support Add support for the Asus Xonar Essence STX sound card. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 841a9365d5f..1356d2a6772 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1824,7 +1824,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ------------------- Module for sound cards based on the Asus AV100/AV200 chips, - i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe). + i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX. This module supports autoprobe and multiple cards. -- cgit v1.2.3 From 1607b8ea0a4cc20752978fadb027daafc8a2d93c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Feb 2009 16:50:43 +0100 Subject: ALSA: hda - Add model=auto for STAC/IDT codecs Added the model=auto to STAC/IDT codecs to use the BIOS default setup explicitly. It can be used to disable the device-specific model quirk in the driver. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 0e52d273ce9..a448bbefd48 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -280,6 +280,7 @@ STAC9200 gateway-m4 Gateway laptops with EAPD control gateway-m4-2 Gateway laptops with EAPD control panasonic Panasonic CF-74 + auto BIOS setup (default) STAC9205/9254 ============= @@ -288,6 +289,7 @@ STAC9205/9254 dell-m43 Dell Precision dell-m44 Dell Inspiron eapd Keep EAPD on (e.g. Gateway T1616) + auto BIOS setup (default) STAC9220/9221 ============= @@ -311,6 +313,7 @@ STAC9220/9221 dell-d82 Dell (unknown) dell-m81 Dell (unknown) dell-m82 Dell XPS M1210 + auto BIOS setup (default) STAC9202/9250/9251 ================== @@ -322,6 +325,7 @@ STAC9202/9250/9251 m3 Some Gateway MX series laptops m5 Some Gateway MX series laptops (MP6954) m6 Some Gateway NX series laptops + auto BIOS setup (default) STAC9227/9228/9229/927x ======================= @@ -331,6 +335,7 @@ STAC9227/9228/9229/927x 5stack D965 5stack + SPDIF dell-3stack Dell Dimension E520 dell-bios Fixes with Dell BIOS setup + auto BIOS setup (default) STAC92HD71B* ============ @@ -339,6 +344,7 @@ STAC92HD71B* dell-m4-2 Dell desktops dell-m4-3 Dell desktops hp-m4 HP dv laptops + auto BIOS setup (default) STAC92HD73* =========== @@ -348,11 +354,13 @@ STAC92HD73* dell-m6-dmic Dell desktops/laptops with digital mics dell-m6 Dell desktops/laptops with both type of mics dell-eq Dell desktops/laptops + auto BIOS setup (default) STAC92HD83* =========== ref Reference board mic-ref Reference board with power managment for ports + auto BIOS setup (default) STAC9872 ======== -- cgit v1.2.3 From d02b1f3910f12cfe377a31afebcbbde4f5664b74 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Mar 2009 17:34:51 +0100 Subject: ALSA: hda - Update documetation for hints sysfs entry Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 99958be7b45..c5948f2f9a2 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -365,10 +365,13 @@ modelname:: to this file. init_verbs:: The extra verbs to execute at initialization. You can add a verb by - writing to this file. Pass three numbers: nid, verb and parameter. + writing to this file. Pass three numbers: nid, verb and parameter + (separated with a space). hints:: - Shows hint strings for codec parsers for any use. Right now it's - not used. + Shows / stores hint strings for codec parsers for any use. + Its format is `key = value`. For example, passing `hp_detect = yes` + to IDT/STAC codec parser will result in the disablement of the + headphone detection. init_pin_configs:: Shows the initial pin default config values set by BIOS. driver_pin_configs:: -- cgit v1.2.3 From 79d7d5333b598e9a559bf27833f0ad2b8bf6ad2c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 4 Mar 2009 09:03:50 +0100 Subject: ALSA: hda - Fix HP dv6736 mic input Fix the mic input of HP dv6736 with Conexant 5051 codec chip. This laptop seems have no mic-switching per jack connection. A new model hp-dv6736 is introduced to match with the h/w implementation. Reference: Novell bnc#480753 https://bugzilla.novell.com/show_bug.cgi?id=480753 Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a448bbefd48..80b796e4a80 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -262,6 +262,7 @@ Conexant 5051 ============= laptop Basic Laptop config (default) hp HP Spartan laptop + hp-dv6736 HP dv6736 lenovo-x200 Lenovo X200 laptop STAC9200 -- cgit v1.2.3 From edf2e2811efa9304ebe14f778d33b764cfd58b7a Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Thu, 5 Mar 2009 00:40:13 +0000 Subject: Squashfs: fix documentation typo, Cramfs filesystem limit is 256 MiB Signed-off-by: Phillip Lougher --- Documentation/filesystems/squashfs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index 3e79e4a7a39..b324c033035 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt @@ -22,7 +22,7 @@ Squashfs filesystem features versus Cramfs: Squashfs Cramfs -Max filesystem size: 2^64 16 MiB +Max filesystem size: 2^64 256 MiB Max file size: ~ 2 TiB 16 MiB Max files: unlimited unlimited Max directories: unlimited unlimited -- cgit v1.2.3 From 79c7cdd5441f5d3900c1632adcc8cd2bee35c8da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 9 Feb 2009 14:47:19 +0100 Subject: ALSA: Add kernel-doc comments to vmaster stuff Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl index 9d644f7e241..115962827c8 100644 --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl @@ -71,6 +71,10 @@ !Esound/pci/ac97/ac97_codec.c !Esound/pci/ac97/ac97_pcm.c + Virtual Master Control API +!Esound/core/vmaster.c +!Iinclude/sound/control.h + MIDI API Raw MIDI API -- cgit v1.2.3 From 662c319ae4b4fb60001816dfe1dde5fdfc7a2af9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 9 Feb 2009 08:53:50 +0100 Subject: ALSA: Add sound/core/jack.c to driver-API docbook entry Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl index 9d644f7e241..37b006cdf2f 100644 --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl @@ -88,6 +88,9 @@ Miscellaneous Functions Hardware-Dependent Devices API !Esound/core/hwdep.c + + Jack Abstraction Layer API +!Esound/core/jack.c ISA DMA Helpers !Esound/core/isadma.c -- cgit v1.2.3 From 5f8206c04857965cc2ff6c395633c4fdd977dd77 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 9 Feb 2009 08:50:43 +0100 Subject: ALSA: Fix DocBook headers Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl | 10 ++++++---- Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 8 ++++---- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl index 90f163c4bde..0230a96f056 100644 --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl @@ -1,11 +1,11 @@ - - - - + + + The ALSA Driver API @@ -35,6 +35,8 @@ + + Management of Cards and Devices Card Management !Esound/core/init.c diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 320384c1791..46b08fef374 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -1,11 +1,11 @@ - - - - + + + Writing an ALSA Driver -- cgit v1.2.3 From e776ec19a47a325ee1d9ece2d983526dcd626c53 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 28 Feb 2009 17:40:18 +0100 Subject: ALSA: Move ALSA docbooks to be with the rest of the kernel docbooks Move ALSA docbooks to be with the rest of the kernel docbooks and add them to the Makefile so that they build. Latter required a few minor changes to alsa .tmpl files. (I did not remove all of the trailing whitespace in the .tmpl files.) Fixes kernel bugzilla #12726: http://bugzilla.kernel.org/show_bug.cgi?id=12726 Signed-off-by: Randy Dunlap Cc: documentation_man-pages@kernel-bugs.osdl.org Cc: Nicola Soranzo Signed-off-by: Takashi Iwai --- Documentation/DocBook/Makefile | 3 +- Documentation/DocBook/alsa-driver-api.tmpl | 109 + Documentation/DocBook/writing-an-alsa-driver.tmpl | 6216 ++++++++++++++++++++ .../sound/alsa/DocBook/alsa-driver-api.tmpl | 109 - .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 6216 -------------------- 5 files changed, 6327 insertions(+), 6326 deletions(-) create mode 100644 Documentation/DocBook/alsa-driver-api.tmpl create mode 100644 Documentation/DocBook/writing-an-alsa-driver.tmpl delete mode 100644 Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl delete mode 100644 Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 1462ed86d40..a3a83d38f96 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -12,7 +12,8 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ - mac80211.xml debugobjects.xml sh.xml regulator.xml + mac80211.xml debugobjects.xml sh.xml regulator.xml \ + alsa-driver-api.xml writing-an-alsa-driver.xml ### # The build process is as follows (targets): diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl new file mode 100644 index 00000000000..0230a96f056 --- /dev/null +++ b/Documentation/DocBook/alsa-driver-api.tmpl @@ -0,0 +1,109 @@ + + + + + + + + + The ALSA Driver API + + + + This document is free; 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 document 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 + + + + + + + + Management of Cards and Devices + Card Management +!Esound/core/init.c + + Device Components +!Esound/core/device.c + + Module requests and Device File Entries +!Esound/core/sound.c + + Memory Management Helpers +!Esound/core/memory.c +!Esound/core/memalloc.c + + + PCM API + PCM Core +!Esound/core/pcm.c +!Esound/core/pcm_lib.c +!Esound/core/pcm_native.c + + PCM Format Helpers +!Esound/core/pcm_misc.c + + PCM Memory Management +!Esound/core/pcm_memory.c + + + Control/Mixer API + General Control Interface +!Esound/core/control.c + + AC97 Codec API +!Esound/pci/ac97/ac97_codec.c +!Esound/pci/ac97/ac97_pcm.c + + Virtual Master Control API +!Esound/core/vmaster.c +!Iinclude/sound/control.h + + + MIDI API + Raw MIDI API +!Esound/core/rawmidi.c + + MPU401-UART API +!Esound/drivers/mpu401/mpu401_uart.c + + + Proc Info API + Proc Info Interface +!Esound/core/info.c + + + Miscellaneous Functions + Hardware-Dependent Devices API +!Esound/core/hwdep.c + + Jack Abstraction Layer API +!Esound/core/jack.c + + ISA DMA Helpers +!Esound/core/isadma.c + + Other Helper Macros +!Iinclude/sound/core.h + + + + diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl new file mode 100644 index 00000000000..46b08fef374 --- /dev/null +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -0,0 +1,6216 @@ + + + + + + + + + Writing an ALSA Driver + + Takashi + Iwai + +
+ tiwai@suse.de +
+
+
+ + Oct 15, 2007 + 0.3.7 + + + + This document describes how to write an ALSA (Advanced Linux + Sound Architecture) driver. + + + + + + Copyright (c) 2002-2005 Takashi Iwai tiwai@suse.de + + + + This document is free; 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 document 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 + + + +
+ + + + + + Preface + + This document describes how to write an + + ALSA (Advanced Linux Sound Architecture) + driver. The document focuses mainly on PCI soundcards. + In the case of other device types, the API might + be different, too. However, at least the ALSA kernel API is + consistent, and therefore it would be still a bit help for + writing them. + + + + This document targets people who already have enough + C language skills and have basic linux kernel programming + knowledge. This document doesn't explain the general + topic of linux kernel coding and doesn't cover low-level + driver implementation details. It only describes + the standard way to write a PCI sound driver on ALSA. + + + + If you are already familiar with the older ALSA ver.0.5.x API, you + can check the drivers such as sound/pci/es1938.c or + sound/pci/maestro3.c which have also almost the same + code-base in the ALSA 0.5.x tree, so you can compare the differences. + + + + This document is still a draft version. Any feedback and + corrections, please!! + + + + + + + + + File Tree Structure + +
+ General + + The ALSA drivers are provided in two ways. + + + + One is the trees provided as a tarball or via cvs from the + ALSA's ftp site, and another is the 2.6 (or later) Linux kernel + tree. To synchronize both, the ALSA driver tree is split into + two different trees: alsa-kernel and alsa-driver. The former + contains purely the source code for the Linux 2.6 (or later) + tree. This tree is designed only for compilation on 2.6 or + later environment. The latter, alsa-driver, contains many subtle + files for compiling ALSA drivers outside of the Linux kernel tree, + wrapper functions for older 2.2 and 2.4 kernels, to adapt the latest kernel API, + and additional drivers which are still in development or in + tests. The drivers in alsa-driver tree will be moved to + alsa-kernel (and eventually to the 2.6 kernel tree) when they are + finished and confirmed to work fine. + + + + The file tree structure of ALSA driver is depicted below. Both + alsa-kernel and alsa-driver have almost the same file + structure, except for core directory. It's + named as acore in alsa-driver tree. + + + ALSA File Tree Structure + + sound + /core + /oss + /seq + /oss + /instr + /ioctl32 + /include + /drivers + /mpu401 + /opl3 + /i2c + /l3 + /synth + /emux + /pci + /(cards) + /isa + /(cards) + /arm + /ppc + /sparc + /usb + /pcmcia /(cards) + /oss + + + +
+ +
+ core directory + + This directory contains the middle layer which is the heart + of ALSA drivers. In this directory, the native ALSA modules are + stored. The sub-directories contain different modules and are + dependent upon the kernel config. + + +
+ core/oss + + + The codes for PCM and mixer OSS emulation modules are stored + in this directory. The rawmidi OSS emulation is included in + the ALSA rawmidi code since it's quite small. The sequencer + code is stored in core/seq/oss directory (see + + below). + +
+ +
+ core/ioctl32 + + + This directory contains the 32bit-ioctl wrappers for 64bit + architectures such like x86-64, ppc64 and sparc64. For 32bit + and alpha architectures, these are not compiled. + +
+ +
+ core/seq + + This directory and its sub-directories are for the ALSA + sequencer. This directory contains the sequencer core and + primary sequencer modules such like snd-seq-midi, + snd-seq-virmidi, etc. They are compiled only when + CONFIG_SND_SEQUENCER is set in the kernel + config. + +
+ +
+ core/seq/oss + + This contains the OSS sequencer emulation codes. + +
+ +
+ core/seq/instr + + This directory contains the modules for the sequencer + instrument layer. + +
+
+ +
+ include directory + + This is the place for the public header files of ALSA drivers, + which are to be exported to user-space, or included by + several files at different directories. Basically, the private + header files should not be placed in this directory, but you may + still find files there, due to historical reasons :) + +
+ +
+ drivers directory + + This directory contains code shared among different drivers + on different architectures. They are hence supposed not to be + architecture-specific. + For example, the dummy pcm driver and the serial MIDI + driver are found in this directory. In the sub-directories, + there is code for components which are independent from + bus and cpu architectures. + + +
+ drivers/mpu401 + + The MPU401 and MPU401-UART modules are stored here. + +
+ +
+ drivers/opl3 and opl4 + + The OPL3 and OPL4 FM-synth stuff is found here. + +
+
+ +
+ i2c directory + + This contains the ALSA i2c components. + + + + Although there is a standard i2c layer on Linux, ALSA has its + own i2c code for some cards, because the soundcard needs only a + simple operation and the standard i2c API is too complicated for + such a purpose. + + +
+ i2c/l3 + + This is a sub-directory for ARM L3 i2c. + +
+
+ +
+ synth directory + + This contains the synth middle-level modules. + + + + So far, there is only Emu8000/Emu10k1 synth driver under + the synth/emux sub-directory. + +
+ +
+ pci directory + + This directory and its sub-directories hold the top-level card modules + for PCI soundcards and the code specific to the PCI BUS. + + + + The drivers compiled from a single file are stored directly + in the pci directory, while the drivers with several source files are + stored on their own sub-directory (e.g. emu10k1, ice1712). + +
+ +
+ isa directory + + This directory and its sub-directories hold the top-level card modules + for ISA soundcards. + +
+ +
+ arm, ppc, and sparc directories + + They are used for top-level card modules which are + specific to one of these architectures. + +
+ +
+ usb directory + + This directory contains the USB-audio driver. In the latest version, the + USB MIDI driver is integrated in the usb-audio driver. + +
+ +
+ pcmcia directory + + The PCMCIA, especially PCCard drivers will go here. CardBus + drivers will be in the pci directory, because their API is identical + to that of standard PCI cards. + +
+ +
+ oss directory + + The OSS/Lite source files are stored here in Linux 2.6 (or + later) tree. In the ALSA driver tarball, this directory is empty, + of course :) + +
+
+ + + + + + + Basic Flow for PCI Drivers + +
+ Outline + + The minimum flow for PCI soundcards is as follows: + + + define the PCI ID table (see the section + PCI Entries + ). + create probe() callback. + create remove() callback. + create a pci_driver structure + containing the three pointers above. + create an init() function just calling + the pci_register_driver() to register the pci_driver table + defined above. + create an exit() function to call + the pci_unregister_driver() function. + + +
+ +
+ Full Code Example + + The code example is shown below. Some parts are kept + unimplemented at this moment but will be filled in the + next sections. The numbers in the comment lines of the + snd_mychip_probe() function + refer to details explained in the following section. + + + Basic Flow for PCI Drivers - Example + + + #include + #include + #include + #include + + /* module parameters (see "Module Parameters") */ + /* SNDRV_CARDS: maximum number of cards supported by this module */ + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; + static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; + static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + + /* definition of the chip-specific record */ + struct mychip { + struct snd_card *card; + /* the rest of the implementation will be in section + * "PCI Resource Management" + */ + }; + + /* chip-specific destructor + * (see "PCI Resource Management") + */ + static int snd_mychip_free(struct mychip *chip) + { + .... /* will be implemented later... */ + } + + /* component-destructor + * (see "Management of Cards and Components") + */ + static int snd_mychip_dev_free(struct snd_device *device) + { + return snd_mychip_free(device->device_data); + } + + /* chip-specific constructor + * (see "Management of Cards and Components") + */ + static int __devinit snd_mychip_create(struct snd_card *card, + struct pci_dev *pci, + struct mychip **rchip) + { + struct mychip *chip; + int err; + static struct snd_device_ops ops = { + .dev_free = snd_mychip_dev_free, + }; + + *rchip = NULL; + + /* check PCI availability here + * (see "PCI Resource Management") + */ + .... + + /* allocate a chip-specific data with zero filled */ + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->card = card; + + /* rest of initialization here; will be implemented + * later, see "PCI Resource Management" + */ + .... + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_mychip_free(chip); + return err; + } + + snd_card_set_dev(card, &pci->dev); + + *rchip = chip; + return 0; + } + + /* constructor -- see "Constructor" sub-section */ + static int __devinit snd_mychip_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) + { + static int dev; + struct snd_card *card; + struct mychip *chip; + int err; + + /* (1) */ + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + /* (2) */ + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + if (err < 0) + return err; + + /* (3) */ + err = snd_mychip_create(card, pci, &chip); + if (err < 0) { + snd_card_free(card); + return err; + } + + /* (4) */ + strcpy(card->driver, "My Chip"); + strcpy(card->shortname, "My Own Chip 123"); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->ioport, chip->irq); + + /* (5) */ + .... /* implemented later */ + + /* (6) */ + err = snd_card_register(card); + if (err < 0) { + snd_card_free(card); + return err; + } + + /* (7) */ + pci_set_drvdata(pci, card); + dev++; + return 0; + } + + /* destructor -- see the "Destructor" sub-section */ + static void __devexit snd_mychip_remove(struct pci_dev *pci) + { + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); + } +]]> + + + +
+ +
+ Constructor + + The real constructor of PCI drivers is the probe callback. + The probe callback and other component-constructors which are called + from the probe callback should be defined with + the __devinit prefix. You + cannot use the __init prefix for them, + because any PCI device could be a hotplug device. + + + + In the probe callback, the following scheme is often used. + + +
+ 1) Check and increment the device index. + + + += SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } +]]> + + + + where enable[dev] is the module option. + + + + Each time the probe callback is called, check the + availability of the device. If not available, simply increment + the device index and returns. dev will be incremented also + later (step + 7). + +
+ +
+ 2) Create a card instance + + + + + + + + + + The details will be explained in the section + + Management of Cards and Components. + +
+ +
+ 3) Create a main component + + In this part, the PCI resources are allocated. + + + + + + + + The details will be explained in the section PCI Resource + Management. + +
+ +
+ 4) Set the driver ID and name strings. + + + +driver, "My Chip"); + strcpy(card->shortname, "My Own Chip 123"); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->ioport, chip->irq); +]]> + + + + The driver field holds the minimal ID string of the + chip. This is used by alsa-lib's configurator, so keep it + simple but unique. + Even the same driver can have different driver IDs to + distinguish the functionality of each chip type. + + + + The shortname field is a string shown as more verbose + name. The longname field contains the information + shown in /proc/asound/cards. + +
+ +
+ 5) Create other components, such as mixer, MIDI, etc. + + Here you define the basic components such as + PCM, + mixer (e.g. AC97), + MIDI (e.g. MPU-401), + and other interfaces. + Also, if you want a proc + file, define it here, too. + +
+ +
+ 6) Register the card instance. + + + + + + + + + + Will be explained in the section Management + of Cards and Components, too. + +
+ +
+ 7) Set the PCI driver data and return zero. + + + + + + + + In the above, the card record is stored. This pointer is + used in the remove callback and power-management + callbacks, too. + +
+
+ +
+ Destructor + + The destructor, remove callback, simply releases the card + instance. Then the ALSA middle layer will release all the + attached components automatically. + + + + It would be typically like the following: + + + + + + + + The above code assumes that the card pointer is set to the PCI + driver data. + +
+ +
+ Header Files + + For the above example, at least the following include files + are necessary. + + + + + #include + #include + #include + #include +]]> + + + + where the last one is necessary only when module options are + defined in the source file. If the code is split into several + files, the files without module options don't need them. + + + + In addition to these headers, you'll need + <linux/interrupt.h> for interrupt + handling, and <asm/io.h> for I/O + access. If you use the mdelay() or + udelay() functions, you'll need to include + <linux/delay.h> too. + + + + The ALSA interfaces like the PCM and control APIs are defined in other + <sound/xxx.h> header files. + They have to be included after + <sound/core.h>. + + +
+
+ + + + + + + Management of Cards and Components + +
+ Card Instance + + For each soundcard, a card record must be allocated. + + + + A card record is the headquarters of the soundcard. It manages + the whole list of devices (components) on the soundcard, such as + PCM, mixers, MIDI, synthesizer, and so on. Also, the card + record holds the ID and the name strings of the card, manages + the root of proc files, and controls the power-management states + and hotplug disconnections. The component list on the card + record is used to manage the correct release of resources at + destruction. + + + + As mentioned above, to create a card instance, call + snd_card_create(). + + + + + + + + + + The function takes five arguments, the card-index number, the + id string, the module pointer (usually + THIS_MODULE), + the size of extra-data space, and the pointer to return the + card instance. The extra_size argument is used to + allocate card->private_data for the + chip-specific data. Note that these data + are allocated by snd_card_create(). + +
+ +
+ Components + + After the card is created, you can attach the components + (devices) to the card instance. In an ALSA driver, a component is + represented as a struct snd_device object. + A component can be a PCM instance, a control interface, a raw + MIDI interface, etc. Each such instance has one component + entry. + + + + A component can be created via + snd_device_new() function. + + + + + + + + + + This takes the card pointer, the device-level + (SNDRV_DEV_XXX), the data pointer, and the + callback pointers (&ops). The + device-level defines the type of components and the order of + registration and de-registration. For most components, the + device-level is already defined. For a user-defined component, + you can use SNDRV_DEV_LOWLEVEL. + + + + This function itself doesn't allocate the data space. The data + must be allocated manually beforehand, and its pointer is passed + as the argument. This pointer is used as the + (chip identifier in the above example) + for the instance. + + + + Each pre-defined ALSA component such as ac97 and pcm calls + snd_device_new() inside its + constructor. The destructor for each component is defined in the + callback pointers. Hence, you don't need to take care of + calling a destructor for such a component. + + + + If you wish to create your own component, you need to + set the destructor function to the dev_free callback in + the ops, so that it can be released + automatically via snd_card_free(). + The next example will show an implementation of chip-specific + data. + +
+ +
+ Chip-Specific Data + + Chip-specific information, e.g. the I/O port address, its + resource pointer, or the irq number, is stored in the + chip-specific record. + + + + + + + + + + In general, there are two ways of allocating the chip record. + + +
+ 1. Allocating via <function>snd_card_create()</function>. + + As mentioned above, you can pass the extra-data-length + to the 4th argument of snd_card_create(), i.e. + + + + + + + + struct mychip is the type of the chip record. + + + + In return, the allocated record can be accessed as + + + +private_data; +]]> + + + + With this method, you don't have to allocate twice. + The record is released together with the card instance. + +
+ +
+ 2. Allocating an extra device. + + + After allocating a card instance via + snd_card_create() (with + 0 on the 4th arg), call + kzalloc(). + + + + + + + + + + The chip record should have the field to hold the card + pointer at least, + + + + + + + + + + Then, set the card pointer in the returned chip instance. + + + +card = card; +]]> + + + + + + Next, initialize the fields, and register this chip + record as a low-level device with a specified + ops, + + + + + + + + snd_mychip_dev_free() is the + device-destructor function, which will call the real + destructor. + + + + + +device_data); + } +]]> + + + + where snd_mychip_free() is the real destructor. + +
+
+ +
+ Registration and Release + + After all components are assigned, register the card instance + by calling snd_card_register(). Access + to the device files is enabled at this point. That is, before + snd_card_register() is called, the + components are safely inaccessible from external side. If this + call fails, exit the probe function after releasing the card via + snd_card_free(). + + + + For releasing the card instance, you can call simply + snd_card_free(). As mentioned earlier, all + components are released automatically by this call. + + + + As further notes, the destructors (both + snd_mychip_dev_free and + snd_mychip_free) cannot be defined with + the __devexit prefix, because they may be + called from the constructor, too, at the false path. + + + + For a device which allows hotplugging, you can use + snd_card_free_when_closed. This one will + postpone the destruction until all devices are closed. + + +
+ +
+ + + + + + + PCI Resource Management + +
+ Full Code Example + + In this section, we'll complete the chip-specific constructor, + destructor and PCI entries. Example code is shown first, + below. + + + PCI Resource Management Example + +irq >= 0) + free_irq(chip->irq, chip); + /* release the I/O ports & memory */ + pci_release_regions(chip->pci); + /* disable the PCI entry */ + pci_disable_device(chip->pci); + /* release the data */ + kfree(chip); + return 0; + } + + /* chip-specific constructor */ + static int __devinit snd_mychip_create(struct snd_card *card, + struct pci_dev *pci, + struct mychip **rchip) + { + struct mychip *chip; + int err; + static struct snd_device_ops ops = { + .dev_free = snd_mychip_dev_free, + }; + + *rchip = NULL; + + /* initialize the PCI entry */ + err = pci_enable_device(pci); + if (err < 0) + return err; + /* check PCI availability (28bit DMA) */ + if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { + printk(KERN_ERR "error to set 28bit mask DMA\n"); + pci_disable_device(pci); + return -ENXIO; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + pci_disable_device(pci); + return -ENOMEM; + } + + /* initialize the stuff */ + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + /* (1) PCI resource allocation */ + err = pci_request_regions(pci, "My Chip"); + if (err < 0) { + kfree(chip); + pci_disable_device(pci); + return err; + } + chip->port = pci_resource_start(pci, 0); + if (request_irq(pci->irq, snd_mychip_interrupt, + IRQF_SHARED, "My Chip", chip)) { + printk(KERN_ERR "cannot grab irq %d\n", pci->irq); + snd_mychip_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + + /* (2) initialization of the chip hardware */ + .... /* (not implemented in this document) */ + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_mychip_free(chip); + return err; + } + + snd_card_set_dev(card, &pci->dev); + + *rchip = chip; + return 0; + } + + /* PCI IDs */ + static struct pci_device_id snd_mychip_ids[] = { + { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, + .... + { 0, } + }; + MODULE_DEVICE_TABLE(pci, snd_mychip_ids); + + /* pci_driver definition */ + static struct pci_driver driver = { + .name = "My Own Chip", + .id_table = snd_mychip_ids, + .probe = snd_mychip_probe, + .remove = __devexit_p(snd_mychip_remove), + }; + + /* module initialization */ + static int __init alsa_card_mychip_init(void) + { + return pci_register_driver(&driver); + } + + /* module clean up */ + static void __exit alsa_card_mychip_exit(void) + { + pci_unregister_driver(&driver); + } + + module_init(alsa_card_mychip_init) + module_exit(alsa_card_mychip_exit) + + EXPORT_NO_SYMBOLS; /* for old kernels only */ +]]> + + + +
+ +
+ Some Hafta's + + The allocation of PCI resources is done in the + probe() function, and usually an extra + xxx_create() function is written for this + purpose. + + + + In the case of PCI devices, you first have to call + the pci_enable_device() function before + allocating resources. Also, you need to set the proper PCI DMA + mask to limit the accessed I/O range. In some cases, you might + need to call pci_set_master() function, + too. + + + + Suppose the 28bit mask, and the code to be added would be like: + + + + + + + +
+ +
+ Resource Allocation + + The allocation of I/O ports and irqs is done via standard kernel + functions. Unlike ALSA ver.0.5.x., there are no helpers for + that. And these resources must be released in the destructor + function (see below). Also, on ALSA 0.9.x, you don't need to + allocate (pseudo-)DMA for PCI like in ALSA 0.5.x. + + + + Now assume that the PCI device has an I/O port with 8 bytes + and an interrupt. Then struct mychip will have the + following fields: + + + + + + + + + + For an I/O port (and also a memory region), you need to have + the resource pointer for the standard resource management. For + an irq, you have to keep only the irq number (integer). But you + need to initialize this number as -1 before actual allocation, + since irq 0 is valid. The port address and its resource pointer + can be initialized as null by + kzalloc() automatically, so you + don't have to take care of resetting them. + + + + The allocation of an I/O port is done like this: + + + +port = pci_resource_start(pci, 0); +]]> + + + + + + + It will reserve the I/O port region of 8 bytes of the given + PCI device. The returned value, chip->res_port, is allocated + via kmalloc() by + request_region(). The pointer must be + released via kfree(), but there is a + problem with this. This issue will be explained later. + + + + The allocation of an interrupt source is done like this: + + + +irq, snd_mychip_interrupt, + IRQF_SHARED, "My Chip", chip)) { + printk(KERN_ERR "cannot grab irq %d\n", pci->irq); + snd_mychip_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; +]]> + + + + where snd_mychip_interrupt() is the + interrupt handler defined later. + Note that chip->irq should be defined + only when request_irq() succeeded. + + + + On the PCI bus, interrupts can be shared. Thus, + IRQF_SHARED is used as the interrupt flag of + request_irq(). + + + + The last argument of request_irq() is the + data pointer passed to the interrupt handler. Usually, the + chip-specific record is used for that, but you can use what you + like, too. + + + + I won't give details about the interrupt handler at this + point, but at least its appearance can be explained now. The + interrupt handler looks usually like the following: + + + + + + + + + + Now let's write the corresponding destructor for the resources + above. The role of destructor is simple: disable the hardware + (if already activated) and release the resources. So far, we + have no hardware part, so the disabling code is not written here. + + + + To release the resources, the check-and-release + method is a safer way. For the interrupt, do like this: + + + +irq >= 0) + free_irq(chip->irq, chip); +]]> + + + + Since the irq number can start from 0, you should initialize + chip->irq with a negative value (e.g. -1), so that you can + check the validity of the irq number as above. + + + + When you requested I/O ports or memory regions via + pci_request_region() or + pci_request_regions() like in this example, + release the resource(s) using the corresponding function, + pci_release_region() or + pci_release_regions(). + + + +pci); +]]> + + + + + + When you requested manually via request_region() + or request_mem_region, you can release it via + release_resource(). Suppose that you keep + the resource pointer returned from request_region() + in chip->res_port, the release procedure looks like: + + + +res_port); +]]> + + + + + + Don't forget to call pci_disable_device() + before the end. + + + + And finally, release the chip-specific record. + + + + + + + + + + Again, remember that you cannot + use the __devexit prefix for this destructor. + + + + We didn't implement the hardware disabling part in the above. + If you need to do this, please note that the destructor may be + called even before the initialization of the chip is completed. + It would be better to have a flag to skip hardware disabling + if the hardware was not initialized yet. + + + + When the chip-data is assigned to the card using + snd_device_new() with + SNDRV_DEV_LOWLELVEL , its destructor is + called at the last. That is, it is assured that all other + components like PCMs and controls have already been released. + You don't have to stop PCMs, etc. explicitly, but just + call low-level hardware stopping. + + + + The management of a memory-mapped region is almost as same as + the management of an I/O port. You'll need three fields like + the following: + + + + + + + + and the allocation would be like below: + + + +iobase_phys = pci_resource_start(pci, 0); + chip->iobase_virt = ioremap_nocache(chip->iobase_phys, + pci_resource_len(pci, 0)); +]]> + + + + and the corresponding destructor would be: + + + +iobase_virt) + iounmap(chip->iobase_virt); + .... + pci_release_regions(chip->pci); + .... + } +]]> + + + + +
+ +
+ Registration of Device Struct + + At some point, typically after calling snd_device_new(), + you need to register the struct device of the chip + you're handling for udev and co. ALSA provides a macro for compatibility with + older kernels. Simply call like the following: + + +dev); +]]> + + + so that it stores the PCI's device pointer to the card. This will be + referred by ALSA core functions later when the devices are registered. + + + In the case of non-PCI, pass the proper device struct pointer of the BUS + instead. (In the case of legacy ISA without PnP, you don't have to do + anything.) + +
+ +
+ PCI Entries + + So far, so good. Let's finish the missing PCI + stuff. At first, we need a + pci_device_id table for this + chipset. It's a table of PCI vendor/device ID number, and some + masks. + + + + For example, + + + + + + + + + + The first and second fields of + the pci_device_id structure are the vendor and + device IDs. If you have no reason to filter the matching + devices, you can leave the remaining fields as above. The last + field of the pci_device_id struct contains + private data for this entry. You can specify any value here, for + example, to define specific operations for supported device IDs. + Such an example is found in the intel8x0 driver. + + + + The last entry of this list is the terminator. You must + specify this all-zero entry. + + + + Then, prepare the pci_driver record: + + + + + + + + + + The probe and + remove functions have already + been defined in the previous sections. + The remove function should + be defined with the + __devexit_p() macro, so that it's not + defined for built-in (and non-hot-pluggable) case. The + name + field is the name string of this device. Note that you must not + use a slash / in this string. + + + + And at last, the module entries: + + + + + + + + + + Note that these module entries are tagged with + __init and + __exit prefixes, not + __devinit nor + __devexit. + + + + Oh, one thing was forgotten. If you have no exported symbols, + you need to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels). + + + + + + + + That's all! + +
+
+ + + + + + + PCM Interface + +
+ General + + The PCM middle layer of ALSA is quite powerful and it is only + necessary for each driver to implement the low-level functions + to access its hardware. + + + + For accessing to the PCM layer, you need to include + <sound/pcm.h> first. In addition, + <sound/pcm_params.h> might be needed + if you access to some functions related with hw_param. + + + + Each card device can have up to four pcm instances. A pcm + instance corresponds to a pcm device file. The limitation of + number of instances comes only from the available bit size of + the Linux's device numbers. Once when 64bit device number is + used, we'll have more pcm instances available. + + + + A pcm instance consists of pcm playback and capture streams, + and each pcm stream consists of one or more pcm substreams. Some + soundcards support multiple playback functions. For example, + emu10k1 has a PCM playback of 32 stereo substreams. In this case, at + each open, a free substream is (usually) automatically chosen + and opened. Meanwhile, when only one substream exists and it was + already opened, the successful open will either block + or error with EAGAIN according to the + file open mode. But you don't have to care about such details in your + driver. The PCM middle layer will take care of such work. + +
+ +
+ Full Code Example + + The example code below does not include any hardware access + routines but shows only the skeleton, how to build up the PCM + interfaces. + + + PCM Example Code + + + .... + + /* hardware definition */ + static struct snd_pcm_hardware snd_mychip_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 32768, + .period_bytes_min = 4096, + .period_bytes_max = 32768, + .periods_min = 1, + .periods_max = 1024, + }; + + /* hardware definition */ + static struct snd_pcm_hardware snd_mychip_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 32768, + .period_bytes_min = 4096, + .period_bytes_max = 32768, + .periods_min = 1, + .periods_max = 1024, + }; + + /* open callback */ + static int snd_mychip_playback_open(struct snd_pcm_substream *substream) + { + struct mychip *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw = snd_mychip_playback_hw; + /* more hardware-initialization will be done here */ + .... + return 0; + } + + /* close callback */ + static int snd_mychip_playback_close(struct snd_pcm_substream *substream) + { + struct mychip *chip = snd_pcm_substream_chip(substream); + /* the hardware-specific codes will be here */ + .... + return 0; + + } + + /* open callback */ + static int snd_mychip_capture_open(struct snd_pcm_substream *substream) + { + struct mychip *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw = snd_mychip_capture_hw; + /* more hardware-initialization will be done here */ + .... + return 0; + } + + /* close callback */ + static int snd_mychip_capture_close(struct snd_pcm_substream *substream) + { + struct mychip *chip = snd_pcm_substream_chip(substream); + /* the hardware-specific codes will be here */ + .... + return 0; + + } + + /* hw_params callback */ + static int snd_mychip_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) + { + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + } + + /* hw_free callback */ + static int snd_mychip_pcm_hw_free(struct snd_pcm_substream *substream) + { + return snd_pcm_lib_free_pages(substream); + } + + /* prepare callback */ + static int snd_mychip_pcm_prepare(struct snd_pcm_substream *substream) + { + struct mychip *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + /* set up the hardware with the current configuration + * for example... + */ + mychip_set_sample_format(chip, runtime->format); + mychip_set_sample_rate(chip, runtime->rate); + mychip_set_channels(chip, runtime->channels); + mychip_set_dma_setup(chip, runtime->dma_addr, + chip->buffer_size, + chip->period_size); + return 0; + } + + /* trigger callback */ + static int snd_mychip_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) + { + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* do something to start the PCM engine */ + .... + break; + case SNDRV_PCM_TRIGGER_STOP: + /* do something to stop the PCM engine */ + .... + break; + default: + return -EINVAL; + } + } + + /* pointer callback */ + static snd_pcm_uframes_t + snd_mychip_pcm_pointer(struct snd_pcm_substream *substream) + { + struct mychip *chip = snd_pcm_substream_chip(substream); + unsigned int current_ptr; + + /* get the current hardware pointer */ + current_ptr = mychip_get_hw_pointer(chip); + return current_ptr; + } + + /* operators */ + static struct snd_pcm_ops snd_mychip_playback_ops = { + .open = snd_mychip_playback_open, + .close = snd_mychip_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_mychip_pcm_hw_params, + .hw_free = snd_mychip_pcm_hw_free, + .prepare = snd_mychip_pcm_prepare, + .trigger = snd_mychip_pcm_trigger, + .pointer = snd_mychip_pcm_pointer, + }; + + /* operators */ + static struct snd_pcm_ops snd_mychip_capture_ops = { + .open = snd_mychip_capture_open, + .close = snd_mychip_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_mychip_pcm_hw_params, + .hw_free = snd_mychip_pcm_hw_free, + .prepare = snd_mychip_pcm_prepare, + .trigger = snd_mychip_pcm_trigger, + .pointer = snd_mychip_pcm_pointer, + }; + + /* + * definitions of capture are omitted here... + */ + + /* create a pcm device */ + static int __devinit snd_mychip_new_pcm(struct mychip *chip) + { + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, &pcm); + if (err < 0) + return err; + pcm->private_data = chip; + strcpy(pcm->name, "My Chip"); + chip->pcm = pcm; + /* set operators */ + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_mychip_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_mychip_capture_ops); + /* pre-allocation of buffers */ + /* NOTE: this may fail */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + 64*1024, 64*1024); + return 0; + } +]]> + + + +
+ +
+ Constructor + + A pcm instance is allocated by the snd_pcm_new() + function. It would be better to create a constructor for pcm, + namely, + + + +card, "My Chip", 0, 1, 1, &pcm); + if (err < 0) + return err; + pcm->private_data = chip; + strcpy(pcm->name, "My Chip"); + chip->pcm = pcm; + .... + return 0; + } +]]> + + + + + + The snd_pcm_new() function takes four + arguments. The first argument is the card pointer to which this + pcm is assigned, and the second is the ID string. + + + + The third argument (index, 0 in the + above) is the index of this new pcm. It begins from zero. If + you create more than one pcm instances, specify the + different numbers in this argument. For example, + index = 1 for the second PCM device. + + + + The fourth and fifth arguments are the number of substreams + for playback and capture, respectively. Here 1 is used for + both arguments. When no playback or capture substreams are available, + pass 0 to the corresponding argument. + + + + If a chip supports multiple playbacks or captures, you can + specify more numbers, but they must be handled properly in + open/close, etc. callbacks. When you need to know which + substream you are referring to, then it can be obtained from + struct snd_pcm_substream data passed to each callback + as follows: + + + +number; +]]> + + + + + + After the pcm is created, you need to set operators for each + pcm stream. + + + + + + + + + + The operators are defined typically like this: + + + + + + + + All the callbacks are described in the + + Operators subsection. + + + + After setting the operators, you probably will want to + pre-allocate the buffer. For the pre-allocation, simply call + the following: + + + +pci), + 64*1024, 64*1024); +]]> + + + + It will allocate a buffer up to 64kB as default. + Buffer management details will be described in the later section Buffer and Memory + Management. + + + + Additionally, you can set some extra information for this pcm + in pcm->info_flags. + The available values are defined as + SNDRV_PCM_INFO_XXX in + <sound/asound.h>, which is used for + the hardware definition (described later). When your soundchip + supports only half-duplex, specify like this: + + + +info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; +]]> + + + +
+ +
+ ... And the Destructor? + + The destructor for a pcm instance is not always + necessary. Since the pcm device will be released by the middle + layer code automatically, you don't have to call the destructor + explicitly. + + + + The destructor would be necessary if you created + special records internally and needed to release them. In such a + case, set the destructor function to + pcm->private_free: + + + PCM Instance with a Destructor + +my_private_pcm_data); + /* do what you like else */ + .... + } + + static int __devinit snd_mychip_new_pcm(struct mychip *chip) + { + struct snd_pcm *pcm; + .... + /* allocate your own data */ + chip->my_private_pcm_data = kmalloc(...); + /* set the destructor */ + pcm->private_data = chip; + pcm->private_free = mychip_pcm_free; + .... + } +]]> + + + +
+ +
+ Runtime Pointer - The Chest of PCM Information + + When the PCM substream is opened, a PCM runtime instance is + allocated and assigned to the substream. This pointer is + accessible via substream->runtime. + This runtime pointer holds most information you need + to control the PCM: the copy of hw_params and sw_params configurations, the buffer + pointers, mmap records, spinlocks, etc. + + + + The definition of runtime instance is found in + <sound/pcm.h>. Here are + the contents of this file: + + + + + + + + + For the operators (callbacks) of each sound driver, most of + these records are supposed to be read-only. Only the PCM + middle-layer changes / updates them. The exceptions are + the hardware description (hw), interrupt callbacks + (transfer_ack_xxx), DMA buffer information, and the private + data. Besides, if you use the standard buffer allocation + method via snd_pcm_lib_malloc_pages(), + you don't need to set the DMA buffer information by yourself. + + + + In the sections below, important records are explained. + + +
+ Hardware Description + + The hardware descriptor (struct snd_pcm_hardware) + contains the definitions of the fundamental hardware + configuration. Above all, you'll need to define this in + + the open callback. + Note that the runtime instance holds the copy of the + descriptor, not the pointer to the existing descriptor. That + is, in the open callback, you can modify the copied descriptor + (runtime->hw) as you need. For example, if the maximum + number of channels is 1 only on some chip models, you can + still use the same hardware descriptor and change the + channels_max later: + + +runtime; + ... + runtime->hw = snd_mychip_playback_hw; /* common definition */ + if (chip->model == VERY_OLD_ONE) + runtime->hw.channels_max = 1; +]]> + + + + + + Typically, you'll have a hardware descriptor as below: + + + + + + + + + + + The info field contains the type and + capabilities of this pcm. The bit flags are defined in + <sound/asound.h> as + SNDRV_PCM_INFO_XXX. Here, at least, you + have to specify whether the mmap is supported and which + interleaved format is supported. + When the is supported, add the + SNDRV_PCM_INFO_MMAP flag here. When the + hardware supports the interleaved or the non-interleaved + formats, SNDRV_PCM_INFO_INTERLEAVED or + SNDRV_PCM_INFO_NONINTERLEAVED flag must + be set, respectively. If both are supported, you can set both, + too. + + + + In the above example, MMAP_VALID and + BLOCK_TRANSFER are specified for the OSS mmap + mode. Usually both are set. Of course, + MMAP_VALID is set only if the mmap is + really supported. + + + + The other possible flags are + SNDRV_PCM_INFO_PAUSE and + SNDRV_PCM_INFO_RESUME. The + PAUSE bit means that the pcm supports the + pause operation, while the + RESUME bit means that the pcm supports + the full suspend/resume operation. + If the PAUSE flag is set, + the trigger callback below + must handle the corresponding (pause push/release) commands. + The suspend/resume trigger commands can be defined even without + the RESUME flag. See + Power Management section for details. + + + + When the PCM substreams can be synchronized (typically, + synchronized start/stop of a playback and a capture streams), + you can give SNDRV_PCM_INFO_SYNC_START, + too. In this case, you'll need to check the linked-list of + PCM substreams in the trigger callback. This will be + described in the later section. + + + + + + formats field contains the bit-flags + of supported formats (SNDRV_PCM_FMTBIT_XXX). + If the hardware supports more than one format, give all or'ed + bits. In the example above, the signed 16bit little-endian + format is specified. + + + + + + rates field contains the bit-flags of + supported rates (SNDRV_PCM_RATE_XXX). + When the chip supports continuous rates, pass + CONTINUOUS bit additionally. + The pre-defined rate bits are provided only for typical + rates. If your chip supports unconventional rates, you need to add + the KNOT bit and set up the hardware + constraint manually (explained later). + + + + + + rate_min and + rate_max define the minimum and + maximum sample rate. This should correspond somehow to + rates bits. + + + + + + channel_min and + channel_max + define, as you might already expected, the minimum and maximum + number of channels. + + + + + + buffer_bytes_max defines the + maximum buffer size in bytes. There is no + buffer_bytes_min field, since + it can be calculated from the minimum period size and the + minimum number of periods. + Meanwhile, period_bytes_min and + define the minimum and maximum size of the period in bytes. + periods_max and + periods_min define the maximum and + minimum number of periods in the buffer. + + + + The period is a term that corresponds to + a fragment in the OSS world. The period defines the size at + which a PCM interrupt is generated. This size strongly + depends on the hardware. + Generally, the smaller period size will give you more + interrupts, that is, more controls. + In the case of capture, this size defines the input latency. + On the other hand, the whole buffer size defines the + output latency for the playback direction. + + + + + + There is also a field fifo_size. + This specifies the size of the hardware FIFO, but currently it + is neither used in the driver nor in the alsa-lib. So, you + can ignore this field. + + + + +
+ +
+ PCM Configurations + + Ok, let's go back again to the PCM runtime records. + The most frequently referred records in the runtime instance are + the PCM configurations. + The PCM configurations are stored in the runtime instance + after the application sends hw_params data via + alsa-lib. There are many fields copied from hw_params and + sw_params structs. For example, + format holds the format type + chosen by the application. This field contains the enum value + SNDRV_PCM_FORMAT_XXX. + + + + One thing to be noted is that the configured buffer and period + sizes are stored in frames in the runtime. + In the ALSA world, 1 frame = channels * samples-size. + For conversion between frames and bytes, you can use the + frames_to_bytes() and + bytes_to_frames() helper functions. + + +period_size); +]]> + + + + + + Also, many software parameters (sw_params) are + stored in frames, too. Please check the type of the field. + snd_pcm_uframes_t is for the frames as unsigned + integer while snd_pcm_sframes_t is for the frames + as signed integer. + +
+ +
+ DMA Buffer Information + + The DMA buffer is defined by the following four fields, + dma_area, + dma_addr, + dma_bytes and + dma_private. + The dma_area holds the buffer + pointer (the logical address). You can call + memcpy from/to + this pointer. Meanwhile, dma_addr + holds the physical address of the buffer. This field is + specified only when the buffer is a linear buffer. + dma_bytes holds the size of buffer + in bytes. dma_private is used for + the ALSA DMA allocator. + + + + If you use a standard ALSA function, + snd_pcm_lib_malloc_pages(), for + allocating the buffer, these fields are set by the ALSA middle + layer, and you should not change them by + yourself. You can read them but not write them. + On the other hand, if you want to allocate the buffer by + yourself, you'll need to manage it in hw_params callback. + At least, dma_bytes is mandatory. + dma_area is necessary when the + buffer is mmapped. If your driver doesn't support mmap, this + field is not necessary. dma_addr + is also optional. You can use + dma_private as you like, too. + +
+ +
+ Running Status + + The running status can be referred via runtime->status. + This is the pointer to the struct snd_pcm_mmap_status + record. For example, you can get the current DMA hardware + pointer via runtime->status->hw_ptr. + + + + The DMA application pointer can be referred via + runtime->control, which points to the + struct snd_pcm_mmap_control record. + However, accessing directly to this value is not recommended. + +
+ +
+ Private Data + + You can allocate a record for the substream and store it in + runtime->private_data. Usually, this + is done in + + the open callback. + Don't mix this with pcm->private_data. + The pcm->private_data usually points to the + chip instance assigned statically at the creation of PCM, while the + runtime->private_data points to a dynamic + data structure created at the PCM open callback. + + + +runtime->private_data = data; + .... + } +]]> + + + + + + The allocated object must be released in + + the close callback. + +
+ +
+ Interrupt Callbacks + + The field transfer_ack_begin and + transfer_ack_end are called at + the beginning and at the end of + snd_pcm_period_elapsed(), respectively. + +
+ +
+ +
+ Operators + + OK, now let me give details about each pcm callback + (ops). In general, every callback must + return 0 if successful, or a negative error number + such as -EINVAL. To choose an appropriate + error number, it is advised to check what value other parts of + the kernel return when the same kind of request fails. + + + + The callback function takes at least the argument with + snd_pcm_substream pointer. To retrieve + the chip record from the given substream instance, you can use the + following macro. + + + + + + + + The macro reads substream->private_data, + which is a copy of pcm->private_data. + You can override the former if you need to assign different data + records per PCM substream. For example, the cmi8330 driver assigns + different private_data for playback and capture directions, + because it uses two different codecs (SB- and AD-compatible) for + different directions. + + +
+ open callback + + + + + + + + This is called when a pcm substream is opened. + + + + At least, here you have to initialize the runtime->hw + record. Typically, this is done by like this: + + + +runtime; + + runtime->hw = snd_mychip_playback_hw; + return 0; + } +]]> + + + + where snd_mychip_playback_hw is the + pre-defined hardware description. + + + + You can allocate a private data in this callback, as described + in + Private Data section. + + + + If the hardware configuration needs more constraints, set the + hardware constraints here, too. + See + Constraints for more details. + +
+ +
+ close callback + + + + + + + + Obviously, this is called when a pcm substream is closed. + + + + Any private instance for a pcm substream allocated in the + open callback will be released here. + + + +runtime->private_data); + .... + } +]]> + + + +
+ +
+ ioctl callback + + This is used for any special call to pcm ioctls. But + usually you can pass a generic ioctl callback, + snd_pcm_lib_ioctl. + +
+ +
+ hw_params callback + + + + + + + + + + This is called when the hardware parameter + (hw_params) is set + up by the application, + that is, once when the buffer size, the period size, the + format, etc. are defined for the pcm substream. + + + + Many hardware setups should be done in this callback, + including the allocation of buffers. + + + + Parameters to be initialized are retrieved by + params_xxx() macros. To allocate + buffer, you can call a helper function, + + + + + + + + snd_pcm_lib_malloc_pages() is available + only when the DMA buffers have been pre-allocated. + See the section + Buffer Types for more details. + + + + Note that this and prepare callbacks + may be called multiple times per initialization. + For example, the OSS emulation may + call these callbacks at each change via its ioctl. + + + + Thus, you need to be careful not to allocate the same buffers + many times, which will lead to memory leaks! Calling the + helper function above many times is OK. It will release the + previous buffer automatically when it was already allocated. + + + + Another note is that this callback is non-atomic + (schedulable). This is important, because the + trigger callback + is atomic (non-schedulable). That is, mutexes or any + schedule-related functions are not available in + trigger callback. + Please see the subsection + + Atomicity for details. + +
+ +
+ hw_free callback + + + + + + + + + + This is called to release the resources allocated via + hw_params. For example, releasing the + buffer via + snd_pcm_lib_malloc_pages() is done by + calling the following: + + + + + + + + + + This function is always called before the close callback is called. + Also, the callback may be called multiple times, too. + Keep track whether the resource was already released. + +
+ +
+ prepare callback + + + + + + + + + + This callback is called when the pcm is + prepared. You can set the format type, sample + rate, etc. here. The difference from + hw_params is that the + prepare callback will be called each + time + snd_pcm_prepare() is called, i.e. when + recovering after underruns, etc. + + + + Note that this callback is now non-atomic. + You can use schedule-related functions safely in this callback. + + + + In this and the following callbacks, you can refer to the + values via the runtime record, + substream->runtime. + For example, to get the current + rate, format or channels, access to + runtime->rate, + runtime->format or + runtime->channels, respectively. + The physical address of the allocated buffer is set to + runtime->dma_area. The buffer and period sizes are + in runtime->buffer_size and runtime->period_size, + respectively. + + + + Be careful that this callback will be called many times at + each setup, too. + +
+ +
+ trigger callback + + + + + + + + This is called when the pcm is started, stopped or paused. + + + + Which action is specified in the second argument, + SNDRV_PCM_TRIGGER_XXX in + <sound/pcm.h>. At least, + the START and STOP + commands must be defined in this callback. + + + + + + + + + + When the pcm supports the pause operation (given in the info + field of the hardware table), the PAUSE_PUSE + and PAUSE_RELEASE commands must be + handled here, too. The former is the command to pause the pcm, + and the latter to restart the pcm again. + + + + When the pcm supports the suspend/resume operation, + regardless of full or partial suspend/resume support, + the SUSPEND and RESUME + commands must be handled, too. + These commands are issued when the power-management status is + changed. Obviously, the SUSPEND and + RESUME commands + suspend and resume the pcm substream, and usually, they + are identical to the STOP and + START commands, respectively. + See the + Power Management section for details. + + + + As mentioned, this callback is atomic. You cannot call + functions which may sleep. + The trigger callback should be as minimal as possible, + just really triggering the DMA. The other stuff should be + initialized hw_params and prepare callbacks properly + beforehand. + +
+ +
+ pointer callback + + + + + + + + This callback is called when the PCM middle layer inquires + the current hardware position on the buffer. The position must + be returned in frames, + ranging from 0 to buffer_size - 1. + + + + This is called usually from the buffer-update routine in the + pcm middle layer, which is invoked when + snd_pcm_period_elapsed() is called in the + interrupt routine. Then the pcm middle layer updates the + position and calculates the available space, and wakes up the + sleeping poll threads, etc. + + + + This callback is also atomic. + +
+ +
+ copy and silence callbacks + + These callbacks are not mandatory, and can be omitted in + most cases. These callbacks are used when the hardware buffer + cannot be in the normal memory space. Some chips have their + own buffer on the hardware which is not mappable. In such a + case, you have to transfer the data manually from the memory + buffer to the hardware buffer. Or, if the buffer is + non-contiguous on both physical and virtual memory spaces, + these callbacks must be defined, too. + + + + If these two callbacks are defined, copy and set-silence + operations are done by them. The detailed will be described in + the later section Buffer and Memory + Management. + +
+ +
+ ack callback + + This callback is also not mandatory. This callback is called + when the appl_ptr is updated in read or write operations. + Some drivers like emu10k1-fx and cs46xx need to track the + current appl_ptr for the internal buffer, and this callback + is useful only for such a purpose. + + + This callback is atomic. + +
+ +
+ page callback + + + This callback is optional too. This callback is used + mainly for non-contiguous buffers. The mmap calls this + callback to get the page address. Some examples will be + explained in the later section Buffer and Memory + Management, too. + +
+
+ +
+ Interrupt Handler + + The rest of pcm stuff is the PCM interrupt handler. The + role of PCM interrupt handler in the sound driver is to update + the buffer position and to tell the PCM middle layer when the + buffer position goes across the prescribed period size. To + inform this, call the snd_pcm_period_elapsed() + function. + + + + There are several types of sound chips to generate the interrupts. + + +
+ Interrupts at the period (fragment) boundary + + This is the most frequently found type: the hardware + generates an interrupt at each period boundary. + In this case, you can call + snd_pcm_period_elapsed() at each + interrupt. + + + + snd_pcm_period_elapsed() takes the + substream pointer as its argument. Thus, you need to keep the + substream pointer accessible from the chip instance. For + example, define substream field in the chip record to hold the + current running substream pointer, and set the pointer value + at open callback (and reset at close callback). + + + + If you acquire a spinlock in the interrupt handler, and the + lock is used in other pcm callbacks, too, then you have to + release the lock before calling + snd_pcm_period_elapsed(), because + snd_pcm_period_elapsed() calls other pcm + callbacks inside. + + + + Typical code would be like: + + + Interrupt Handler Case #1 + +lock); + .... + if (pcm_irq_invoked(chip)) { + /* call updater, unlock before it */ + spin_unlock(&chip->lock); + snd_pcm_period_elapsed(chip->substream); + spin_lock(&chip->lock); + /* acknowledge the interrupt if necessary */ + } + .... + spin_unlock(&chip->lock); + return IRQ_HANDLED; + } +]]> + + + +
+ +
+ High frequency timer interrupts + + This happense when the hardware doesn't generate interrupts + at the period boundary but issues timer interrupts at a fixed + timer rate (e.g. es1968 or ymfpci drivers). + In this case, you need to check the current hardware + position and accumulate the processed sample length at each + interrupt. When the accumulated size exceeds the period + size, call + snd_pcm_period_elapsed() and reset the + accumulator. + + + + Typical code would be like the following. + + + Interrupt Handler Case #2 + +lock); + .... + if (pcm_irq_invoked(chip)) { + unsigned int last_ptr, size; + /* get the current hardware pointer (in frames) */ + last_ptr = get_hw_ptr(chip); + /* calculate the processed frames since the + * last update + */ + if (last_ptr < chip->last_ptr) + size = runtime->buffer_size + last_ptr + - chip->last_ptr; + else + size = last_ptr - chip->last_ptr; + /* remember the last updated point */ + chip->last_ptr = last_ptr; + /* accumulate the size */ + chip->size += size; + /* over the period boundary? */ + if (chip->size >= runtime->period_size) { + /* reset the accumulator */ + chip->size %= runtime->period_size; + /* call updater */ + spin_unlock(&chip->lock); + snd_pcm_period_elapsed(substream); + spin_lock(&chip->lock); + } + /* acknowledge the interrupt if necessary */ + } + .... + spin_unlock(&chip->lock); + return IRQ_HANDLED; + } +]]> + + + +
+ +
+ On calling <function>snd_pcm_period_elapsed()</function> + + In both cases, even if more than one period are elapsed, you + don't have to call + snd_pcm_period_elapsed() many times. Call + only once. And the pcm layer will check the current hardware + pointer and update to the latest status. + +
+
+ +
+ Atomicity + + One of the most important (and thus difficult to debug) problems + in kernel programming are race conditions. + In the Linux kernel, they are usually avoided via spin-locks, mutexes + or semaphores. In general, if a race condition can happen + in an interrupt handler, it has to be managed atomically, and you + have to use a spinlock to protect the critical session. If the + critical section is not in interrupt handler code and + if taking a relatively long time to execute is acceptable, you + should use mutexes or semaphores instead. + + + + As already seen, some pcm callbacks are atomic and some are + not. For example, the hw_params callback is + non-atomic, while trigger callback is + atomic. This means, the latter is called already in a spinlock + held by the PCM middle layer. Please take this atomicity into + account when you choose a locking scheme in the callbacks. + + + + In the atomic callbacks, you cannot use functions which may call + schedule or go to + sleep. Semaphores and mutexes can sleep, + and hence they cannot be used inside the atomic callbacks + (e.g. trigger callback). + To implement some delay in such a callback, please use + udelay() or mdelay(). + + + + All three atomic callbacks (trigger, pointer, and ack) are + called with local interrupts disabled. + + +
+
+ Constraints + + If your chip supports unconventional sample rates, or only the + limited samples, you need to set a constraint for the + condition. + + + + For example, in order to restrict the sample rates in the some + supported values, use + snd_pcm_hw_constraint_list(). + You need to call this function in the open callback. + + + Example of Hardware Constraints + +runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + if (err < 0) + return err; + .... + } +]]> + + + + + + There are many different constraints. + Look at sound/pcm.h for a complete list. + You can even define your own constraint rules. + For example, let's suppose my_chip can manage a substream of 1 channel + if and only if the format is S16_LE, otherwise it supports any format + specified in the snd_pcm_hardware structure (or in any + other constraint_list). You can build a rule like this: + + + Example of Hardware Constraints for Channels + +min < 2) { + fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE; + return snd_mask_refine(f, &fmt); + } + return 0; + } +]]> + + + + + + Then you need to call this function to add your rule: + + + +runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_channels_by_format, 0, SNDRV_PCM_HW_PARAM_FORMAT, + -1); +]]> + + + + + + The rule function is called when an application sets the number of + channels. But an application can set the format before the number of + channels. Thus you also need to define the inverse rule: + + + Example of Hardware Constraints for Channels + +bits[0] == SNDRV_PCM_FMTBIT_S16_LE) { + ch.min = ch.max = 1; + ch.integer = 1; + return snd_interval_refine(c, &ch); + } + return 0; + } +]]> + + + + + + ...and in the open callback: + + +runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_format_by_channels, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + -1); +]]> + + + + + + I won't give more details here, rather I + would like to say, Luke, use the source. + +
+ +
+ + + + + + + Control Interface + +
+ General + + The control interface is used widely for many switches, + sliders, etc. which are accessed from user-space. Its most + important use is the mixer interface. In other words, since ALSA + 0.9.x, all the mixer stuff is implemented on the control kernel API. + + + + ALSA has a well-defined AC97 control module. If your chip + supports only the AC97 and nothing else, you can skip this + section. + + + + The control API is defined in + <sound/control.h>. + Include this file if you want to add your own controls. + +
+ +
+ Definition of Controls + + To create a new control, you need to define the + following three + callbacks: info, + get and + put. Then, define a + struct snd_kcontrol_new record, such as: + + + Definition of a Control + + + + + + + + Most likely the control is created via + snd_ctl_new1(), and in such a case, you can + add the __devinitdata prefix to the + definition as above. + + + + The iface field specifies the control + type, SNDRV_CTL_ELEM_IFACE_XXX, which + is usually MIXER. + Use CARD for global controls that are not + logically part of the mixer. + If the control is closely associated with some specific device on + the sound card, use HWDEP, + PCM, RAWMIDI, + TIMER, or SEQUENCER, and + specify the device number with the + device and + subdevice fields. + + + + The name is the name identifier + string. Since ALSA 0.9.x, the control name is very important, + because its role is classified from its name. There are + pre-defined standard control names. The details are described in + the + Control Names subsection. + + + + The index field holds the index number + of this control. If there are several different controls with + the same name, they can be distinguished by the index + number. This is the case when + several codecs exist on the card. If the index is zero, you can + omit the definition above. + + + + The access field contains the access + type of this control. Give the combination of bit masks, + SNDRV_CTL_ELEM_ACCESS_XXX, there. + The details will be explained in + the + Access Flags subsection. + + + + The private_value field contains + an arbitrary long integer value for this record. When using + the generic info, + get and + put callbacks, you can pass a value + through this field. If several small numbers are necessary, you can + combine them in bitwise. Or, it's possible to give a pointer + (casted to unsigned long) of some record to this field, too. + + + + The tlv field can be used to provide + metadata about the control; see the + + Metadata subsection. + + + + The other three are + + callback functions. + +
+ +
+ Control Names + + There are some standards to define the control names. A + control is usually defined from the three parts as + SOURCE DIRECTION FUNCTION. + + + + The first, SOURCE, specifies the source + of the control, and is a string such as Master, + PCM, CD and + Line. There are many pre-defined sources. + + + + The second, DIRECTION, is one of the + following strings according to the direction of the control: + Playback, Capture, Bypass + Playback and Bypass Capture. Or, it can + be omitted, meaning both playback and capture directions. + + + + The third, FUNCTION, is one of the + following strings according to the function of the control: + Switch, Volume and + Route. + + + + The example of control names are, thus, Master Capture + Switch or PCM Playback Volume. + + + + There are some exceptions: + + +
+ Global capture and playback + + Capture Source, Capture Switch + and Capture Volume are used for the global + capture (input) source, switch and volume. Similarly, + Playback Switch and Playback + Volume are used for the global output gain switch and + volume. + +
+ +
+ Tone-controls + + tone-control switch and volumes are specified like + Tone Control - XXX, e.g. Tone Control - + Switch, Tone Control - Bass, + Tone Control - Center. + +
+ +
+ 3D controls + + 3D-control switches and volumes are specified like 3D + Control - XXX, e.g. 3D Control - + Switch, 3D Control - Center, 3D + Control - Space. + +
+ +
+ Mic boost + + Mic-boost switch is set as Mic Boost or + Mic Boost (6dB). + + + + More precise information can be found in + Documentation/sound/alsa/ControlNames.txt. + +
+
+ +
+ Access Flags + + + The access flag is the bitmask which specifies the access type + of the given control. The default access type is + SNDRV_CTL_ELEM_ACCESS_READWRITE, + which means both read and write are allowed to this control. + When the access flag is omitted (i.e. = 0), it is + considered as READWRITE access as default. + + + + When the control is read-only, pass + SNDRV_CTL_ELEM_ACCESS_READ instead. + In this case, you don't have to define + the put callback. + Similarly, when the control is write-only (although it's a rare + case), you can use the WRITE flag instead, and + you don't need the get callback. + + + + If the control value changes frequently (e.g. the VU meter), + VOLATILE flag should be given. This means + that the control may be changed without + + notification. Applications should poll such + a control constantly. + + + + When the control is inactive, set + the INACTIVE flag, too. + There are LOCK and + OWNER flags to change the write + permissions. + + +
+ +
+ Callbacks + +
+ info callback + + The info callback is used to get + detailed information on this control. This must store the + values of the given struct snd_ctl_elem_info + object. For example, for a boolean control with a single + element: + + + Example of info callback + +type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; + } +]]> + + + + + + The type field specifies the type + of the control. There are BOOLEAN, + INTEGER, ENUMERATED, + BYTES, IEC958 and + INTEGER64. The + count field specifies the + number of elements in this control. For example, a stereo + volume would have count = 2. The + value field is a union, and + the values stored are depending on the type. The boolean and + integer types are identical. + + + + The enumerated type is a bit different from others. You'll + need to set the string for the currently given item index. + + + +type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item > 3) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; + } +]]> + + + + + + Some common info callbacks are available for your convenience: + snd_ctl_boolean_mono_info() and + snd_ctl_boolean_stereo_info(). + Obviously, the former is an info callback for a mono channel + boolean item, just like snd_myctl_mono_info + above, and the latter is for a stereo channel boolean item. + + +
+ +
+ get callback + + + This callback is used to read the current value of the + control and to return to user-space. + + + + For example, + + + Example of get callback + +value.integer.value[0] = get_some_value(chip); + return 0; + } +]]> + + + + + + The value field depends on + the type of control as well as on the info callback. For example, + the sb driver uses this field to store the register offset, + the bit-shift and the bit-mask. The + private_value field is set as follows: + + + + + + and is retrieved in callbacks like + + +private_value & 0xff; + int shift = (kcontrol->private_value >> 16) & 0xff; + int mask = (kcontrol->private_value >> 24) & 0xff; + .... + } +]]> + + + + + + In the get callback, + you have to fill all the elements if the + control has more than one elements, + i.e. count > 1. + In the example above, we filled only one element + (value.integer.value[0]) since it's + assumed as count = 1. + +
+ +
+ put callback + + + This callback is used to write a value from user-space. + + + + For example, + + + Example of put callback + +current_value != + ucontrol->value.integer.value[0]) { + change_current_value(chip, + ucontrol->value.integer.value[0]); + changed = 1; + } + return changed; + } +]]> + + + + As seen above, you have to return 1 if the value is + changed. If the value is not changed, return 0 instead. + If any fatal error happens, return a negative error code as + usual. + + + + As in the get callback, + when the control has more than one elements, + all elements must be evaluated in this callback, too. + +
+ +
+ Callbacks are not atomic + + All these three callbacks are basically not atomic. + +
+
+ +
+ Constructor + + When everything is ready, finally we can create a new + control. To create a control, there are two functions to be + called, snd_ctl_new1() and + snd_ctl_add(). + + + + In the simplest way, you can do like this: + + + + + + + + where my_control is the + struct snd_kcontrol_new object defined above, and chip + is the object pointer to be passed to + kcontrol->private_data + which can be referred to in callbacks. + + + + snd_ctl_new1() allocates a new + snd_kcontrol instance (that's why the definition + of my_control can be with + the __devinitdata + prefix), and snd_ctl_add assigns the given + control component to the card. + +
+ +
+ Change Notification + + If you need to change and update a control in the interrupt + routine, you can call snd_ctl_notify(). For + example, + + + + + + + + This function takes the card pointer, the event-mask, and the + control id pointer for the notification. The event-mask + specifies the types of notification, for example, in the above + example, the change of control values is notified. + The id pointer is the pointer of struct snd_ctl_elem_id + to be notified. + You can find some examples in es1938.c or + es1968.c for hardware volume interrupts. + +
+ +
+ Metadata + + To provide information about the dB values of a mixer control, use + on of the DECLARE_TLV_xxx macros from + <sound/tlv.h> to define a variable + containing this information, set thetlv.p + field to point to this variable, and include the + SNDRV_CTL_ELEM_ACCESS_TLV_READ flag in the + access field; like this: + + + + + + + + + The DECLARE_TLV_DB_SCALE macro defines + information about a mixer control where each step in the control's + value changes the dB value by a constant dB amount. + The first parameter is the name of the variable to be defined. + The second parameter is the minimum value, in units of 0.01 dB. + The third parameter is the step size, in units of 0.01 dB. + Set the fourth parameter to 1 if the minimum value actually mutes + the control. + + + + The DECLARE_TLV_DB_LINEAR macro defines + information about a mixer control where the control's value affects + the output linearly. + The first parameter is the name of the variable to be defined. + The second parameter is the minimum value, in units of 0.01 dB. + The third parameter is the maximum value, in units of 0.01 dB. + If the minimum value mutes the control, set the second parameter to + TLV_DB_GAIN_MUTE. + +
+ +
+ + + + + + + API for AC97 Codec + +
+ General + + The ALSA AC97 codec layer is a well-defined one, and you don't + have to write much code to control it. Only low-level control + routines are necessary. The AC97 codec API is defined in + <sound/ac97_codec.h>. + +
+ +
+ Full Code Example + + + Example of AC97 Interface + +private_data; + .... + /* read a register value here from the codec */ + return the_register_value; + } + + static void snd_mychip_ac97_write(struct snd_ac97 *ac97, + unsigned short reg, unsigned short val) + { + struct mychip *chip = ac97->private_data; + .... + /* write the given register value to the codec */ + } + + static int snd_mychip_ac97(struct mychip *chip) + { + struct snd_ac97_bus *bus; + struct snd_ac97_template ac97; + int err; + static struct snd_ac97_bus_ops ops = { + .write = snd_mychip_ac97_write, + .read = snd_mychip_ac97_read, + }; + + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus); + if (err < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); + ac97.private_data = chip; + return snd_ac97_mixer(bus, &ac97, &chip->ac97); + } + +]]> + + + +
+ +
+ Constructor + + To create an ac97 instance, first call snd_ac97_bus + with an ac97_bus_ops_t record with callback functions. + + + + + + + + The bus record is shared among all belonging ac97 instances. + + + + And then call snd_ac97_mixer() with an + struct snd_ac97_template + record together with the bus pointer created above. + + + +ac97); +]]> + + + + where chip->ac97 is a pointer to a newly created + ac97_t instance. + In this case, the chip pointer is set as the private data, so that + the read/write callback functions can refer to this chip instance. + This instance is not necessarily stored in the chip + record. If you need to change the register values from the + driver, or need the suspend/resume of ac97 codecs, keep this + pointer to pass to the corresponding functions. + +
+ +
+ Callbacks + + The standard callbacks are read and + write. Obviously they + correspond to the functions for read and write accesses to the + hardware low-level codes. + + + + The read callback returns the + register value specified in the argument. + + + +private_data; + .... + return the_register_value; + } +]]> + + + + Here, the chip can be cast from ac97->private_data. + + + + Meanwhile, the write callback is + used to set the register value. + + + + + + + + + + These callbacks are non-atomic like the control API callbacks. + + + + There are also other callbacks: + reset, + wait and + init. + + + + The reset callback is used to reset + the codec. If the chip requires a special kind of reset, you can + define this callback. + + + + The wait callback is used to + add some waiting time in the standard initialization of the codec. If the + chip requires the extra waiting time, define this callback. + + + + The init callback is used for + additional initialization of the codec. + +
+ +
+ Updating Registers in The Driver + + If you need to access to the codec from the driver, you can + call the following functions: + snd_ac97_write(), + snd_ac97_read(), + snd_ac97_update() and + snd_ac97_update_bits(). + + + + Both snd_ac97_write() and + snd_ac97_update() functions are used to + set a value to the given register + (AC97_XXX). The difference between them is + that snd_ac97_update() doesn't write a + value if the given value has been already set, while + snd_ac97_write() always rewrites the + value. + + + + + + + + + + snd_ac97_read() is used to read the value + of the given register. For example, + + + + + + + + + + snd_ac97_update_bits() is used to update + some bits in the given register. + + + + + + + + + + Also, there is a function to change the sample rate (of a + given register such as + AC97_PCM_FRONT_DAC_RATE) when VRA or + DRA is supported by the codec: + snd_ac97_set_rate(). + + + + + + + + + + The following registers are available to set the rate: + AC97_PCM_MIC_ADC_RATE, + AC97_PCM_FRONT_DAC_RATE, + AC97_PCM_LR_ADC_RATE, + AC97_SPDIF. When + AC97_SPDIF is specified, the register is + not really changed but the corresponding IEC958 status bits will + be updated. + +
+ +
+ Clock Adjustment + + In some chips, the clock of the codec isn't 48000 but using a + PCI clock (to save a quartz!). In this case, change the field + bus->clock to the corresponding + value. For example, intel8x0 + and es1968 drivers have their own function to read from the clock. + +
+ +
+ Proc Files + + The ALSA AC97 interface will create a proc file such as + /proc/asound/card0/codec97#0/ac97#0-0 and + ac97#0-0+regs. You can refer to these files to + see the current status and registers of the codec. + +
+ +
+ Multiple Codecs + + When there are several codecs on the same card, you need to + call snd_ac97_mixer() multiple times with + ac97.num=1 or greater. The num field + specifies the codec number. + + + + If you set up multiple codecs, you either need to write + different callbacks for each codec or check + ac97->num in the callback routines. + +
+ +
+ + + + + + + MIDI (MPU401-UART) Interface + +
+ General + + Many soundcards have built-in MIDI (MPU401-UART) + interfaces. When the soundcard supports the standard MPU401-UART + interface, most likely you can use the ALSA MPU401-UART API. The + MPU401-UART API is defined in + <sound/mpu401.h>. + + + + Some soundchips have a similar but slightly different + implementation of mpu401 stuff. For example, emu10k1 has its own + mpu401 routines. + +
+ +
+ Constructor + + To create a rawmidi object, call + snd_mpu401_uart_new(). + + + + + + + + + + The first argument is the card pointer, and the second is the + index of this component. You can create up to 8 rawmidi + devices. + + + + The third argument is the type of the hardware, + MPU401_HW_XXX. If it's not a special one, + you can use MPU401_HW_MPU401. + + + + The 4th argument is the I/O port address. Many + backward-compatible MPU401 have an I/O port such as 0x330. Or, it + might be a part of its own PCI I/O region. It depends on the + chip design. + + + + The 5th argument is a bitflag for additional information. + When the I/O port address above is part of the PCI I/O + region, the MPU401 I/O port might have been already allocated + (reserved) by the driver itself. In such a case, pass a bit flag + MPU401_INFO_INTEGRATED, + and the mpu401-uart layer will allocate the I/O ports by itself. + + + + When the controller supports only the input or output MIDI stream, + pass the MPU401_INFO_INPUT or + MPU401_INFO_OUTPUT bitflag, respectively. + Then the rawmidi instance is created as a single stream. + + + + MPU401_INFO_MMIO bitflag is used to change + the access method to MMIO (via readb and writeb) instead of + iob and outb. In this case, you have to pass the iomapped address + to snd_mpu401_uart_new(). + + + + When MPU401_INFO_TX_IRQ is set, the output + stream isn't checked in the default interrupt handler. The driver + needs to call snd_mpu401_uart_interrupt_tx() + by itself to start processing the output stream in the irq handler. + + + + Usually, the port address corresponds to the command port and + port + 1 corresponds to the data port. If not, you may change + the cport field of + struct snd_mpu401 manually + afterward. However, snd_mpu401 pointer is not + returned explicitly by + snd_mpu401_uart_new(). You need to cast + rmidi->private_data to + snd_mpu401 explicitly, + + + +private_data; +]]> + + + + and reset the cport as you like: + + + +cport = my_own_control_port; +]]> + + + + + + The 6th argument specifies the irq number for UART. If the irq + is already allocated, pass 0 to the 7th argument + (irq_flags). Otherwise, pass the flags + for irq allocation + (SA_XXX bits) to it, and the irq will be + reserved by the mpu401-uart layer. If the card doesn't generate + UART interrupts, pass -1 as the irq number. Then a timer + interrupt will be invoked for polling. + +
+ +
+ Interrupt Handler + + When the interrupt is allocated in + snd_mpu401_uart_new(), the private + interrupt handler is used, hence you don't have anything else to do + than creating the mpu401 stuff. Otherwise, you have to call + snd_mpu401_uart_interrupt() explicitly when + a UART interrupt is invoked and checked in your own interrupt + handler. + + + + In this case, you need to pass the private_data of the + returned rawmidi object from + snd_mpu401_uart_new() as the second + argument of snd_mpu401_uart_interrupt(). + + + +private_data, regs); +]]> + + + +
+ +
+ + + + + + + RawMIDI Interface + +
+ Overview + + + The raw MIDI interface is used for hardware MIDI ports that can + be accessed as a byte stream. It is not used for synthesizer + chips that do not directly understand MIDI. + + + + ALSA handles file and buffer management. All you have to do is + to write some code to move data between the buffer and the + hardware. + + + + The rawmidi API is defined in + <sound/rawmidi.h>. + +
+ +
+ Constructor + + + To create a rawmidi device, call the + snd_rawmidi_new function: + + +card, "MyMIDI", 0, outs, ins, &rmidi); + if (err < 0) + return err; + rmidi->private_data = chip; + strcpy(rmidi->name, "My MIDI"); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; +]]> + + + + + + The first argument is the card pointer, the second argument is + the ID string. + + + + The third argument is the index of this component. You can + create up to 8 rawmidi devices. + + + + The fourth and fifth arguments are the number of output and + input substreams, respectively, of this device (a substream is + the equivalent of a MIDI port). + + + + Set the info_flags field to specify + the capabilities of the device. + Set SNDRV_RAWMIDI_INFO_OUTPUT if there is + at least one output port, + SNDRV_RAWMIDI_INFO_INPUT if there is at + least one input port, + and SNDRV_RAWMIDI_INFO_DUPLEX if the device + can handle output and input at the same time. + + + + After the rawmidi device is created, you need to set the + operators (callbacks) for each substream. There are helper + functions to set the operators for all the substreams of a device: + + + + + + + + + The operators are usually defined like this: + + + + + + These callbacks are explained in the Callbacks + section. + + + + If there are more than one substream, you should give a + unique name to each of them: + + +streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, + list { + sprintf(substream->name, "My MIDI Port %d", substream->number + 1); + } + /* same for SNDRV_RAWMIDI_STREAM_INPUT */ +]]> + + + +
+ +
+ Callbacks + + + In all the callbacks, the private data that you've set for the + rawmidi device can be accessed as + substream->rmidi->private_data. + + + + + If there is more than one port, your callbacks can determine the + port index from the struct snd_rawmidi_substream data passed to each + callback: + + +number; +]]> + + + + +
+ <function>open</function> callback + + + + + + + + + This is called when a substream is opened. + You can initialize the hardware here, but you shouldn't + start transmitting/receiving data yet. + +
+ +
+ <function>close</function> callback + + + + + + + + + Guess what. + + + + The open and close + callbacks of a rawmidi device are serialized with a mutex, + and can sleep. + +
+ +
+ <function>trigger</function> callback for output + substreams + + + + + + + + + This is called with a nonzero up + parameter when there is some data in the substream buffer that + must be transmitted. + + + + To read data from the buffer, call + snd_rawmidi_transmit_peek. It will + return the number of bytes that have been read; this will be + less than the number of bytes requested when there are no more + data in the buffer. + After the data have been transmitted successfully, call + snd_rawmidi_transmit_ack to remove the + data from the substream buffer: + + + + + + + + + If you know beforehand that the hardware will accept data, you + can use the snd_rawmidi_transmit function + which reads some data and removes them from the buffer at once: + + + + + + + + + If you know beforehand how many bytes you can accept, you can + use a buffer size greater than one with the + snd_rawmidi_transmit* functions. + + + + The trigger callback must not sleep. If + the hardware FIFO is full before the substream buffer has been + emptied, you have to continue transmitting data later, either + in an interrupt handler, or with a timer if the hardware + doesn't have a MIDI transmit interrupt. + + + + The trigger callback is called with a + zero up parameter when the transmission + of data should be aborted. + +
+ +
+ <function>trigger</function> callback for input + substreams + + + + + + + + + This is called with a nonzero up + parameter to enable receiving data, or with a zero + up parameter do disable receiving data. + + + + The trigger callback must not sleep; the + actual reading of data from the device is usually done in an + interrupt handler. + + + + When data reception is enabled, your interrupt handler should + call snd_rawmidi_receive for all received + data: + + + + + + +
+ +
+ <function>drain</function> callback + + + + + + + + + This is only used with output substreams. This function should wait + until all data read from the substream buffer have been transmitted. + This ensures that the device can be closed and the driver unloaded + without losing data. + + + + This callback is optional. If you do not set + drain in the struct snd_rawmidi_ops + structure, ALSA will simply wait for 50 milliseconds + instead. + +
+
+ +
+ + + + + + + Miscellaneous Devices + +
+ FM OPL3 + + The FM OPL3 is still used in many chips (mainly for backward + compatibility). ALSA has a nice OPL3 FM control layer, too. The + OPL3 API is defined in + <sound/opl3.h>. + + + + FM registers can be directly accessed through the direct-FM API, + defined in <sound/asound_fm.h>. In + ALSA native mode, FM registers are accessed through + the Hardware-Dependant Device direct-FM extension API, whereas in + OSS compatible mode, FM registers can be accessed with the OSS + direct-FM compatible API in /dev/dmfmX device. + + + + To create the OPL3 component, you have two functions to + call. The first one is a constructor for the opl3_t + instance. + + + + + + + + + + The first argument is the card pointer, the second one is the + left port address, and the third is the right port address. In + most cases, the right port is placed at the left port + 2. + + + + The fourth argument is the hardware type. + + + + When the left and right ports have been already allocated by + the card driver, pass non-zero to the fifth argument + (integrated). Otherwise, the opl3 module will + allocate the specified ports by itself. + + + + When the accessing the hardware requires special method + instead of the standard I/O access, you can create opl3 instance + separately with snd_opl3_new(). + + + + + + + + + + Then set command, + private_data and + private_free for the private + access function, the private data and the destructor. + The l_port and r_port are not necessarily set. Only the + command must be set properly. You can retrieve the data + from the opl3->private_data field. + + + + After creating the opl3 instance via snd_opl3_new(), + call snd_opl3_init() to initialize the chip to the + proper state. Note that snd_opl3_create() always + calls it internally. + + + + If the opl3 instance is created successfully, then create a + hwdep device for this opl3. + + + + + + + + + + The first argument is the opl3_t instance you + created, and the second is the index number, usually 0. + + + + The third argument is the index-offset for the sequencer + client assigned to the OPL3 port. When there is an MPU401-UART, + give 1 for here (UART always takes 0). + +
+ +
+ Hardware-Dependent Devices + + Some chips need user-space access for special + controls or for loading the micro code. In such a case, you can + create a hwdep (hardware-dependent) device. The hwdep API is + defined in <sound/hwdep.h>. You can + find examples in opl3 driver or + isa/sb/sb16_csp.c. + + + + The creation of the hwdep instance is done via + snd_hwdep_new(). + + + + + + + + where the third argument is the index number. + + + + You can then pass any pointer value to the + private_data. + If you assign a private data, you should define the + destructor, too. The destructor function is set in + the private_free field. + + + +private_data = p; + hw->private_free = mydata_free; +]]> + + + + and the implementation of the destructor would be: + + + +private_data; + kfree(p); + } +]]> + + + + + + The arbitrary file operations can be defined for this + instance. The file operators are defined in + the ops table. For example, assume that + this chip needs an ioctl. + + + +ops.open = mydata_open; + hw->ops.ioctl = mydata_ioctl; + hw->ops.release = mydata_release; +]]> + + + + And implement the callback functions as you like. + +
+ +
+ IEC958 (S/PDIF) + + Usually the controls for IEC958 devices are implemented via + the control interface. There is a macro to compose a name string for + IEC958 controls, SNDRV_CTL_NAME_IEC958() + defined in <include/asound.h>. + + + + There are some standard controls for IEC958 status bits. These + controls use the type SNDRV_CTL_ELEM_TYPE_IEC958, + and the size of element is fixed as 4 bytes array + (value.iec958.status[x]). For the info + callback, you don't specify + the value field for this type (the count field must be set, + though). + + + + IEC958 Playback Con Mask is used to return the + bit-mask for the IEC958 status bits of consumer mode. Similarly, + IEC958 Playback Pro Mask returns the bitmask for + professional mode. They are read-only controls, and are defined + as MIXER controls (iface = + SNDRV_CTL_ELEM_IFACE_MIXER). + + + + Meanwhile, IEC958 Playback Default control is + defined for getting and setting the current default IEC958 + bits. Note that this one is usually defined as a PCM control + (iface = SNDRV_CTL_ELEM_IFACE_PCM), + although in some places it's defined as a MIXER control. + + + + In addition, you can define the control switches to + enable/disable or to set the raw bit mode. The implementation + will depend on the chip, but the control should be named as + IEC958 xxx, preferably using + the SNDRV_CTL_NAME_IEC958() macro. + + + + You can find several cases, for example, + pci/emu10k1, + pci/ice1712, or + pci/cmipci.c. + +
+ +
+ + + + + + + Buffer and Memory Management + +
+ Buffer Types + + ALSA provides several different buffer allocation functions + depending on the bus and the architecture. All these have a + consistent API. The allocation of physically-contiguous pages is + done via + snd_malloc_xxx_pages() function, where xxx + is the bus type. + + + + The allocation of pages with fallback is + snd_malloc_xxx_pages_fallback(). This + function tries to allocate the specified pages but if the pages + are not available, it tries to reduce the page sizes until + enough space is found. + + + + The release the pages, call + snd_free_xxx_pages() function. + + + + Usually, ALSA drivers try to allocate and reserve + a large contiguous physical space + at the time the module is loaded for the later use. + This is called pre-allocation. + As already written, you can call the following function at + pcm instance construction time (in the case of PCI bus). + + + + + + + + where size is the byte size to be + pre-allocated and the max is the maximum + size to be changed via the prealloc proc file. + The allocator will try to get an area as large as possible + within the given size. + + + + The second argument (type) and the third argument (device pointer) + are dependent on the bus. + In the case of the ISA bus, pass snd_dma_isa_data() + as the third argument with SNDRV_DMA_TYPE_DEV type. + For the continuous buffer unrelated to the bus can be pre-allocated + with SNDRV_DMA_TYPE_CONTINUOUS type and the + snd_dma_continuous_data(GFP_KERNEL) device pointer, + where GFP_KERNEL is the kernel allocation flag to + use. + For the PCI scatter-gather buffers, use + SNDRV_DMA_TYPE_DEV_SG with + snd_dma_pci_data(pci) + (see the + Non-Contiguous Buffers + section). + + + + Once the buffer is pre-allocated, you can use the + allocator in the hw_params callback: + + + + + + + + Note that you have to pre-allocate to use this function. + +
+ +
+ External Hardware Buffers + + Some chips have their own hardware buffers and the DMA + transfer from the host memory is not available. In such a case, + you need to either 1) copy/set the audio data directly to the + external hardware buffer, or 2) make an intermediate buffer and + copy/set the data from it to the external hardware buffer in + interrupts (or in tasklets, preferably). + + + + The first case works fine if the external hardware buffer is large + enough. This method doesn't need any extra buffers and thus is + more effective. You need to define the + copy and + silence callbacks for + the data transfer. However, there is a drawback: it cannot + be mmapped. The examples are GUS's GF1 PCM or emu8000's + wavetable PCM. + + + + The second case allows for mmap on the buffer, although you have + to handle an interrupt or a tasklet to transfer the data + from the intermediate buffer to the hardware buffer. You can find an + example in the vxpocket driver. + + + + Another case is when the chip uses a PCI memory-map + region for the buffer instead of the host memory. In this case, + mmap is available only on certain architectures like the Intel one. + In non-mmap mode, the data cannot be transferred as in the normal + way. Thus you need to define the copy and + silence callbacks as well, + as in the cases above. The examples are found in + rme32.c and rme96.c. + + + + The implementation of the copy and + silence callbacks depends upon + whether the hardware supports interleaved or non-interleaved + samples. The copy callback is + defined like below, a bit + differently depending whether the direction is playback or + capture: + + + + + + + + + + In the case of interleaved samples, the second argument + (channel) is not used. The third argument + (pos) points the + current position offset in frames. + + + + The meaning of the fourth argument is different between + playback and capture. For playback, it holds the source data + pointer, and for capture, it's the destination data pointer. + + + + The last argument is the number of frames to be copied. + + + + What you have to do in this callback is again different + between playback and capture directions. In the + playback case, you copy the given amount of data + (count) at the specified pointer + (src) to the specified offset + (pos) on the hardware buffer. When + coded like memcpy-like way, the copy would be like: + + + + + + + + + + For the capture direction, you copy the given amount of + data (count) at the specified offset + (pos) on the hardware buffer to the + specified pointer (dst). + + + + + + + + Note that both the position and the amount of data are given + in frames. + + + + In the case of non-interleaved samples, the implementation + will be a bit more complicated. + + + + You need to check the channel argument, and if it's -1, copy + the whole channels. Otherwise, you have to copy only the + specified channel. Please check + isa/gus/gus_pcm.c as an example. + + + + The silence callback is also + implemented in a similar way. + + + + + + + + + + The meanings of arguments are the same as in the + copy + callback, although there is no src/dst + argument. In the case of interleaved samples, the channel + argument has no meaning, as well as on + copy callback. + + + + The role of silence callback is to + set the given amount + (count) of silence data at the + specified offset (pos) on the hardware + buffer. Suppose that the data format is signed (that is, the + silent-data is 0), and the implementation using a memset-like + function would be like: + + + + + + + + + + In the case of non-interleaved samples, again, the + implementation becomes a bit more complicated. See, for example, + isa/gus/gus_pcm.c. + +
+ +
+ Non-Contiguous Buffers + + If your hardware supports the page table as in emu10k1 or the + buffer descriptors as in via82xx, you can use the scatter-gather + (SG) DMA. ALSA provides an interface for handling SG-buffers. + The API is provided in <sound/pcm.h>. + + + + For creating the SG-buffer handler, call + snd_pcm_lib_preallocate_pages() or + snd_pcm_lib_preallocate_pages_for_all() + with SNDRV_DMA_TYPE_DEV_SG + in the PCM constructor like other PCI pre-allocator. + You need to pass snd_dma_pci_data(pci), + where pci is the struct pci_dev pointer + of the chip as well. + The struct snd_sg_buf instance is created as + substream->dma_private. You can cast + the pointer like: + + + +dma_private; +]]> + + + + + + Then call snd_pcm_lib_malloc_pages() + in the hw_params callback + as well as in the case of normal PCI buffer. + The SG-buffer handler will allocate the non-contiguous kernel + pages of the given size and map them onto the virtually contiguous + memory. The virtual pointer is addressed in runtime->dma_area. + The physical address (runtime->dma_addr) is set to zero, + because the buffer is physically non-contigous. + The physical address table is set up in sgbuf->table. + You can get the physical address at a certain offset via + snd_pcm_sgbuf_get_addr(). + + + + When a SG-handler is used, you need to set + snd_pcm_sgbuf_ops_page as + the page callback. + (See + page callback section.) + + + + To release the data, call + snd_pcm_lib_free_pages() in the + hw_free callback as usual. + +
+ +
+ Vmalloc'ed Buffers + + It's possible to use a buffer allocated via + vmalloc, for example, for an intermediate + buffer. Since the allocated pages are not contiguous, you need + to set the page callback to obtain + the physical address at every offset. + + + + The implementation of page callback + would be like this: + + + + + + /* get the physical page pointer on the given offset */ + static struct page *mychip_page(struct snd_pcm_substream *substream, + unsigned long offset) + { + void *pageptr = substream->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); + } +]]> + + + +
+ +
+ + + + + + + Proc Interface + + ALSA provides an easy interface for procfs. The proc files are + very useful for debugging. I recommend you set up proc files if + you write a driver and want to get a running status or register + dumps. The API is found in + <sound/info.h>. + + + + To create a proc file, call + snd_card_proc_new(). + + + + + + + + where the second argument specifies the name of the proc file to be + created. The above example will create a file + my-file under the card directory, + e.g. /proc/asound/card0/my-file. + + + + Like other components, the proc entry created via + snd_card_proc_new() will be registered and + released automatically in the card registration and release + functions. + + + + When the creation is successful, the function stores a new + instance in the pointer given in the third argument. + It is initialized as a text proc file for read only. To use + this proc file as a read-only text file as it is, set the read + callback with a private data via + snd_info_set_text_ops(). + + + + + + + + where the second argument (chip) is the + private data to be used in the callbacks. The third parameter + specifies the read buffer size and the fourth + (my_proc_read) is the callback function, which + is defined like + + + + + + + + + + + In the read callback, use snd_iprintf() for + output strings, which works just like normal + printf(). For example, + + + +private_data; + + snd_iprintf(buffer, "This is my chip!\n"); + snd_iprintf(buffer, "Port = %ld\n", chip->port); + } +]]> + + + + + + The file permissions can be changed afterwards. As default, it's + set as read only for all users. If you want to add write + permission for the user (root as default), do as follows: + + + +mode = S_IFREG | S_IRUGO | S_IWUSR; +]]> + + + + and set the write buffer size and the callback + + + +c.text.write = my_proc_write; +]]> + + + + + + For the write callback, you can use + snd_info_get_line() to get a text line, and + snd_info_get_str() to retrieve a string from + the line. Some examples are found in + core/oss/mixer_oss.c, core/oss/and + pcm_oss.c. + + + + For a raw-data proc-file, set the attributes as follows: + + + +content = SNDRV_INFO_CONTENT_DATA; + entry->private_data = chip; + entry->c.ops = &my_file_io_ops; + entry->size = 4096; + entry->mode = S_IFREG | S_IRUGO; +]]> + + + + + + The callback is much more complicated than the text-file + version. You need to use a low-level I/O functions such as + copy_from/to_user() to transfer the + data. + + + + local_max_size) + size = local_max_size - pos; + if (copy_to_user(buf, local_data + pos, size)) + return -EFAULT; + return size; + } +]]> + + + + + + + + + + + + Power Management + + If the chip is supposed to work with suspend/resume + functions, you need to add power-management code to the + driver. The additional code for power-management should be + ifdef'ed with + CONFIG_PM. + + + + If the driver fully supports suspend/resume + that is, the device can be + properly resumed to its state when suspend was called, + you can set the SNDRV_PCM_INFO_RESUME flag + in the pcm info field. Usually, this is possible when the + registers of the chip can be safely saved and restored to + RAM. If this is set, the trigger callback is called with + SNDRV_PCM_TRIGGER_RESUME after the resume + callback completes. + + + + Even if the driver doesn't support PM fully but + partial suspend/resume is still possible, it's still worthy to + implement suspend/resume callbacks. In such a case, applications + would reset the status by calling + snd_pcm_prepare() and restart the stream + appropriately. Hence, you can define suspend/resume callbacks + below but don't set SNDRV_PCM_INFO_RESUME + info flag to the PCM. + + + + Note that the trigger with SUSPEND can always be called when + snd_pcm_suspend_all is called, + regardless of the SNDRV_PCM_INFO_RESUME flag. + The RESUME flag affects only the behavior + of snd_pcm_resume(). + (Thus, in theory, + SNDRV_PCM_TRIGGER_RESUME isn't needed + to be handled in the trigger callback when no + SNDRV_PCM_INFO_RESUME flag is set. But, + it's better to keep it for compatibility reasons.) + + + In the earlier version of ALSA drivers, a common + power-management layer was provided, but it has been removed. + The driver needs to define the suspend/resume hooks according to + the bus the device is connected to. In the case of PCI drivers, the + callbacks look like below: + + + + + + + + + + The scheme of the real suspend job is as follows. + + + Retrieve the card and the chip data. + Call snd_power_change_state() with + SNDRV_CTL_POWER_D3hot to change the + power status. + Call snd_pcm_suspend_all() to suspend the running PCM streams. + If AC97 codecs are used, call + snd_ac97_suspend() for each codec. + Save the register values if necessary. + Stop the hardware if necessary. + Disable the PCI device by calling + pci_disable_device(). Then, call + pci_save_state() at last. + + + + + A typical code would be like: + + + +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; + } +]]> + + + + + + The scheme of the real resume job is as follows. + + + Retrieve the card and the chip data. + Set up PCI. First, call pci_restore_state(). + Then enable the pci device again by calling pci_enable_device(). + Call pci_set_master() if necessary, too. + Re-initialize the chip. + Restore the saved registers if necessary. + Resume the mixer, e.g. calling + snd_ac97_resume(). + Restart the hardware (if any). + Call snd_power_change_state() with + SNDRV_CTL_POWER_D0 to notify the processes. + + + + + A typical code would be like: + + + +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; + } +]]> + + + + + + As shown in the above, it's better to save registers after + suspending the PCM operations via + snd_pcm_suspend_all() or + snd_pcm_suspend(). It means that the PCM + streams are already stoppped when the register snapshot is + taken. But, remember that you don't have to restart the PCM + stream in the resume callback. It'll be restarted via + trigger call with SNDRV_PCM_TRIGGER_RESUME + when necessary. + + + + OK, we have all callbacks now. Let's set them up. In the + initialization of the card, make sure that you can get the chip + data from the card instance, typically via + private_data field, in case you + created the chip data individually. + + + +private_data = chip; + .... + } +]]> + + + + When you created the chip data with + snd_card_create(), it's anyway accessible + via private_data field. + + + +private_data; + .... + } +]]> + + + + + + + If you need a space to save the registers, allocate the + buffer for it here, too, since it would be fatal + if you cannot allocate a memory in the suspend phase. + The allocated buffer should be released in the corresponding + destructor. + + + + And next, set suspend/resume callbacks to the pci_driver. + + + + + + + + + + + + + + + + Module Parameters + + There are standard module options for ALSA. At least, each + module should have the index, + id and enable + options. + + + + If the module supports multiple cards (usually up to + 8 = SNDRV_CARDS cards), they should be + arrays. The default initial values are defined already as + constants for easier programming: + + + + + + + + + + If the module supports only a single card, they could be single + variables, instead. enable option is not + always necessary in this case, but it would be better to have a + dummy option for compatibility. + + + + The module parameters must be declared with the standard + module_param()(), + module_param_array()() and + MODULE_PARM_DESC() macros. + + + + The typical coding would be like below: + + + + + + + + + + Also, don't forget to define the module description, classes, + license and devices. Especially, the recent modprobe requires to + define the module license as GPL, etc., otherwise the system is + shown as tainted. + + + + + + + + + + + + + + + + How To Put Your Driver Into ALSA Tree +
+ General + + So far, you've learned how to write the driver codes. + And you might have a question now: how to put my own + driver into the ALSA driver tree? + Here (finally :) the standard procedure is described briefly. + + + + Suppose that you create a new PCI driver for the card + xyz. The card module name would be + snd-xyz. The new driver is usually put into the alsa-driver + tree, alsa-driver/pci directory in + the case of PCI cards. + Then the driver is evaluated, audited and tested + by developers and users. After a certain time, the driver + will go to the alsa-kernel tree (to the corresponding directory, + such as alsa-kernel/pci) and eventually + will be integrated into the Linux 2.6 tree (the directory would be + linux/sound/pci). + + + + In the following sections, the driver code is supposed + to be put into alsa-driver tree. The two cases are covered: + a driver consisting of a single source file and one consisting + of several source files. + +
+ +
+ Driver with A Single Source File + + + + + Modify alsa-driver/pci/Makefile + + + + Suppose you have a file xyz.c. Add the following + two lines + + + + + + + + + + + Create the Kconfig entry + + + + Add the new entry of Kconfig for your xyz driver. + + + + + + + the line, select SND_PCM, specifies that the driver xyz supports + PCM. In addition to SND_PCM, the following components are + supported for select command: + SND_RAWMIDI, SND_TIMER, SND_HWDEP, SND_MPU401_UART, + SND_OPL3_LIB, SND_OPL4_LIB, SND_VX_LIB, SND_AC97_CODEC. + Add the select command for each supported component. + + + + Note that some selections imply the lowlevel selections. + For example, PCM includes TIMER, MPU401_UART includes RAWMIDI, + AC97_CODEC includes PCM, and OPL3_LIB includes HWDEP. + You don't need to give the lowlevel selections again. + + + + For the details of Kconfig script, refer to the kbuild + documentation. + + + + + + + Run cvscompile script to re-generate the configure script and + build the whole stuff again. + + + + +
+ +
+ Drivers with Several Source Files + + Suppose that the driver snd-xyz have several source files. + They are located in the new subdirectory, + pci/xyz. + + + + + Add a new directory (xyz) in + alsa-driver/pci/Makefile as below + + + + + + + + + + + + Under the directory xyz, create a Makefile + + + Sample Makefile for a driver xyz + + + + + + + + + + Create the Kconfig entry + + + + This procedure is as same as in the last section. + + + + + + Run cvscompile script to re-generate the configure script and + build the whole stuff again. + + + + +
+ +
+ + + + + + Useful Functions + +
+ <function>snd_printk()</function> and friends + + ALSA provides a verbose version of the + printk() function. If a kernel config + CONFIG_SND_VERBOSE_PRINTK is set, this + function prints the given message together with the file name + and the line of the caller. The KERN_XXX + prefix is processed as + well as the original printk() does, so it's + recommended to add this prefix, e.g. + + + + + + + + + + There are also printk()'s for + debugging. snd_printd() can be used for + general debugging purposes. If + CONFIG_SND_DEBUG is set, this function is + compiled, and works just like + snd_printk(). If the ALSA is compiled + without the debugging flag, it's ignored. + + + + snd_printdd() is compiled in only when + CONFIG_SND_DEBUG_VERBOSE is set. Please note + that CONFIG_SND_DEBUG_VERBOSE is not set as default + even if you configure the alsa-driver with + option. You need to give + explicitly option instead. + +
+ +
+ <function>snd_BUG()</function> + + It shows the BUG? message and + stack trace as well as snd_BUG_ON at the point. + It's useful to show that a fatal error happens there. + + + When no debug flag is set, this macro is ignored. + +
+ +
+ <function>snd_BUG_ON()</function> + + snd_BUG_ON() macro is similar with + WARN_ON() macro. For example, + + + + + + + + or it can be used as the condition, + + + + + + + + + + The macro takes an conditional expression to evaluate. + When CONFIG_SND_DEBUG, is set, the + expression is actually evaluated. If it's non-zero, it shows + the warning message such as + BUG? (xxx) + normally followed by stack trace. It returns the evaluated + value. + When no CONFIG_SND_DEBUG is set, this + macro always returns zero. + + +
+ +
+ + + + + + + Acknowledgments + + I would like to thank Phil Kerr for his help for improvement and + corrections of this document. + + + Kevin Conder reformatted the original plain-text to the + DocBook format. + + + Giuliano Pochini corrected typos and contributed the example codes + in the hardware constraints section. + + +
diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl deleted file mode 100644 index 0230a96f056..00000000000 --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - The ALSA Driver API - - - - This document is free; 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 document 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 - - - - - - - - Management of Cards and Devices - Card Management -!Esound/core/init.c - - Device Components -!Esound/core/device.c - - Module requests and Device File Entries -!Esound/core/sound.c - - Memory Management Helpers -!Esound/core/memory.c -!Esound/core/memalloc.c - - - PCM API - PCM Core -!Esound/core/pcm.c -!Esound/core/pcm_lib.c -!Esound/core/pcm_native.c - - PCM Format Helpers -!Esound/core/pcm_misc.c - - PCM Memory Management -!Esound/core/pcm_memory.c - - - Control/Mixer API - General Control Interface -!Esound/core/control.c - - AC97 Codec API -!Esound/pci/ac97/ac97_codec.c -!Esound/pci/ac97/ac97_pcm.c - - Virtual Master Control API -!Esound/core/vmaster.c -!Iinclude/sound/control.h - - - MIDI API - Raw MIDI API -!Esound/core/rawmidi.c - - MPU401-UART API -!Esound/drivers/mpu401/mpu401_uart.c - - - Proc Info API - Proc Info Interface -!Esound/core/info.c - - - Miscellaneous Functions - Hardware-Dependent Devices API -!Esound/core/hwdep.c - - Jack Abstraction Layer API -!Esound/core/jack.c - - ISA DMA Helpers -!Esound/core/isadma.c - - Other Helper Macros -!Iinclude/sound/core.h - - - - diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl deleted file mode 100644 index 46b08fef374..00000000000 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ /dev/null @@ -1,6216 +0,0 @@ - - - - - - - - - Writing an ALSA Driver - - Takashi - Iwai - -
- tiwai@suse.de -
-
-
- - Oct 15, 2007 - 0.3.7 - - - - This document describes how to write an ALSA (Advanced Linux - Sound Architecture) driver. - - - - - - Copyright (c) 2002-2005 Takashi Iwai tiwai@suse.de - - - - This document is free; 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 document 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 - - - -
- - - - - - Preface - - This document describes how to write an - - ALSA (Advanced Linux Sound Architecture) - driver. The document focuses mainly on PCI soundcards. - In the case of other device types, the API might - be different, too. However, at least the ALSA kernel API is - consistent, and therefore it would be still a bit help for - writing them. - - - - This document targets people who already have enough - C language skills and have basic linux kernel programming - knowledge. This document doesn't explain the general - topic of linux kernel coding and doesn't cover low-level - driver implementation details. It only describes - the standard way to write a PCI sound driver on ALSA. - - - - If you are already familiar with the older ALSA ver.0.5.x API, you - can check the drivers such as sound/pci/es1938.c or - sound/pci/maestro3.c which have also almost the same - code-base in the ALSA 0.5.x tree, so you can compare the differences. - - - - This document is still a draft version. Any feedback and - corrections, please!! - - - - - - - - - File Tree Structure - -
- General - - The ALSA drivers are provided in two ways. - - - - One is the trees provided as a tarball or via cvs from the - ALSA's ftp site, and another is the 2.6 (or later) Linux kernel - tree. To synchronize both, the ALSA driver tree is split into - two different trees: alsa-kernel and alsa-driver. The former - contains purely the source code for the Linux 2.6 (or later) - tree. This tree is designed only for compilation on 2.6 or - later environment. The latter, alsa-driver, contains many subtle - files for compiling ALSA drivers outside of the Linux kernel tree, - wrapper functions for older 2.2 and 2.4 kernels, to adapt the latest kernel API, - and additional drivers which are still in development or in - tests. The drivers in alsa-driver tree will be moved to - alsa-kernel (and eventually to the 2.6 kernel tree) when they are - finished and confirmed to work fine. - - - - The file tree structure of ALSA driver is depicted below. Both - alsa-kernel and alsa-driver have almost the same file - structure, except for core directory. It's - named as acore in alsa-driver tree. - - - ALSA File Tree Structure - - sound - /core - /oss - /seq - /oss - /instr - /ioctl32 - /include - /drivers - /mpu401 - /opl3 - /i2c - /l3 - /synth - /emux - /pci - /(cards) - /isa - /(cards) - /arm - /ppc - /sparc - /usb - /pcmcia /(cards) - /oss - - - -
- -
- core directory - - This directory contains the middle layer which is the heart - of ALSA drivers. In this directory, the native ALSA modules are - stored. The sub-directories contain different modules and are - dependent upon the kernel config. - - -
- core/oss - - - The codes for PCM and mixer OSS emulation modules are stored - in this directory. The rawmidi OSS emulation is included in - the ALSA rawmidi code since it's quite small. The sequencer - code is stored in core/seq/oss directory (see - - below). - -
- -
- core/ioctl32 - - - This directory contains the 32bit-ioctl wrappers for 64bit - architectures such like x86-64, ppc64 and sparc64. For 32bit - and alpha architectures, these are not compiled. - -
- -
- core/seq - - This directory and its sub-directories are for the ALSA - sequencer. This directory contains the sequencer core and - primary sequencer modules such like snd-seq-midi, - snd-seq-virmidi, etc. They are compiled only when - CONFIG_SND_SEQUENCER is set in the kernel - config. - -
- -
- core/seq/oss - - This contains the OSS sequencer emulation codes. - -
- -
- core/seq/instr - - This directory contains the modules for the sequencer - instrument layer. - -
-
- -
- include directory - - This is the place for the public header files of ALSA drivers, - which are to be exported to user-space, or included by - several files at different directories. Basically, the private - header files should not be placed in this directory, but you may - still find files there, due to historical reasons :) - -
- -
- drivers directory - - This directory contains code shared among different drivers - on different architectures. They are hence supposed not to be - architecture-specific. - For example, the dummy pcm driver and the serial MIDI - driver are found in this directory. In the sub-directories, - there is code for components which are independent from - bus and cpu architectures. - - -
- drivers/mpu401 - - The MPU401 and MPU401-UART modules are stored here. - -
- -
- drivers/opl3 and opl4 - - The OPL3 and OPL4 FM-synth stuff is found here. - -
-
- -
- i2c directory - - This contains the ALSA i2c components. - - - - Although there is a standard i2c layer on Linux, ALSA has its - own i2c code for some cards, because the soundcard needs only a - simple operation and the standard i2c API is too complicated for - such a purpose. - - -
- i2c/l3 - - This is a sub-directory for ARM L3 i2c. - -
-
- -
- synth directory - - This contains the synth middle-level modules. - - - - So far, there is only Emu8000/Emu10k1 synth driver under - the synth/emux sub-directory. - -
- -
- pci directory - - This directory and its sub-directories hold the top-level card modules - for PCI soundcards and the code specific to the PCI BUS. - - - - The drivers compiled from a single file are stored directly - in the pci directory, while the drivers with several source files are - stored on their own sub-directory (e.g. emu10k1, ice1712). - -
- -
- isa directory - - This directory and its sub-directories hold the top-level card modules - for ISA soundcards. - -
- -
- arm, ppc, and sparc directories - - They are used for top-level card modules which are - specific to one of these architectures. - -
- -
- usb directory - - This directory contains the USB-audio driver. In the latest version, the - USB MIDI driver is integrated in the usb-audio driver. - -
- -
- pcmcia directory - - The PCMCIA, especially PCCard drivers will go here. CardBus - drivers will be in the pci directory, because their API is identical - to that of standard PCI cards. - -
- -
- oss directory - - The OSS/Lite source files are stored here in Linux 2.6 (or - later) tree. In the ALSA driver tarball, this directory is empty, - of course :) - -
-
- - - - - - - Basic Flow for PCI Drivers - -
- Outline - - The minimum flow for PCI soundcards is as follows: - - - define the PCI ID table (see the section - PCI Entries - ). - create probe() callback. - create remove() callback. - create a pci_driver structure - containing the three pointers above. - create an init() function just calling - the pci_register_driver() to register the pci_driver table - defined above. - create an exit() function to call - the pci_unregister_driver() function. - - -
- -
- Full Code Example - - The code example is shown below. Some parts are kept - unimplemented at this moment but will be filled in the - next sections. The numbers in the comment lines of the - snd_mychip_probe() function - refer to details explained in the following section. - - - Basic Flow for PCI Drivers - Example - - - #include - #include - #include - #include - - /* module parameters (see "Module Parameters") */ - /* SNDRV_CARDS: maximum number of cards supported by this module */ - static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; - static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; - static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; - - /* definition of the chip-specific record */ - struct mychip { - struct snd_card *card; - /* the rest of the implementation will be in section - * "PCI Resource Management" - */ - }; - - /* chip-specific destructor - * (see "PCI Resource Management") - */ - static int snd_mychip_free(struct mychip *chip) - { - .... /* will be implemented later... */ - } - - /* component-destructor - * (see "Management of Cards and Components") - */ - static int snd_mychip_dev_free(struct snd_device *device) - { - return snd_mychip_free(device->device_data); - } - - /* chip-specific constructor - * (see "Management of Cards and Components") - */ - static int __devinit snd_mychip_create(struct snd_card *card, - struct pci_dev *pci, - struct mychip **rchip) - { - struct mychip *chip; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_mychip_dev_free, - }; - - *rchip = NULL; - - /* check PCI availability here - * (see "PCI Resource Management") - */ - .... - - /* allocate a chip-specific data with zero filled */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->card = card; - - /* rest of initialization here; will be implemented - * later, see "PCI Resource Management" - */ - .... - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) { - snd_mychip_free(chip); - return err; - } - - snd_card_set_dev(card, &pci->dev); - - *rchip = chip; - return 0; - } - - /* constructor -- see "Constructor" sub-section */ - static int __devinit snd_mychip_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) - { - static int dev; - struct snd_card *card; - struct mychip *chip; - int err; - - /* (1) */ - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - /* (2) */ - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); - if (err < 0) - return err; - - /* (3) */ - err = snd_mychip_create(card, pci, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } - - /* (4) */ - strcpy(card->driver, "My Chip"); - strcpy(card->shortname, "My Own Chip 123"); - sprintf(card->longname, "%s at 0x%lx irq %i", - card->shortname, chip->ioport, chip->irq); - - /* (5) */ - .... /* implemented later */ - - /* (6) */ - err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } - - /* (7) */ - pci_set_drvdata(pci, card); - dev++; - return 0; - } - - /* destructor -- see the "Destructor" sub-section */ - static void __devexit snd_mychip_remove(struct pci_dev *pci) - { - snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); - } -]]> - - - -
- -
- Constructor - - The real constructor of PCI drivers is the probe callback. - The probe callback and other component-constructors which are called - from the probe callback should be defined with - the __devinit prefix. You - cannot use the __init prefix for them, - because any PCI device could be a hotplug device. - - - - In the probe callback, the following scheme is often used. - - -
- 1) Check and increment the device index. - - - -= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } -]]> - - - - where enable[dev] is the module option. - - - - Each time the probe callback is called, check the - availability of the device. If not available, simply increment - the device index and returns. dev will be incremented also - later (step - 7). - -
- -
- 2) Create a card instance - - - - - - - - - - The details will be explained in the section - - Management of Cards and Components. - -
- -
- 3) Create a main component - - In this part, the PCI resources are allocated. - - - - - - - - The details will be explained in the section PCI Resource - Management. - -
- -
- 4) Set the driver ID and name strings. - - - -driver, "My Chip"); - strcpy(card->shortname, "My Own Chip 123"); - sprintf(card->longname, "%s at 0x%lx irq %i", - card->shortname, chip->ioport, chip->irq); -]]> - - - - The driver field holds the minimal ID string of the - chip. This is used by alsa-lib's configurator, so keep it - simple but unique. - Even the same driver can have different driver IDs to - distinguish the functionality of each chip type. - - - - The shortname field is a string shown as more verbose - name. The longname field contains the information - shown in /proc/asound/cards. - -
- -
- 5) Create other components, such as mixer, MIDI, etc. - - Here you define the basic components such as - PCM, - mixer (e.g. AC97), - MIDI (e.g. MPU-401), - and other interfaces. - Also, if you want a proc - file, define it here, too. - -
- -
- 6) Register the card instance. - - - - - - - - - - Will be explained in the section Management - of Cards and Components, too. - -
- -
- 7) Set the PCI driver data and return zero. - - - - - - - - In the above, the card record is stored. This pointer is - used in the remove callback and power-management - callbacks, too. - -
-
- -
- Destructor - - The destructor, remove callback, simply releases the card - instance. Then the ALSA middle layer will release all the - attached components automatically. - - - - It would be typically like the following: - - - - - - - - The above code assumes that the card pointer is set to the PCI - driver data. - -
- -
- Header Files - - For the above example, at least the following include files - are necessary. - - - - - #include - #include - #include - #include -]]> - - - - where the last one is necessary only when module options are - defined in the source file. If the code is split into several - files, the files without module options don't need them. - - - - In addition to these headers, you'll need - <linux/interrupt.h> for interrupt - handling, and <asm/io.h> for I/O - access. If you use the mdelay() or - udelay() functions, you'll need to include - <linux/delay.h> too. - - - - The ALSA interfaces like the PCM and control APIs are defined in other - <sound/xxx.h> header files. - They have to be included after - <sound/core.h>. - - -
-
- - - - - - - Management of Cards and Components - -
- Card Instance - - For each soundcard, a card record must be allocated. - - - - A card record is the headquarters of the soundcard. It manages - the whole list of devices (components) on the soundcard, such as - PCM, mixers, MIDI, synthesizer, and so on. Also, the card - record holds the ID and the name strings of the card, manages - the root of proc files, and controls the power-management states - and hotplug disconnections. The component list on the card - record is used to manage the correct release of resources at - destruction. - - - - As mentioned above, to create a card instance, call - snd_card_create(). - - - - - - - - - - The function takes five arguments, the card-index number, the - id string, the module pointer (usually - THIS_MODULE), - the size of extra-data space, and the pointer to return the - card instance. The extra_size argument is used to - allocate card->private_data for the - chip-specific data. Note that these data - are allocated by snd_card_create(). - -
- -
- Components - - After the card is created, you can attach the components - (devices) to the card instance. In an ALSA driver, a component is - represented as a struct snd_device object. - A component can be a PCM instance, a control interface, a raw - MIDI interface, etc. Each such instance has one component - entry. - - - - A component can be created via - snd_device_new() function. - - - - - - - - - - This takes the card pointer, the device-level - (SNDRV_DEV_XXX), the data pointer, and the - callback pointers (&ops). The - device-level defines the type of components and the order of - registration and de-registration. For most components, the - device-level is already defined. For a user-defined component, - you can use SNDRV_DEV_LOWLEVEL. - - - - This function itself doesn't allocate the data space. The data - must be allocated manually beforehand, and its pointer is passed - as the argument. This pointer is used as the - (chip identifier in the above example) - for the instance. - - - - Each pre-defined ALSA component such as ac97 and pcm calls - snd_device_new() inside its - constructor. The destructor for each component is defined in the - callback pointers. Hence, you don't need to take care of - calling a destructor for such a component. - - - - If you wish to create your own component, you need to - set the destructor function to the dev_free callback in - the ops, so that it can be released - automatically via snd_card_free(). - The next example will show an implementation of chip-specific - data. - -
- -
- Chip-Specific Data - - Chip-specific information, e.g. the I/O port address, its - resource pointer, or the irq number, is stored in the - chip-specific record. - - - - - - - - - - In general, there are two ways of allocating the chip record. - - -
- 1. Allocating via <function>snd_card_create()</function>. - - As mentioned above, you can pass the extra-data-length - to the 4th argument of snd_card_create(), i.e. - - - - - - - - struct mychip is the type of the chip record. - - - - In return, the allocated record can be accessed as - - - -private_data; -]]> - - - - With this method, you don't have to allocate twice. - The record is released together with the card instance. - -
- -
- 2. Allocating an extra device. - - - After allocating a card instance via - snd_card_create() (with - 0 on the 4th arg), call - kzalloc(). - - - - - - - - - - The chip record should have the field to hold the card - pointer at least, - - - - - - - - - - Then, set the card pointer in the returned chip instance. - - - -card = card; -]]> - - - - - - Next, initialize the fields, and register this chip - record as a low-level device with a specified - ops, - - - - - - - - snd_mychip_dev_free() is the - device-destructor function, which will call the real - destructor. - - - - - -device_data); - } -]]> - - - - where snd_mychip_free() is the real destructor. - -
-
- -
- Registration and Release - - After all components are assigned, register the card instance - by calling snd_card_register(). Access - to the device files is enabled at this point. That is, before - snd_card_register() is called, the - components are safely inaccessible from external side. If this - call fails, exit the probe function after releasing the card via - snd_card_free(). - - - - For releasing the card instance, you can call simply - snd_card_free(). As mentioned earlier, all - components are released automatically by this call. - - - - As further notes, the destructors (both - snd_mychip_dev_free and - snd_mychip_free) cannot be defined with - the __devexit prefix, because they may be - called from the constructor, too, at the false path. - - - - For a device which allows hotplugging, you can use - snd_card_free_when_closed. This one will - postpone the destruction until all devices are closed. - - -
- -
- - - - - - - PCI Resource Management - -
- Full Code Example - - In this section, we'll complete the chip-specific constructor, - destructor and PCI entries. Example code is shown first, - below. - - - PCI Resource Management Example - -irq >= 0) - free_irq(chip->irq, chip); - /* release the I/O ports & memory */ - pci_release_regions(chip->pci); - /* disable the PCI entry */ - pci_disable_device(chip->pci); - /* release the data */ - kfree(chip); - return 0; - } - - /* chip-specific constructor */ - static int __devinit snd_mychip_create(struct snd_card *card, - struct pci_dev *pci, - struct mychip **rchip) - { - struct mychip *chip; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_mychip_dev_free, - }; - - *rchip = NULL; - - /* initialize the PCI entry */ - err = pci_enable_device(pci); - if (err < 0) - return err; - /* check PCI availability (28bit DMA) */ - if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || - pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { - printk(KERN_ERR "error to set 28bit mask DMA\n"); - pci_disable_device(pci); - return -ENXIO; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } - - /* initialize the stuff */ - chip->card = card; - chip->pci = pci; - chip->irq = -1; - - /* (1) PCI resource allocation */ - err = pci_request_regions(pci, "My Chip"); - if (err < 0) { - kfree(chip); - pci_disable_device(pci); - return err; - } - chip->port = pci_resource_start(pci, 0); - if (request_irq(pci->irq, snd_mychip_interrupt, - IRQF_SHARED, "My Chip", chip)) { - printk(KERN_ERR "cannot grab irq %d\n", pci->irq); - snd_mychip_free(chip); - return -EBUSY; - } - chip->irq = pci->irq; - - /* (2) initialization of the chip hardware */ - .... /* (not implemented in this document) */ - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) { - snd_mychip_free(chip); - return err; - } - - snd_card_set_dev(card, &pci->dev); - - *rchip = chip; - return 0; - } - - /* PCI IDs */ - static struct pci_device_id snd_mychip_ids[] = { - { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, - .... - { 0, } - }; - MODULE_DEVICE_TABLE(pci, snd_mychip_ids); - - /* pci_driver definition */ - static struct pci_driver driver = { - .name = "My Own Chip", - .id_table = snd_mychip_ids, - .probe = snd_mychip_probe, - .remove = __devexit_p(snd_mychip_remove), - }; - - /* module initialization */ - static int __init alsa_card_mychip_init(void) - { - return pci_register_driver(&driver); - } - - /* module clean up */ - static void __exit alsa_card_mychip_exit(void) - { - pci_unregister_driver(&driver); - } - - module_init(alsa_card_mychip_init) - module_exit(alsa_card_mychip_exit) - - EXPORT_NO_SYMBOLS; /* for old kernels only */ -]]> - - - -
- -
- Some Hafta's - - The allocation of PCI resources is done in the - probe() function, and usually an extra - xxx_create() function is written for this - purpose. - - - - In the case of PCI devices, you first have to call - the pci_enable_device() function before - allocating resources. Also, you need to set the proper PCI DMA - mask to limit the accessed I/O range. In some cases, you might - need to call pci_set_master() function, - too. - - - - Suppose the 28bit mask, and the code to be added would be like: - - - - - - - -
- -
- Resource Allocation - - The allocation of I/O ports and irqs is done via standard kernel - functions. Unlike ALSA ver.0.5.x., there are no helpers for - that. And these resources must be released in the destructor - function (see below). Also, on ALSA 0.9.x, you don't need to - allocate (pseudo-)DMA for PCI like in ALSA 0.5.x. - - - - Now assume that the PCI device has an I/O port with 8 bytes - and an interrupt. Then struct mychip will have the - following fields: - - - - - - - - - - For an I/O port (and also a memory region), you need to have - the resource pointer for the standard resource management. For - an irq, you have to keep only the irq number (integer). But you - need to initialize this number as -1 before actual allocation, - since irq 0 is valid. The port address and its resource pointer - can be initialized as null by - kzalloc() automatically, so you - don't have to take care of resetting them. - - - - The allocation of an I/O port is done like this: - - - -port = pci_resource_start(pci, 0); -]]> - - - - - - - It will reserve the I/O port region of 8 bytes of the given - PCI device. The returned value, chip->res_port, is allocated - via kmalloc() by - request_region(). The pointer must be - released via kfree(), but there is a - problem with this. This issue will be explained later. - - - - The allocation of an interrupt source is done like this: - - - -irq, snd_mychip_interrupt, - IRQF_SHARED, "My Chip", chip)) { - printk(KERN_ERR "cannot grab irq %d\n", pci->irq); - snd_mychip_free(chip); - return -EBUSY; - } - chip->irq = pci->irq; -]]> - - - - where snd_mychip_interrupt() is the - interrupt handler defined later. - Note that chip->irq should be defined - only when request_irq() succeeded. - - - - On the PCI bus, interrupts can be shared. Thus, - IRQF_SHARED is used as the interrupt flag of - request_irq(). - - - - The last argument of request_irq() is the - data pointer passed to the interrupt handler. Usually, the - chip-specific record is used for that, but you can use what you - like, too. - - - - I won't give details about the interrupt handler at this - point, but at least its appearance can be explained now. The - interrupt handler looks usually like the following: - - - - - - - - - - Now let's write the corresponding destructor for the resources - above. The role of destructor is simple: disable the hardware - (if already activated) and release the resources. So far, we - have no hardware part, so the disabling code is not written here. - - - - To release the resources, the check-and-release - method is a safer way. For the interrupt, do like this: - - - -irq >= 0) - free_irq(chip->irq, chip); -]]> - - - - Since the irq number can start from 0, you should initialize - chip->irq with a negative value (e.g. -1), so that you can - check the validity of the irq number as above. - - - - When you requested I/O ports or memory regions via - pci_request_region() or - pci_request_regions() like in this example, - release the resource(s) using the corresponding function, - pci_release_region() or - pci_release_regions(). - - - -pci); -]]> - - - - - - When you requested manually via request_region() - or request_mem_region, you can release it via - release_resource(). Suppose that you keep - the resource pointer returned from request_region() - in chip->res_port, the release procedure looks like: - - - -res_port); -]]> - - - - - - Don't forget to call pci_disable_device() - before the end. - - - - And finally, release the chip-specific record. - - - - - - - - - - Again, remember that you cannot - use the __devexit prefix for this destructor. - - - - We didn't implement the hardware disabling part in the above. - If you need to do this, please note that the destructor may be - called even before the initialization of the chip is completed. - It would be better to have a flag to skip hardware disabling - if the hardware was not initialized yet. - - - - When the chip-data is assigned to the card using - snd_device_new() with - SNDRV_DEV_LOWLELVEL , its destructor is - called at the last. That is, it is assured that all other - components like PCMs and controls have already been released. - You don't have to stop PCMs, etc. explicitly, but just - call low-level hardware stopping. - - - - The management of a memory-mapped region is almost as same as - the management of an I/O port. You'll need three fields like - the following: - - - - - - - - and the allocation would be like below: - - - -iobase_phys = pci_resource_start(pci, 0); - chip->iobase_virt = ioremap_nocache(chip->iobase_phys, - pci_resource_len(pci, 0)); -]]> - - - - and the corresponding destructor would be: - - - -iobase_virt) - iounmap(chip->iobase_virt); - .... - pci_release_regions(chip->pci); - .... - } -]]> - - - - -
- -
- Registration of Device Struct - - At some point, typically after calling snd_device_new(), - you need to register the struct device of the chip - you're handling for udev and co. ALSA provides a macro for compatibility with - older kernels. Simply call like the following: - - -dev); -]]> - - - so that it stores the PCI's device pointer to the card. This will be - referred by ALSA core functions later when the devices are registered. - - - In the case of non-PCI, pass the proper device struct pointer of the BUS - instead. (In the case of legacy ISA without PnP, you don't have to do - anything.) - -
- -
- PCI Entries - - So far, so good. Let's finish the missing PCI - stuff. At first, we need a - pci_device_id table for this - chipset. It's a table of PCI vendor/device ID number, and some - masks. - - - - For example, - - - - - - - - - - The first and second fields of - the pci_device_id structure are the vendor and - device IDs. If you have no reason to filter the matching - devices, you can leave the remaining fields as above. The last - field of the pci_device_id struct contains - private data for this entry. You can specify any value here, for - example, to define specific operations for supported device IDs. - Such an example is found in the intel8x0 driver. - - - - The last entry of this list is the terminator. You must - specify this all-zero entry. - - - - Then, prepare the pci_driver record: - - - - - - - - - - The probe and - remove functions have already - been defined in the previous sections. - The remove function should - be defined with the - __devexit_p() macro, so that it's not - defined for built-in (and non-hot-pluggable) case. The - name - field is the name string of this device. Note that you must not - use a slash / in this string. - - - - And at last, the module entries: - - - - - - - - - - Note that these module entries are tagged with - __init and - __exit prefixes, not - __devinit nor - __devexit. - - - - Oh, one thing was forgotten. If you have no exported symbols, - you need to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels). - - - - - - - - That's all! - -
-
- - - - - - - PCM Interface - -
- General - - The PCM middle layer of ALSA is quite powerful and it is only - necessary for each driver to implement the low-level functions - to access its hardware. - - - - For accessing to the PCM layer, you need to include - <sound/pcm.h> first. In addition, - <sound/pcm_params.h> might be needed - if you access to some functions related with hw_param. - - - - Each card device can have up to four pcm instances. A pcm - instance corresponds to a pcm device file. The limitation of - number of instances comes only from the available bit size of - the Linux's device numbers. Once when 64bit device number is - used, we'll have more pcm instances available. - - - - A pcm instance consists of pcm playback and capture streams, - and each pcm stream consists of one or more pcm substreams. Some - soundcards support multiple playback functions. For example, - emu10k1 has a PCM playback of 32 stereo substreams. In this case, at - each open, a free substream is (usually) automatically chosen - and opened. Meanwhile, when only one substream exists and it was - already opened, the successful open will either block - or error with EAGAIN according to the - file open mode. But you don't have to care about such details in your - driver. The PCM middle layer will take care of such work. - -
- -
- Full Code Example - - The example code below does not include any hardware access - routines but shows only the skeleton, how to build up the PCM - interfaces. - - - PCM Example Code - - - .... - - /* hardware definition */ - static struct snd_pcm_hardware snd_mychip_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 32768, - .period_bytes_min = 4096, - .period_bytes_max = 32768, - .periods_min = 1, - .periods_max = 1024, - }; - - /* hardware definition */ - static struct snd_pcm_hardware snd_mychip_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 32768, - .period_bytes_min = 4096, - .period_bytes_max = 32768, - .periods_min = 1, - .periods_max = 1024, - }; - - /* open callback */ - static int snd_mychip_playback_open(struct snd_pcm_substream *substream) - { - struct mychip *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw = snd_mychip_playback_hw; - /* more hardware-initialization will be done here */ - .... - return 0; - } - - /* close callback */ - static int snd_mychip_playback_close(struct snd_pcm_substream *substream) - { - struct mychip *chip = snd_pcm_substream_chip(substream); - /* the hardware-specific codes will be here */ - .... - return 0; - - } - - /* open callback */ - static int snd_mychip_capture_open(struct snd_pcm_substream *substream) - { - struct mychip *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw = snd_mychip_capture_hw; - /* more hardware-initialization will be done here */ - .... - return 0; - } - - /* close callback */ - static int snd_mychip_capture_close(struct snd_pcm_substream *substream) - { - struct mychip *chip = snd_pcm_substream_chip(substream); - /* the hardware-specific codes will be here */ - .... - return 0; - - } - - /* hw_params callback */ - static int snd_mychip_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) - { - return snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - } - - /* hw_free callback */ - static int snd_mychip_pcm_hw_free(struct snd_pcm_substream *substream) - { - return snd_pcm_lib_free_pages(substream); - } - - /* prepare callback */ - static int snd_mychip_pcm_prepare(struct snd_pcm_substream *substream) - { - struct mychip *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - /* set up the hardware with the current configuration - * for example... - */ - mychip_set_sample_format(chip, runtime->format); - mychip_set_sample_rate(chip, runtime->rate); - mychip_set_channels(chip, runtime->channels); - mychip_set_dma_setup(chip, runtime->dma_addr, - chip->buffer_size, - chip->period_size); - return 0; - } - - /* trigger callback */ - static int snd_mychip_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) - { - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - /* do something to start the PCM engine */ - .... - break; - case SNDRV_PCM_TRIGGER_STOP: - /* do something to stop the PCM engine */ - .... - break; - default: - return -EINVAL; - } - } - - /* pointer callback */ - static snd_pcm_uframes_t - snd_mychip_pcm_pointer(struct snd_pcm_substream *substream) - { - struct mychip *chip = snd_pcm_substream_chip(substream); - unsigned int current_ptr; - - /* get the current hardware pointer */ - current_ptr = mychip_get_hw_pointer(chip); - return current_ptr; - } - - /* operators */ - static struct snd_pcm_ops snd_mychip_playback_ops = { - .open = snd_mychip_playback_open, - .close = snd_mychip_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_mychip_pcm_hw_params, - .hw_free = snd_mychip_pcm_hw_free, - .prepare = snd_mychip_pcm_prepare, - .trigger = snd_mychip_pcm_trigger, - .pointer = snd_mychip_pcm_pointer, - }; - - /* operators */ - static struct snd_pcm_ops snd_mychip_capture_ops = { - .open = snd_mychip_capture_open, - .close = snd_mychip_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_mychip_pcm_hw_params, - .hw_free = snd_mychip_pcm_hw_free, - .prepare = snd_mychip_pcm_prepare, - .trigger = snd_mychip_pcm_trigger, - .pointer = snd_mychip_pcm_pointer, - }; - - /* - * definitions of capture are omitted here... - */ - - /* create a pcm device */ - static int __devinit snd_mychip_new_pcm(struct mychip *chip) - { - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, &pcm); - if (err < 0) - return err; - pcm->private_data = chip; - strcpy(pcm->name, "My Chip"); - chip->pcm = pcm; - /* set operators */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_mychip_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_mychip_capture_ops); - /* pre-allocation of buffers */ - /* NOTE: this may fail */ - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - 64*1024, 64*1024); - return 0; - } -]]> - - - -
- -
- Constructor - - A pcm instance is allocated by the snd_pcm_new() - function. It would be better to create a constructor for pcm, - namely, - - - -card, "My Chip", 0, 1, 1, &pcm); - if (err < 0) - return err; - pcm->private_data = chip; - strcpy(pcm->name, "My Chip"); - chip->pcm = pcm; - .... - return 0; - } -]]> - - - - - - The snd_pcm_new() function takes four - arguments. The first argument is the card pointer to which this - pcm is assigned, and the second is the ID string. - - - - The third argument (index, 0 in the - above) is the index of this new pcm. It begins from zero. If - you create more than one pcm instances, specify the - different numbers in this argument. For example, - index = 1 for the second PCM device. - - - - The fourth and fifth arguments are the number of substreams - for playback and capture, respectively. Here 1 is used for - both arguments. When no playback or capture substreams are available, - pass 0 to the corresponding argument. - - - - If a chip supports multiple playbacks or captures, you can - specify more numbers, but they must be handled properly in - open/close, etc. callbacks. When you need to know which - substream you are referring to, then it can be obtained from - struct snd_pcm_substream data passed to each callback - as follows: - - - -number; -]]> - - - - - - After the pcm is created, you need to set operators for each - pcm stream. - - - - - - - - - - The operators are defined typically like this: - - - - - - - - All the callbacks are described in the - - Operators subsection. - - - - After setting the operators, you probably will want to - pre-allocate the buffer. For the pre-allocation, simply call - the following: - - - -pci), - 64*1024, 64*1024); -]]> - - - - It will allocate a buffer up to 64kB as default. - Buffer management details will be described in the later section Buffer and Memory - Management. - - - - Additionally, you can set some extra information for this pcm - in pcm->info_flags. - The available values are defined as - SNDRV_PCM_INFO_XXX in - <sound/asound.h>, which is used for - the hardware definition (described later). When your soundchip - supports only half-duplex, specify like this: - - - -info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; -]]> - - - -
- -
- ... And the Destructor? - - The destructor for a pcm instance is not always - necessary. Since the pcm device will be released by the middle - layer code automatically, you don't have to call the destructor - explicitly. - - - - The destructor would be necessary if you created - special records internally and needed to release them. In such a - case, set the destructor function to - pcm->private_free: - - - PCM Instance with a Destructor - -my_private_pcm_data); - /* do what you like else */ - .... - } - - static int __devinit snd_mychip_new_pcm(struct mychip *chip) - { - struct snd_pcm *pcm; - .... - /* allocate your own data */ - chip->my_private_pcm_data = kmalloc(...); - /* set the destructor */ - pcm->private_data = chip; - pcm->private_free = mychip_pcm_free; - .... - } -]]> - - - -
- -
- Runtime Pointer - The Chest of PCM Information - - When the PCM substream is opened, a PCM runtime instance is - allocated and assigned to the substream. This pointer is - accessible via substream->runtime. - This runtime pointer holds most information you need - to control the PCM: the copy of hw_params and sw_params configurations, the buffer - pointers, mmap records, spinlocks, etc. - - - - The definition of runtime instance is found in - <sound/pcm.h>. Here are - the contents of this file: - - - - - - - - - For the operators (callbacks) of each sound driver, most of - these records are supposed to be read-only. Only the PCM - middle-layer changes / updates them. The exceptions are - the hardware description (hw), interrupt callbacks - (transfer_ack_xxx), DMA buffer information, and the private - data. Besides, if you use the standard buffer allocation - method via snd_pcm_lib_malloc_pages(), - you don't need to set the DMA buffer information by yourself. - - - - In the sections below, important records are explained. - - -
- Hardware Description - - The hardware descriptor (struct snd_pcm_hardware) - contains the definitions of the fundamental hardware - configuration. Above all, you'll need to define this in - - the open callback. - Note that the runtime instance holds the copy of the - descriptor, not the pointer to the existing descriptor. That - is, in the open callback, you can modify the copied descriptor - (runtime->hw) as you need. For example, if the maximum - number of channels is 1 only on some chip models, you can - still use the same hardware descriptor and change the - channels_max later: - - -runtime; - ... - runtime->hw = snd_mychip_playback_hw; /* common definition */ - if (chip->model == VERY_OLD_ONE) - runtime->hw.channels_max = 1; -]]> - - - - - - Typically, you'll have a hardware descriptor as below: - - - - - - - - - - - The info field contains the type and - capabilities of this pcm. The bit flags are defined in - <sound/asound.h> as - SNDRV_PCM_INFO_XXX. Here, at least, you - have to specify whether the mmap is supported and which - interleaved format is supported. - When the is supported, add the - SNDRV_PCM_INFO_MMAP flag here. When the - hardware supports the interleaved or the non-interleaved - formats, SNDRV_PCM_INFO_INTERLEAVED or - SNDRV_PCM_INFO_NONINTERLEAVED flag must - be set, respectively. If both are supported, you can set both, - too. - - - - In the above example, MMAP_VALID and - BLOCK_TRANSFER are specified for the OSS mmap - mode. Usually both are set. Of course, - MMAP_VALID is set only if the mmap is - really supported. - - - - The other possible flags are - SNDRV_PCM_INFO_PAUSE and - SNDRV_PCM_INFO_RESUME. The - PAUSE bit means that the pcm supports the - pause operation, while the - RESUME bit means that the pcm supports - the full suspend/resume operation. - If the PAUSE flag is set, - the trigger callback below - must handle the corresponding (pause push/release) commands. - The suspend/resume trigger commands can be defined even without - the RESUME flag. See - Power Management section for details. - - - - When the PCM substreams can be synchronized (typically, - synchronized start/stop of a playback and a capture streams), - you can give SNDRV_PCM_INFO_SYNC_START, - too. In this case, you'll need to check the linked-list of - PCM substreams in the trigger callback. This will be - described in the later section. - - - - - - formats field contains the bit-flags - of supported formats (SNDRV_PCM_FMTBIT_XXX). - If the hardware supports more than one format, give all or'ed - bits. In the example above, the signed 16bit little-endian - format is specified. - - - - - - rates field contains the bit-flags of - supported rates (SNDRV_PCM_RATE_XXX). - When the chip supports continuous rates, pass - CONTINUOUS bit additionally. - The pre-defined rate bits are provided only for typical - rates. If your chip supports unconventional rates, you need to add - the KNOT bit and set up the hardware - constraint manually (explained later). - - - - - - rate_min and - rate_max define the minimum and - maximum sample rate. This should correspond somehow to - rates bits. - - - - - - channel_min and - channel_max - define, as you might already expected, the minimum and maximum - number of channels. - - - - - - buffer_bytes_max defines the - maximum buffer size in bytes. There is no - buffer_bytes_min field, since - it can be calculated from the minimum period size and the - minimum number of periods. - Meanwhile, period_bytes_min and - define the minimum and maximum size of the period in bytes. - periods_max and - periods_min define the maximum and - minimum number of periods in the buffer. - - - - The period is a term that corresponds to - a fragment in the OSS world. The period defines the size at - which a PCM interrupt is generated. This size strongly - depends on the hardware. - Generally, the smaller period size will give you more - interrupts, that is, more controls. - In the case of capture, this size defines the input latency. - On the other hand, the whole buffer size defines the - output latency for the playback direction. - - - - - - There is also a field fifo_size. - This specifies the size of the hardware FIFO, but currently it - is neither used in the driver nor in the alsa-lib. So, you - can ignore this field. - - - - -
- -
- PCM Configurations - - Ok, let's go back again to the PCM runtime records. - The most frequently referred records in the runtime instance are - the PCM configurations. - The PCM configurations are stored in the runtime instance - after the application sends hw_params data via - alsa-lib. There are many fields copied from hw_params and - sw_params structs. For example, - format holds the format type - chosen by the application. This field contains the enum value - SNDRV_PCM_FORMAT_XXX. - - - - One thing to be noted is that the configured buffer and period - sizes are stored in frames in the runtime. - In the ALSA world, 1 frame = channels * samples-size. - For conversion between frames and bytes, you can use the - frames_to_bytes() and - bytes_to_frames() helper functions. - - -period_size); -]]> - - - - - - Also, many software parameters (sw_params) are - stored in frames, too. Please check the type of the field. - snd_pcm_uframes_t is for the frames as unsigned - integer while snd_pcm_sframes_t is for the frames - as signed integer. - -
- -
- DMA Buffer Information - - The DMA buffer is defined by the following four fields, - dma_area, - dma_addr, - dma_bytes and - dma_private. - The dma_area holds the buffer - pointer (the logical address). You can call - memcpy from/to - this pointer. Meanwhile, dma_addr - holds the physical address of the buffer. This field is - specified only when the buffer is a linear buffer. - dma_bytes holds the size of buffer - in bytes. dma_private is used for - the ALSA DMA allocator. - - - - If you use a standard ALSA function, - snd_pcm_lib_malloc_pages(), for - allocating the buffer, these fields are set by the ALSA middle - layer, and you should not change them by - yourself. You can read them but not write them. - On the other hand, if you want to allocate the buffer by - yourself, you'll need to manage it in hw_params callback. - At least, dma_bytes is mandatory. - dma_area is necessary when the - buffer is mmapped. If your driver doesn't support mmap, this - field is not necessary. dma_addr - is also optional. You can use - dma_private as you like, too. - -
- -
- Running Status - - The running status can be referred via runtime->status. - This is the pointer to the struct snd_pcm_mmap_status - record. For example, you can get the current DMA hardware - pointer via runtime->status->hw_ptr. - - - - The DMA application pointer can be referred via - runtime->control, which points to the - struct snd_pcm_mmap_control record. - However, accessing directly to this value is not recommended. - -
- -
- Private Data - - You can allocate a record for the substream and store it in - runtime->private_data. Usually, this - is done in - - the open callback. - Don't mix this with pcm->private_data. - The pcm->private_data usually points to the - chip instance assigned statically at the creation of PCM, while the - runtime->private_data points to a dynamic - data structure created at the PCM open callback. - - - -runtime->private_data = data; - .... - } -]]> - - - - - - The allocated object must be released in - - the close callback. - -
- -
- Interrupt Callbacks - - The field transfer_ack_begin and - transfer_ack_end are called at - the beginning and at the end of - snd_pcm_period_elapsed(), respectively. - -
- -
- -
- Operators - - OK, now let me give details about each pcm callback - (ops). In general, every callback must - return 0 if successful, or a negative error number - such as -EINVAL. To choose an appropriate - error number, it is advised to check what value other parts of - the kernel return when the same kind of request fails. - - - - The callback function takes at least the argument with - snd_pcm_substream pointer. To retrieve - the chip record from the given substream instance, you can use the - following macro. - - - - - - - - The macro reads substream->private_data, - which is a copy of pcm->private_data. - You can override the former if you need to assign different data - records per PCM substream. For example, the cmi8330 driver assigns - different private_data for playback and capture directions, - because it uses two different codecs (SB- and AD-compatible) for - different directions. - - -
- open callback - - - - - - - - This is called when a pcm substream is opened. - - - - At least, here you have to initialize the runtime->hw - record. Typically, this is done by like this: - - - -runtime; - - runtime->hw = snd_mychip_playback_hw; - return 0; - } -]]> - - - - where snd_mychip_playback_hw is the - pre-defined hardware description. - - - - You can allocate a private data in this callback, as described - in - Private Data section. - - - - If the hardware configuration needs more constraints, set the - hardware constraints here, too. - See - Constraints for more details. - -
- -
- close callback - - - - - - - - Obviously, this is called when a pcm substream is closed. - - - - Any private instance for a pcm substream allocated in the - open callback will be released here. - - - -runtime->private_data); - .... - } -]]> - - - -
- -
- ioctl callback - - This is used for any special call to pcm ioctls. But - usually you can pass a generic ioctl callback, - snd_pcm_lib_ioctl. - -
- -
- hw_params callback - - - - - - - - - - This is called when the hardware parameter - (hw_params) is set - up by the application, - that is, once when the buffer size, the period size, the - format, etc. are defined for the pcm substream. - - - - Many hardware setups should be done in this callback, - including the allocation of buffers. - - - - Parameters to be initialized are retrieved by - params_xxx() macros. To allocate - buffer, you can call a helper function, - - - - - - - - snd_pcm_lib_malloc_pages() is available - only when the DMA buffers have been pre-allocated. - See the section - Buffer Types for more details. - - - - Note that this and prepare callbacks - may be called multiple times per initialization. - For example, the OSS emulation may - call these callbacks at each change via its ioctl. - - - - Thus, you need to be careful not to allocate the same buffers - many times, which will lead to memory leaks! Calling the - helper function above many times is OK. It will release the - previous buffer automatically when it was already allocated. - - - - Another note is that this callback is non-atomic - (schedulable). This is important, because the - trigger callback - is atomic (non-schedulable). That is, mutexes or any - schedule-related functions are not available in - trigger callback. - Please see the subsection - - Atomicity for details. - -
- -
- hw_free callback - - - - - - - - - - This is called to release the resources allocated via - hw_params. For example, releasing the - buffer via - snd_pcm_lib_malloc_pages() is done by - calling the following: - - - - - - - - - - This function is always called before the close callback is called. - Also, the callback may be called multiple times, too. - Keep track whether the resource was already released. - -
- -
- prepare callback - - - - - - - - - - This callback is called when the pcm is - prepared. You can set the format type, sample - rate, etc. here. The difference from - hw_params is that the - prepare callback will be called each - time - snd_pcm_prepare() is called, i.e. when - recovering after underruns, etc. - - - - Note that this callback is now non-atomic. - You can use schedule-related functions safely in this callback. - - - - In this and the following callbacks, you can refer to the - values via the runtime record, - substream->runtime. - For example, to get the current - rate, format or channels, access to - runtime->rate, - runtime->format or - runtime->channels, respectively. - The physical address of the allocated buffer is set to - runtime->dma_area. The buffer and period sizes are - in runtime->buffer_size and runtime->period_size, - respectively. - - - - Be careful that this callback will be called many times at - each setup, too. - -
- -
- trigger callback - - - - - - - - This is called when the pcm is started, stopped or paused. - - - - Which action is specified in the second argument, - SNDRV_PCM_TRIGGER_XXX in - <sound/pcm.h>. At least, - the START and STOP - commands must be defined in this callback. - - - - - - - - - - When the pcm supports the pause operation (given in the info - field of the hardware table), the PAUSE_PUSE - and PAUSE_RELEASE commands must be - handled here, too. The former is the command to pause the pcm, - and the latter to restart the pcm again. - - - - When the pcm supports the suspend/resume operation, - regardless of full or partial suspend/resume support, - the SUSPEND and RESUME - commands must be handled, too. - These commands are issued when the power-management status is - changed. Obviously, the SUSPEND and - RESUME commands - suspend and resume the pcm substream, and usually, they - are identical to the STOP and - START commands, respectively. - See the - Power Management section for details. - - - - As mentioned, this callback is atomic. You cannot call - functions which may sleep. - The trigger callback should be as minimal as possible, - just really triggering the DMA. The other stuff should be - initialized hw_params and prepare callbacks properly - beforehand. - -
- -
- pointer callback - - - - - - - - This callback is called when the PCM middle layer inquires - the current hardware position on the buffer. The position must - be returned in frames, - ranging from 0 to buffer_size - 1. - - - - This is called usually from the buffer-update routine in the - pcm middle layer, which is invoked when - snd_pcm_period_elapsed() is called in the - interrupt routine. Then the pcm middle layer updates the - position and calculates the available space, and wakes up the - sleeping poll threads, etc. - - - - This callback is also atomic. - -
- -
- copy and silence callbacks - - These callbacks are not mandatory, and can be omitted in - most cases. These callbacks are used when the hardware buffer - cannot be in the normal memory space. Some chips have their - own buffer on the hardware which is not mappable. In such a - case, you have to transfer the data manually from the memory - buffer to the hardware buffer. Or, if the buffer is - non-contiguous on both physical and virtual memory spaces, - these callbacks must be defined, too. - - - - If these two callbacks are defined, copy and set-silence - operations are done by them. The detailed will be described in - the later section Buffer and Memory - Management. - -
- -
- ack callback - - This callback is also not mandatory. This callback is called - when the appl_ptr is updated in read or write operations. - Some drivers like emu10k1-fx and cs46xx need to track the - current appl_ptr for the internal buffer, and this callback - is useful only for such a purpose. - - - This callback is atomic. - -
- -
- page callback - - - This callback is optional too. This callback is used - mainly for non-contiguous buffers. The mmap calls this - callback to get the page address. Some examples will be - explained in the later section Buffer and Memory - Management, too. - -
-
- -
- Interrupt Handler - - The rest of pcm stuff is the PCM interrupt handler. The - role of PCM interrupt handler in the sound driver is to update - the buffer position and to tell the PCM middle layer when the - buffer position goes across the prescribed period size. To - inform this, call the snd_pcm_period_elapsed() - function. - - - - There are several types of sound chips to generate the interrupts. - - -
- Interrupts at the period (fragment) boundary - - This is the most frequently found type: the hardware - generates an interrupt at each period boundary. - In this case, you can call - snd_pcm_period_elapsed() at each - interrupt. - - - - snd_pcm_period_elapsed() takes the - substream pointer as its argument. Thus, you need to keep the - substream pointer accessible from the chip instance. For - example, define substream field in the chip record to hold the - current running substream pointer, and set the pointer value - at open callback (and reset at close callback). - - - - If you acquire a spinlock in the interrupt handler, and the - lock is used in other pcm callbacks, too, then you have to - release the lock before calling - snd_pcm_period_elapsed(), because - snd_pcm_period_elapsed() calls other pcm - callbacks inside. - - - - Typical code would be like: - - - Interrupt Handler Case #1 - -lock); - .... - if (pcm_irq_invoked(chip)) { - /* call updater, unlock before it */ - spin_unlock(&chip->lock); - snd_pcm_period_elapsed(chip->substream); - spin_lock(&chip->lock); - /* acknowledge the interrupt if necessary */ - } - .... - spin_unlock(&chip->lock); - return IRQ_HANDLED; - } -]]> - - - -
- -
- High frequency timer interrupts - - This happense when the hardware doesn't generate interrupts - at the period boundary but issues timer interrupts at a fixed - timer rate (e.g. es1968 or ymfpci drivers). - In this case, you need to check the current hardware - position and accumulate the processed sample length at each - interrupt. When the accumulated size exceeds the period - size, call - snd_pcm_period_elapsed() and reset the - accumulator. - - - - Typical code would be like the following. - - - Interrupt Handler Case #2 - -lock); - .... - if (pcm_irq_invoked(chip)) { - unsigned int last_ptr, size; - /* get the current hardware pointer (in frames) */ - last_ptr = get_hw_ptr(chip); - /* calculate the processed frames since the - * last update - */ - if (last_ptr < chip->last_ptr) - size = runtime->buffer_size + last_ptr - - chip->last_ptr; - else - size = last_ptr - chip->last_ptr; - /* remember the last updated point */ - chip->last_ptr = last_ptr; - /* accumulate the size */ - chip->size += size; - /* over the period boundary? */ - if (chip->size >= runtime->period_size) { - /* reset the accumulator */ - chip->size %= runtime->period_size; - /* call updater */ - spin_unlock(&chip->lock); - snd_pcm_period_elapsed(substream); - spin_lock(&chip->lock); - } - /* acknowledge the interrupt if necessary */ - } - .... - spin_unlock(&chip->lock); - return IRQ_HANDLED; - } -]]> - - - -
- -
- On calling <function>snd_pcm_period_elapsed()</function> - - In both cases, even if more than one period are elapsed, you - don't have to call - snd_pcm_period_elapsed() many times. Call - only once. And the pcm layer will check the current hardware - pointer and update to the latest status. - -
-
- -
- Atomicity - - One of the most important (and thus difficult to debug) problems - in kernel programming are race conditions. - In the Linux kernel, they are usually avoided via spin-locks, mutexes - or semaphores. In general, if a race condition can happen - in an interrupt handler, it has to be managed atomically, and you - have to use a spinlock to protect the critical session. If the - critical section is not in interrupt handler code and - if taking a relatively long time to execute is acceptable, you - should use mutexes or semaphores instead. - - - - As already seen, some pcm callbacks are atomic and some are - not. For example, the hw_params callback is - non-atomic, while trigger callback is - atomic. This means, the latter is called already in a spinlock - held by the PCM middle layer. Please take this atomicity into - account when you choose a locking scheme in the callbacks. - - - - In the atomic callbacks, you cannot use functions which may call - schedule or go to - sleep. Semaphores and mutexes can sleep, - and hence they cannot be used inside the atomic callbacks - (e.g. trigger callback). - To implement some delay in such a callback, please use - udelay() or mdelay(). - - - - All three atomic callbacks (trigger, pointer, and ack) are - called with local interrupts disabled. - - -
-
- Constraints - - If your chip supports unconventional sample rates, or only the - limited samples, you need to set a constraint for the - condition. - - - - For example, in order to restrict the sample rates in the some - supported values, use - snd_pcm_hw_constraint_list(). - You need to call this function in the open callback. - - - Example of Hardware Constraints - -runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_rates); - if (err < 0) - return err; - .... - } -]]> - - - - - - There are many different constraints. - Look at sound/pcm.h for a complete list. - You can even define your own constraint rules. - For example, let's suppose my_chip can manage a substream of 1 channel - if and only if the format is S16_LE, otherwise it supports any format - specified in the snd_pcm_hardware structure (or in any - other constraint_list). You can build a rule like this: - - - Example of Hardware Constraints for Channels - -min < 2) { - fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE; - return snd_mask_refine(f, &fmt); - } - return 0; - } -]]> - - - - - - Then you need to call this function to add your rule: - - - -runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - hw_rule_channels_by_format, 0, SNDRV_PCM_HW_PARAM_FORMAT, - -1); -]]> - - - - - - The rule function is called when an application sets the number of - channels. But an application can set the format before the number of - channels. Thus you also need to define the inverse rule: - - - Example of Hardware Constraints for Channels - -bits[0] == SNDRV_PCM_FMTBIT_S16_LE) { - ch.min = ch.max = 1; - ch.integer = 1; - return snd_interval_refine(c, &ch); - } - return 0; - } -]]> - - - - - - ...and in the open callback: - - -runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, - hw_rule_format_by_channels, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - -1); -]]> - - - - - - I won't give more details here, rather I - would like to say, Luke, use the source. - -
- -
- - - - - - - Control Interface - -
- General - - The control interface is used widely for many switches, - sliders, etc. which are accessed from user-space. Its most - important use is the mixer interface. In other words, since ALSA - 0.9.x, all the mixer stuff is implemented on the control kernel API. - - - - ALSA has a well-defined AC97 control module. If your chip - supports only the AC97 and nothing else, you can skip this - section. - - - - The control API is defined in - <sound/control.h>. - Include this file if you want to add your own controls. - -
- -
- Definition of Controls - - To create a new control, you need to define the - following three - callbacks: info, - get and - put. Then, define a - struct snd_kcontrol_new record, such as: - - - Definition of a Control - - - - - - - - Most likely the control is created via - snd_ctl_new1(), and in such a case, you can - add the __devinitdata prefix to the - definition as above. - - - - The iface field specifies the control - type, SNDRV_CTL_ELEM_IFACE_XXX, which - is usually MIXER. - Use CARD for global controls that are not - logically part of the mixer. - If the control is closely associated with some specific device on - the sound card, use HWDEP, - PCM, RAWMIDI, - TIMER, or SEQUENCER, and - specify the device number with the - device and - subdevice fields. - - - - The name is the name identifier - string. Since ALSA 0.9.x, the control name is very important, - because its role is classified from its name. There are - pre-defined standard control names. The details are described in - the - Control Names subsection. - - - - The index field holds the index number - of this control. If there are several different controls with - the same name, they can be distinguished by the index - number. This is the case when - several codecs exist on the card. If the index is zero, you can - omit the definition above. - - - - The access field contains the access - type of this control. Give the combination of bit masks, - SNDRV_CTL_ELEM_ACCESS_XXX, there. - The details will be explained in - the - Access Flags subsection. - - - - The private_value field contains - an arbitrary long integer value for this record. When using - the generic info, - get and - put callbacks, you can pass a value - through this field. If several small numbers are necessary, you can - combine them in bitwise. Or, it's possible to give a pointer - (casted to unsigned long) of some record to this field, too. - - - - The tlv field can be used to provide - metadata about the control; see the - - Metadata subsection. - - - - The other three are - - callback functions. - -
- -
- Control Names - - There are some standards to define the control names. A - control is usually defined from the three parts as - SOURCE DIRECTION FUNCTION. - - - - The first, SOURCE, specifies the source - of the control, and is a string such as Master, - PCM, CD and - Line. There are many pre-defined sources. - - - - The second, DIRECTION, is one of the - following strings according to the direction of the control: - Playback, Capture, Bypass - Playback and Bypass Capture. Or, it can - be omitted, meaning both playback and capture directions. - - - - The third, FUNCTION, is one of the - following strings according to the function of the control: - Switch, Volume and - Route. - - - - The example of control names are, thus, Master Capture - Switch or PCM Playback Volume. - - - - There are some exceptions: - - -
- Global capture and playback - - Capture Source, Capture Switch - and Capture Volume are used for the global - capture (input) source, switch and volume. Similarly, - Playback Switch and Playback - Volume are used for the global output gain switch and - volume. - -
- -
- Tone-controls - - tone-control switch and volumes are specified like - Tone Control - XXX, e.g. Tone Control - - Switch, Tone Control - Bass, - Tone Control - Center. - -
- -
- 3D controls - - 3D-control switches and volumes are specified like 3D - Control - XXX, e.g. 3D Control - - Switch, 3D Control - Center, 3D - Control - Space. - -
- -
- Mic boost - - Mic-boost switch is set as Mic Boost or - Mic Boost (6dB). - - - - More precise information can be found in - Documentation/sound/alsa/ControlNames.txt. - -
-
- -
- Access Flags - - - The access flag is the bitmask which specifies the access type - of the given control. The default access type is - SNDRV_CTL_ELEM_ACCESS_READWRITE, - which means both read and write are allowed to this control. - When the access flag is omitted (i.e. = 0), it is - considered as READWRITE access as default. - - - - When the control is read-only, pass - SNDRV_CTL_ELEM_ACCESS_READ instead. - In this case, you don't have to define - the put callback. - Similarly, when the control is write-only (although it's a rare - case), you can use the WRITE flag instead, and - you don't need the get callback. - - - - If the control value changes frequently (e.g. the VU meter), - VOLATILE flag should be given. This means - that the control may be changed without - - notification. Applications should poll such - a control constantly. - - - - When the control is inactive, set - the INACTIVE flag, too. - There are LOCK and - OWNER flags to change the write - permissions. - - -
- -
- Callbacks - -
- info callback - - The info callback is used to get - detailed information on this control. This must store the - values of the given struct snd_ctl_elem_info - object. For example, for a boolean control with a single - element: - - - Example of info callback - -type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; - } -]]> - - - - - - The type field specifies the type - of the control. There are BOOLEAN, - INTEGER, ENUMERATED, - BYTES, IEC958 and - INTEGER64. The - count field specifies the - number of elements in this control. For example, a stereo - volume would have count = 2. The - value field is a union, and - the values stored are depending on the type. The boolean and - integer types are identical. - - - - The enumerated type is a bit different from others. You'll - need to set the string for the currently given item index. - - - -type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; - } -]]> - - - - - - Some common info callbacks are available for your convenience: - snd_ctl_boolean_mono_info() and - snd_ctl_boolean_stereo_info(). - Obviously, the former is an info callback for a mono channel - boolean item, just like snd_myctl_mono_info - above, and the latter is for a stereo channel boolean item. - - -
- -
- get callback - - - This callback is used to read the current value of the - control and to return to user-space. - - - - For example, - - - Example of get callback - -value.integer.value[0] = get_some_value(chip); - return 0; - } -]]> - - - - - - The value field depends on - the type of control as well as on the info callback. For example, - the sb driver uses this field to store the register offset, - the bit-shift and the bit-mask. The - private_value field is set as follows: - - - - - - and is retrieved in callbacks like - - -private_value & 0xff; - int shift = (kcontrol->private_value >> 16) & 0xff; - int mask = (kcontrol->private_value >> 24) & 0xff; - .... - } -]]> - - - - - - In the get callback, - you have to fill all the elements if the - control has more than one elements, - i.e. count > 1. - In the example above, we filled only one element - (value.integer.value[0]) since it's - assumed as count = 1. - -
- -
- put callback - - - This callback is used to write a value from user-space. - - - - For example, - - - Example of put callback - -current_value != - ucontrol->value.integer.value[0]) { - change_current_value(chip, - ucontrol->value.integer.value[0]); - changed = 1; - } - return changed; - } -]]> - - - - As seen above, you have to return 1 if the value is - changed. If the value is not changed, return 0 instead. - If any fatal error happens, return a negative error code as - usual. - - - - As in the get callback, - when the control has more than one elements, - all elements must be evaluated in this callback, too. - -
- -
- Callbacks are not atomic - - All these three callbacks are basically not atomic. - -
-
- -
- Constructor - - When everything is ready, finally we can create a new - control. To create a control, there are two functions to be - called, snd_ctl_new1() and - snd_ctl_add(). - - - - In the simplest way, you can do like this: - - - - - - - - where my_control is the - struct snd_kcontrol_new object defined above, and chip - is the object pointer to be passed to - kcontrol->private_data - which can be referred to in callbacks. - - - - snd_ctl_new1() allocates a new - snd_kcontrol instance (that's why the definition - of my_control can be with - the __devinitdata - prefix), and snd_ctl_add assigns the given - control component to the card. - -
- -
- Change Notification - - If you need to change and update a control in the interrupt - routine, you can call snd_ctl_notify(). For - example, - - - - - - - - This function takes the card pointer, the event-mask, and the - control id pointer for the notification. The event-mask - specifies the types of notification, for example, in the above - example, the change of control values is notified. - The id pointer is the pointer of struct snd_ctl_elem_id - to be notified. - You can find some examples in es1938.c or - es1968.c for hardware volume interrupts. - -
- -
- Metadata - - To provide information about the dB values of a mixer control, use - on of the DECLARE_TLV_xxx macros from - <sound/tlv.h> to define a variable - containing this information, set thetlv.p - field to point to this variable, and include the - SNDRV_CTL_ELEM_ACCESS_TLV_READ flag in the - access field; like this: - - - - - - - - - The DECLARE_TLV_DB_SCALE macro defines - information about a mixer control where each step in the control's - value changes the dB value by a constant dB amount. - The first parameter is the name of the variable to be defined. - The second parameter is the minimum value, in units of 0.01 dB. - The third parameter is the step size, in units of 0.01 dB. - Set the fourth parameter to 1 if the minimum value actually mutes - the control. - - - - The DECLARE_TLV_DB_LINEAR macro defines - information about a mixer control where the control's value affects - the output linearly. - The first parameter is the name of the variable to be defined. - The second parameter is the minimum value, in units of 0.01 dB. - The third parameter is the maximum value, in units of 0.01 dB. - If the minimum value mutes the control, set the second parameter to - TLV_DB_GAIN_MUTE. - -
- -
- - - - - - - API for AC97 Codec - -
- General - - The ALSA AC97 codec layer is a well-defined one, and you don't - have to write much code to control it. Only low-level control - routines are necessary. The AC97 codec API is defined in - <sound/ac97_codec.h>. - -
- -
- Full Code Example - - - Example of AC97 Interface - -private_data; - .... - /* read a register value here from the codec */ - return the_register_value; - } - - static void snd_mychip_ac97_write(struct snd_ac97 *ac97, - unsigned short reg, unsigned short val) - { - struct mychip *chip = ac97->private_data; - .... - /* write the given register value to the codec */ - } - - static int snd_mychip_ac97(struct mychip *chip) - { - struct snd_ac97_bus *bus; - struct snd_ac97_template ac97; - int err; - static struct snd_ac97_bus_ops ops = { - .write = snd_mychip_ac97_write, - .read = snd_mychip_ac97_read, - }; - - err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus); - if (err < 0) - return err; - memset(&ac97, 0, sizeof(ac97)); - ac97.private_data = chip; - return snd_ac97_mixer(bus, &ac97, &chip->ac97); - } - -]]> - - - -
- -
- Constructor - - To create an ac97 instance, first call snd_ac97_bus - with an ac97_bus_ops_t record with callback functions. - - - - - - - - The bus record is shared among all belonging ac97 instances. - - - - And then call snd_ac97_mixer() with an - struct snd_ac97_template - record together with the bus pointer created above. - - - -ac97); -]]> - - - - where chip->ac97 is a pointer to a newly created - ac97_t instance. - In this case, the chip pointer is set as the private data, so that - the read/write callback functions can refer to this chip instance. - This instance is not necessarily stored in the chip - record. If you need to change the register values from the - driver, or need the suspend/resume of ac97 codecs, keep this - pointer to pass to the corresponding functions. - -
- -
- Callbacks - - The standard callbacks are read and - write. Obviously they - correspond to the functions for read and write accesses to the - hardware low-level codes. - - - - The read callback returns the - register value specified in the argument. - - - -private_data; - .... - return the_register_value; - } -]]> - - - - Here, the chip can be cast from ac97->private_data. - - - - Meanwhile, the write callback is - used to set the register value. - - - - - - - - - - These callbacks are non-atomic like the control API callbacks. - - - - There are also other callbacks: - reset, - wait and - init. - - - - The reset callback is used to reset - the codec. If the chip requires a special kind of reset, you can - define this callback. - - - - The wait callback is used to - add some waiting time in the standard initialization of the codec. If the - chip requires the extra waiting time, define this callback. - - - - The init callback is used for - additional initialization of the codec. - -
- -
- Updating Registers in The Driver - - If you need to access to the codec from the driver, you can - call the following functions: - snd_ac97_write(), - snd_ac97_read(), - snd_ac97_update() and - snd_ac97_update_bits(). - - - - Both snd_ac97_write() and - snd_ac97_update() functions are used to - set a value to the given register - (AC97_XXX). The difference between them is - that snd_ac97_update() doesn't write a - value if the given value has been already set, while - snd_ac97_write() always rewrites the - value. - - - - - - - - - - snd_ac97_read() is used to read the value - of the given register. For example, - - - - - - - - - - snd_ac97_update_bits() is used to update - some bits in the given register. - - - - - - - - - - Also, there is a function to change the sample rate (of a - given register such as - AC97_PCM_FRONT_DAC_RATE) when VRA or - DRA is supported by the codec: - snd_ac97_set_rate(). - - - - - - - - - - The following registers are available to set the rate: - AC97_PCM_MIC_ADC_RATE, - AC97_PCM_FRONT_DAC_RATE, - AC97_PCM_LR_ADC_RATE, - AC97_SPDIF. When - AC97_SPDIF is specified, the register is - not really changed but the corresponding IEC958 status bits will - be updated. - -
- -
- Clock Adjustment - - In some chips, the clock of the codec isn't 48000 but using a - PCI clock (to save a quartz!). In this case, change the field - bus->clock to the corresponding - value. For example, intel8x0 - and es1968 drivers have their own function to read from the clock. - -
- -
- Proc Files - - The ALSA AC97 interface will create a proc file such as - /proc/asound/card0/codec97#0/ac97#0-0 and - ac97#0-0+regs. You can refer to these files to - see the current status and registers of the codec. - -
- -
- Multiple Codecs - - When there are several codecs on the same card, you need to - call snd_ac97_mixer() multiple times with - ac97.num=1 or greater. The num field - specifies the codec number. - - - - If you set up multiple codecs, you either need to write - different callbacks for each codec or check - ac97->num in the callback routines. - -
- -
- - - - - - - MIDI (MPU401-UART) Interface - -
- General - - Many soundcards have built-in MIDI (MPU401-UART) - interfaces. When the soundcard supports the standard MPU401-UART - interface, most likely you can use the ALSA MPU401-UART API. The - MPU401-UART API is defined in - <sound/mpu401.h>. - - - - Some soundchips have a similar but slightly different - implementation of mpu401 stuff. For example, emu10k1 has its own - mpu401 routines. - -
- -
- Constructor - - To create a rawmidi object, call - snd_mpu401_uart_new(). - - - - - - - - - - The first argument is the card pointer, and the second is the - index of this component. You can create up to 8 rawmidi - devices. - - - - The third argument is the type of the hardware, - MPU401_HW_XXX. If it's not a special one, - you can use MPU401_HW_MPU401. - - - - The 4th argument is the I/O port address. Many - backward-compatible MPU401 have an I/O port such as 0x330. Or, it - might be a part of its own PCI I/O region. It depends on the - chip design. - - - - The 5th argument is a bitflag for additional information. - When the I/O port address above is part of the PCI I/O - region, the MPU401 I/O port might have been already allocated - (reserved) by the driver itself. In such a case, pass a bit flag - MPU401_INFO_INTEGRATED, - and the mpu401-uart layer will allocate the I/O ports by itself. - - - - When the controller supports only the input or output MIDI stream, - pass the MPU401_INFO_INPUT or - MPU401_INFO_OUTPUT bitflag, respectively. - Then the rawmidi instance is created as a single stream. - - - - MPU401_INFO_MMIO bitflag is used to change - the access method to MMIO (via readb and writeb) instead of - iob and outb. In this case, you have to pass the iomapped address - to snd_mpu401_uart_new(). - - - - When MPU401_INFO_TX_IRQ is set, the output - stream isn't checked in the default interrupt handler. The driver - needs to call snd_mpu401_uart_interrupt_tx() - by itself to start processing the output stream in the irq handler. - - - - Usually, the port address corresponds to the command port and - port + 1 corresponds to the data port. If not, you may change - the cport field of - struct snd_mpu401 manually - afterward. However, snd_mpu401 pointer is not - returned explicitly by - snd_mpu401_uart_new(). You need to cast - rmidi->private_data to - snd_mpu401 explicitly, - - - -private_data; -]]> - - - - and reset the cport as you like: - - - -cport = my_own_control_port; -]]> - - - - - - The 6th argument specifies the irq number for UART. If the irq - is already allocated, pass 0 to the 7th argument - (irq_flags). Otherwise, pass the flags - for irq allocation - (SA_XXX bits) to it, and the irq will be - reserved by the mpu401-uart layer. If the card doesn't generate - UART interrupts, pass -1 as the irq number. Then a timer - interrupt will be invoked for polling. - -
- -
- Interrupt Handler - - When the interrupt is allocated in - snd_mpu401_uart_new(), the private - interrupt handler is used, hence you don't have anything else to do - than creating the mpu401 stuff. Otherwise, you have to call - snd_mpu401_uart_interrupt() explicitly when - a UART interrupt is invoked and checked in your own interrupt - handler. - - - - In this case, you need to pass the private_data of the - returned rawmidi object from - snd_mpu401_uart_new() as the second - argument of snd_mpu401_uart_interrupt(). - - - -private_data, regs); -]]> - - - -
- -
- - - - - - - RawMIDI Interface - -
- Overview - - - The raw MIDI interface is used for hardware MIDI ports that can - be accessed as a byte stream. It is not used for synthesizer - chips that do not directly understand MIDI. - - - - ALSA handles file and buffer management. All you have to do is - to write some code to move data between the buffer and the - hardware. - - - - The rawmidi API is defined in - <sound/rawmidi.h>. - -
- -
- Constructor - - - To create a rawmidi device, call the - snd_rawmidi_new function: - - -card, "MyMIDI", 0, outs, ins, &rmidi); - if (err < 0) - return err; - rmidi->private_data = chip; - strcpy(rmidi->name, "My MIDI"); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; -]]> - - - - - - The first argument is the card pointer, the second argument is - the ID string. - - - - The third argument is the index of this component. You can - create up to 8 rawmidi devices. - - - - The fourth and fifth arguments are the number of output and - input substreams, respectively, of this device (a substream is - the equivalent of a MIDI port). - - - - Set the info_flags field to specify - the capabilities of the device. - Set SNDRV_RAWMIDI_INFO_OUTPUT if there is - at least one output port, - SNDRV_RAWMIDI_INFO_INPUT if there is at - least one input port, - and SNDRV_RAWMIDI_INFO_DUPLEX if the device - can handle output and input at the same time. - - - - After the rawmidi device is created, you need to set the - operators (callbacks) for each substream. There are helper - functions to set the operators for all the substreams of a device: - - - - - - - - - The operators are usually defined like this: - - - - - - These callbacks are explained in the Callbacks - section. - - - - If there are more than one substream, you should give a - unique name to each of them: - - -streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, - list { - sprintf(substream->name, "My MIDI Port %d", substream->number + 1); - } - /* same for SNDRV_RAWMIDI_STREAM_INPUT */ -]]> - - - -
- -
- Callbacks - - - In all the callbacks, the private data that you've set for the - rawmidi device can be accessed as - substream->rmidi->private_data. - - - - - If there is more than one port, your callbacks can determine the - port index from the struct snd_rawmidi_substream data passed to each - callback: - - -number; -]]> - - - - -
- <function>open</function> callback - - - - - - - - - This is called when a substream is opened. - You can initialize the hardware here, but you shouldn't - start transmitting/receiving data yet. - -
- -
- <function>close</function> callback - - - - - - - - - Guess what. - - - - The open and close - callbacks of a rawmidi device are serialized with a mutex, - and can sleep. - -
- -
- <function>trigger</function> callback for output - substreams - - - - - - - - - This is called with a nonzero up - parameter when there is some data in the substream buffer that - must be transmitted. - - - - To read data from the buffer, call - snd_rawmidi_transmit_peek. It will - return the number of bytes that have been read; this will be - less than the number of bytes requested when there are no more - data in the buffer. - After the data have been transmitted successfully, call - snd_rawmidi_transmit_ack to remove the - data from the substream buffer: - - - - - - - - - If you know beforehand that the hardware will accept data, you - can use the snd_rawmidi_transmit function - which reads some data and removes them from the buffer at once: - - - - - - - - - If you know beforehand how many bytes you can accept, you can - use a buffer size greater than one with the - snd_rawmidi_transmit* functions. - - - - The trigger callback must not sleep. If - the hardware FIFO is full before the substream buffer has been - emptied, you have to continue transmitting data later, either - in an interrupt handler, or with a timer if the hardware - doesn't have a MIDI transmit interrupt. - - - - The trigger callback is called with a - zero up parameter when the transmission - of data should be aborted. - -
- -
- <function>trigger</function> callback for input - substreams - - - - - - - - - This is called with a nonzero up - parameter to enable receiving data, or with a zero - up parameter do disable receiving data. - - - - The trigger callback must not sleep; the - actual reading of data from the device is usually done in an - interrupt handler. - - - - When data reception is enabled, your interrupt handler should - call snd_rawmidi_receive for all received - data: - - - - - - -
- -
- <function>drain</function> callback - - - - - - - - - This is only used with output substreams. This function should wait - until all data read from the substream buffer have been transmitted. - This ensures that the device can be closed and the driver unloaded - without losing data. - - - - This callback is optional. If you do not set - drain in the struct snd_rawmidi_ops - structure, ALSA will simply wait for 50 milliseconds - instead. - -
-
- -
- - - - - - - Miscellaneous Devices - -
- FM OPL3 - - The FM OPL3 is still used in many chips (mainly for backward - compatibility). ALSA has a nice OPL3 FM control layer, too. The - OPL3 API is defined in - <sound/opl3.h>. - - - - FM registers can be directly accessed through the direct-FM API, - defined in <sound/asound_fm.h>. In - ALSA native mode, FM registers are accessed through - the Hardware-Dependant Device direct-FM extension API, whereas in - OSS compatible mode, FM registers can be accessed with the OSS - direct-FM compatible API in /dev/dmfmX device. - - - - To create the OPL3 component, you have two functions to - call. The first one is a constructor for the opl3_t - instance. - - - - - - - - - - The first argument is the card pointer, the second one is the - left port address, and the third is the right port address. In - most cases, the right port is placed at the left port + 2. - - - - The fourth argument is the hardware type. - - - - When the left and right ports have been already allocated by - the card driver, pass non-zero to the fifth argument - (integrated). Otherwise, the opl3 module will - allocate the specified ports by itself. - - - - When the accessing the hardware requires special method - instead of the standard I/O access, you can create opl3 instance - separately with snd_opl3_new(). - - - - - - - - - - Then set command, - private_data and - private_free for the private - access function, the private data and the destructor. - The l_port and r_port are not necessarily set. Only the - command must be set properly. You can retrieve the data - from the opl3->private_data field. - - - - After creating the opl3 instance via snd_opl3_new(), - call snd_opl3_init() to initialize the chip to the - proper state. Note that snd_opl3_create() always - calls it internally. - - - - If the opl3 instance is created successfully, then create a - hwdep device for this opl3. - - - - - - - - - - The first argument is the opl3_t instance you - created, and the second is the index number, usually 0. - - - - The third argument is the index-offset for the sequencer - client assigned to the OPL3 port. When there is an MPU401-UART, - give 1 for here (UART always takes 0). - -
- -
- Hardware-Dependent Devices - - Some chips need user-space access for special - controls or for loading the micro code. In such a case, you can - create a hwdep (hardware-dependent) device. The hwdep API is - defined in <sound/hwdep.h>. You can - find examples in opl3 driver or - isa/sb/sb16_csp.c. - - - - The creation of the hwdep instance is done via - snd_hwdep_new(). - - - - - - - - where the third argument is the index number. - - - - You can then pass any pointer value to the - private_data. - If you assign a private data, you should define the - destructor, too. The destructor function is set in - the private_free field. - - - -private_data = p; - hw->private_free = mydata_free; -]]> - - - - and the implementation of the destructor would be: - - - -private_data; - kfree(p); - } -]]> - - - - - - The arbitrary file operations can be defined for this - instance. The file operators are defined in - the ops table. For example, assume that - this chip needs an ioctl. - - - -ops.open = mydata_open; - hw->ops.ioctl = mydata_ioctl; - hw->ops.release = mydata_release; -]]> - - - - And implement the callback functions as you like. - -
- -
- IEC958 (S/PDIF) - - Usually the controls for IEC958 devices are implemented via - the control interface. There is a macro to compose a name string for - IEC958 controls, SNDRV_CTL_NAME_IEC958() - defined in <include/asound.h>. - - - - There are some standard controls for IEC958 status bits. These - controls use the type SNDRV_CTL_ELEM_TYPE_IEC958, - and the size of element is fixed as 4 bytes array - (value.iec958.status[x]). For the info - callback, you don't specify - the value field for this type (the count field must be set, - though). - - - - IEC958 Playback Con Mask is used to return the - bit-mask for the IEC958 status bits of consumer mode. Similarly, - IEC958 Playback Pro Mask returns the bitmask for - professional mode. They are read-only controls, and are defined - as MIXER controls (iface = - SNDRV_CTL_ELEM_IFACE_MIXER). - - - - Meanwhile, IEC958 Playback Default control is - defined for getting and setting the current default IEC958 - bits. Note that this one is usually defined as a PCM control - (iface = SNDRV_CTL_ELEM_IFACE_PCM), - although in some places it's defined as a MIXER control. - - - - In addition, you can define the control switches to - enable/disable or to set the raw bit mode. The implementation - will depend on the chip, but the control should be named as - IEC958 xxx, preferably using - the SNDRV_CTL_NAME_IEC958() macro. - - - - You can find several cases, for example, - pci/emu10k1, - pci/ice1712, or - pci/cmipci.c. - -
- -
- - - - - - - Buffer and Memory Management - -
- Buffer Types - - ALSA provides several different buffer allocation functions - depending on the bus and the architecture. All these have a - consistent API. The allocation of physically-contiguous pages is - done via - snd_malloc_xxx_pages() function, where xxx - is the bus type. - - - - The allocation of pages with fallback is - snd_malloc_xxx_pages_fallback(). This - function tries to allocate the specified pages but if the pages - are not available, it tries to reduce the page sizes until - enough space is found. - - - - The release the pages, call - snd_free_xxx_pages() function. - - - - Usually, ALSA drivers try to allocate and reserve - a large contiguous physical space - at the time the module is loaded for the later use. - This is called pre-allocation. - As already written, you can call the following function at - pcm instance construction time (in the case of PCI bus). - - - - - - - - where size is the byte size to be - pre-allocated and the max is the maximum - size to be changed via the prealloc proc file. - The allocator will try to get an area as large as possible - within the given size. - - - - The second argument (type) and the third argument (device pointer) - are dependent on the bus. - In the case of the ISA bus, pass snd_dma_isa_data() - as the third argument with SNDRV_DMA_TYPE_DEV type. - For the continuous buffer unrelated to the bus can be pre-allocated - with SNDRV_DMA_TYPE_CONTINUOUS type and the - snd_dma_continuous_data(GFP_KERNEL) device pointer, - where GFP_KERNEL is the kernel allocation flag to - use. - For the PCI scatter-gather buffers, use - SNDRV_DMA_TYPE_DEV_SG with - snd_dma_pci_data(pci) - (see the - Non-Contiguous Buffers - section). - - - - Once the buffer is pre-allocated, you can use the - allocator in the hw_params callback: - - - - - - - - Note that you have to pre-allocate to use this function. - -
- -
- External Hardware Buffers - - Some chips have their own hardware buffers and the DMA - transfer from the host memory is not available. In such a case, - you need to either 1) copy/set the audio data directly to the - external hardware buffer, or 2) make an intermediate buffer and - copy/set the data from it to the external hardware buffer in - interrupts (or in tasklets, preferably). - - - - The first case works fine if the external hardware buffer is large - enough. This method doesn't need any extra buffers and thus is - more effective. You need to define the - copy and - silence callbacks for - the data transfer. However, there is a drawback: it cannot - be mmapped. The examples are GUS's GF1 PCM or emu8000's - wavetable PCM. - - - - The second case allows for mmap on the buffer, although you have - to handle an interrupt or a tasklet to transfer the data - from the intermediate buffer to the hardware buffer. You can find an - example in the vxpocket driver. - - - - Another case is when the chip uses a PCI memory-map - region for the buffer instead of the host memory. In this case, - mmap is available only on certain architectures like the Intel one. - In non-mmap mode, the data cannot be transferred as in the normal - way. Thus you need to define the copy and - silence callbacks as well, - as in the cases above. The examples are found in - rme32.c and rme96.c. - - - - The implementation of the copy and - silence callbacks depends upon - whether the hardware supports interleaved or non-interleaved - samples. The copy callback is - defined like below, a bit - differently depending whether the direction is playback or - capture: - - - - - - - - - - In the case of interleaved samples, the second argument - (channel) is not used. The third argument - (pos) points the - current position offset in frames. - - - - The meaning of the fourth argument is different between - playback and capture. For playback, it holds the source data - pointer, and for capture, it's the destination data pointer. - - - - The last argument is the number of frames to be copied. - - - - What you have to do in this callback is again different - between playback and capture directions. In the - playback case, you copy the given amount of data - (count) at the specified pointer - (src) to the specified offset - (pos) on the hardware buffer. When - coded like memcpy-like way, the copy would be like: - - - - - - - - - - For the capture direction, you copy the given amount of - data (count) at the specified offset - (pos) on the hardware buffer to the - specified pointer (dst). - - - - - - - - Note that both the position and the amount of data are given - in frames. - - - - In the case of non-interleaved samples, the implementation - will be a bit more complicated. - - - - You need to check the channel argument, and if it's -1, copy - the whole channels. Otherwise, you have to copy only the - specified channel. Please check - isa/gus/gus_pcm.c as an example. - - - - The silence callback is also - implemented in a similar way. - - - - - - - - - - The meanings of arguments are the same as in the - copy - callback, although there is no src/dst - argument. In the case of interleaved samples, the channel - argument has no meaning, as well as on - copy callback. - - - - The role of silence callback is to - set the given amount - (count) of silence data at the - specified offset (pos) on the hardware - buffer. Suppose that the data format is signed (that is, the - silent-data is 0), and the implementation using a memset-like - function would be like: - - - - - - - - - - In the case of non-interleaved samples, again, the - implementation becomes a bit more complicated. See, for example, - isa/gus/gus_pcm.c. - -
- -
- Non-Contiguous Buffers - - If your hardware supports the page table as in emu10k1 or the - buffer descriptors as in via82xx, you can use the scatter-gather - (SG) DMA. ALSA provides an interface for handling SG-buffers. - The API is provided in <sound/pcm.h>. - - - - For creating the SG-buffer handler, call - snd_pcm_lib_preallocate_pages() or - snd_pcm_lib_preallocate_pages_for_all() - with SNDRV_DMA_TYPE_DEV_SG - in the PCM constructor like other PCI pre-allocator. - You need to pass snd_dma_pci_data(pci), - where pci is the struct pci_dev pointer - of the chip as well. - The struct snd_sg_buf instance is created as - substream->dma_private. You can cast - the pointer like: - - - -dma_private; -]]> - - - - - - Then call snd_pcm_lib_malloc_pages() - in the hw_params callback - as well as in the case of normal PCI buffer. - The SG-buffer handler will allocate the non-contiguous kernel - pages of the given size and map them onto the virtually contiguous - memory. The virtual pointer is addressed in runtime->dma_area. - The physical address (runtime->dma_addr) is set to zero, - because the buffer is physically non-contigous. - The physical address table is set up in sgbuf->table. - You can get the physical address at a certain offset via - snd_pcm_sgbuf_get_addr(). - - - - When a SG-handler is used, you need to set - snd_pcm_sgbuf_ops_page as - the page callback. - (See - page callback section.) - - - - To release the data, call - snd_pcm_lib_free_pages() in the - hw_free callback as usual. - -
- -
- Vmalloc'ed Buffers - - It's possible to use a buffer allocated via - vmalloc, for example, for an intermediate - buffer. Since the allocated pages are not contiguous, you need - to set the page callback to obtain - the physical address at every offset. - - - - The implementation of page callback - would be like this: - - - - - - /* get the physical page pointer on the given offset */ - static struct page *mychip_page(struct snd_pcm_substream *substream, - unsigned long offset) - { - void *pageptr = substream->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); - } -]]> - - - -
- -
- - - - - - - Proc Interface - - ALSA provides an easy interface for procfs. The proc files are - very useful for debugging. I recommend you set up proc files if - you write a driver and want to get a running status or register - dumps. The API is found in - <sound/info.h>. - - - - To create a proc file, call - snd_card_proc_new(). - - - - - - - - where the second argument specifies the name of the proc file to be - created. The above example will create a file - my-file under the card directory, - e.g. /proc/asound/card0/my-file. - - - - Like other components, the proc entry created via - snd_card_proc_new() will be registered and - released automatically in the card registration and release - functions. - - - - When the creation is successful, the function stores a new - instance in the pointer given in the third argument. - It is initialized as a text proc file for read only. To use - this proc file as a read-only text file as it is, set the read - callback with a private data via - snd_info_set_text_ops(). - - - - - - - - where the second argument (chip) is the - private data to be used in the callbacks. The third parameter - specifies the read buffer size and the fourth - (my_proc_read) is the callback function, which - is defined like - - - - - - - - - - - In the read callback, use snd_iprintf() for - output strings, which works just like normal - printf(). For example, - - - -private_data; - - snd_iprintf(buffer, "This is my chip!\n"); - snd_iprintf(buffer, "Port = %ld\n", chip->port); - } -]]> - - - - - - The file permissions can be changed afterwards. As default, it's - set as read only for all users. If you want to add write - permission for the user (root as default), do as follows: - - - -mode = S_IFREG | S_IRUGO | S_IWUSR; -]]> - - - - and set the write buffer size and the callback - - - -c.text.write = my_proc_write; -]]> - - - - - - For the write callback, you can use - snd_info_get_line() to get a text line, and - snd_info_get_str() to retrieve a string from - the line. Some examples are found in - core/oss/mixer_oss.c, core/oss/and - pcm_oss.c. - - - - For a raw-data proc-file, set the attributes as follows: - - - -content = SNDRV_INFO_CONTENT_DATA; - entry->private_data = chip; - entry->c.ops = &my_file_io_ops; - entry->size = 4096; - entry->mode = S_IFREG | S_IRUGO; -]]> - - - - - - The callback is much more complicated than the text-file - version. You need to use a low-level I/O functions such as - copy_from/to_user() to transfer the - data. - - - - local_max_size) - size = local_max_size - pos; - if (copy_to_user(buf, local_data + pos, size)) - return -EFAULT; - return size; - } -]]> - - - - - - - - - - - - Power Management - - If the chip is supposed to work with suspend/resume - functions, you need to add power-management code to the - driver. The additional code for power-management should be - ifdef'ed with - CONFIG_PM. - - - - If the driver fully supports suspend/resume - that is, the device can be - properly resumed to its state when suspend was called, - you can set the SNDRV_PCM_INFO_RESUME flag - in the pcm info field. Usually, this is possible when the - registers of the chip can be safely saved and restored to - RAM. If this is set, the trigger callback is called with - SNDRV_PCM_TRIGGER_RESUME after the resume - callback completes. - - - - Even if the driver doesn't support PM fully but - partial suspend/resume is still possible, it's still worthy to - implement suspend/resume callbacks. In such a case, applications - would reset the status by calling - snd_pcm_prepare() and restart the stream - appropriately. Hence, you can define suspend/resume callbacks - below but don't set SNDRV_PCM_INFO_RESUME - info flag to the PCM. - - - - Note that the trigger with SUSPEND can always be called when - snd_pcm_suspend_all is called, - regardless of the SNDRV_PCM_INFO_RESUME flag. - The RESUME flag affects only the behavior - of snd_pcm_resume(). - (Thus, in theory, - SNDRV_PCM_TRIGGER_RESUME isn't needed - to be handled in the trigger callback when no - SNDRV_PCM_INFO_RESUME flag is set. But, - it's better to keep it for compatibility reasons.) - - - In the earlier version of ALSA drivers, a common - power-management layer was provided, but it has been removed. - The driver needs to define the suspend/resume hooks according to - the bus the device is connected to. In the case of PCI drivers, the - callbacks look like below: - - - - - - - - - - The scheme of the real suspend job is as follows. - - - Retrieve the card and the chip data. - Call snd_power_change_state() with - SNDRV_CTL_POWER_D3hot to change the - power status. - Call snd_pcm_suspend_all() to suspend the running PCM streams. - If AC97 codecs are used, call - snd_ac97_suspend() for each codec. - Save the register values if necessary. - Stop the hardware if necessary. - Disable the PCI device by calling - pci_disable_device(). Then, call - pci_save_state() at last. - - - - - A typical code would be like: - - - -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; - } -]]> - - - - - - The scheme of the real resume job is as follows. - - - Retrieve the card and the chip data. - Set up PCI. First, call pci_restore_state(). - Then enable the pci device again by calling pci_enable_device(). - Call pci_set_master() if necessary, too. - Re-initialize the chip. - Restore the saved registers if necessary. - Resume the mixer, e.g. calling - snd_ac97_resume(). - Restart the hardware (if any). - Call snd_power_change_state() with - SNDRV_CTL_POWER_D0 to notify the processes. - - - - - A typical code would be like: - - - -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; - } -]]> - - - - - - As shown in the above, it's better to save registers after - suspending the PCM operations via - snd_pcm_suspend_all() or - snd_pcm_suspend(). It means that the PCM - streams are already stoppped when the register snapshot is - taken. But, remember that you don't have to restart the PCM - stream in the resume callback. It'll be restarted via - trigger call with SNDRV_PCM_TRIGGER_RESUME - when necessary. - - - - OK, we have all callbacks now. Let's set them up. In the - initialization of the card, make sure that you can get the chip - data from the card instance, typically via - private_data field, in case you - created the chip data individually. - - - -private_data = chip; - .... - } -]]> - - - - When you created the chip data with - snd_card_create(), it's anyway accessible - via private_data field. - - - -private_data; - .... - } -]]> - - - - - - - If you need a space to save the registers, allocate the - buffer for it here, too, since it would be fatal - if you cannot allocate a memory in the suspend phase. - The allocated buffer should be released in the corresponding - destructor. - - - - And next, set suspend/resume callbacks to the pci_driver. - - - - - - - - - - - - - - - - Module Parameters - - There are standard module options for ALSA. At least, each - module should have the index, - id and enable - options. - - - - If the module supports multiple cards (usually up to - 8 = SNDRV_CARDS cards), they should be - arrays. The default initial values are defined already as - constants for easier programming: - - - - - - - - - - If the module supports only a single card, they could be single - variables, instead. enable option is not - always necessary in this case, but it would be better to have a - dummy option for compatibility. - - - - The module parameters must be declared with the standard - module_param()(), - module_param_array()() and - MODULE_PARM_DESC() macros. - - - - The typical coding would be like below: - - - - - - - - - - Also, don't forget to define the module description, classes, - license and devices. Especially, the recent modprobe requires to - define the module license as GPL, etc., otherwise the system is - shown as tainted. - - - - - - - - - - - - - - - - How To Put Your Driver Into ALSA Tree -
- General - - So far, you've learned how to write the driver codes. - And you might have a question now: how to put my own - driver into the ALSA driver tree? - Here (finally :) the standard procedure is described briefly. - - - - Suppose that you create a new PCI driver for the card - xyz. The card module name would be - snd-xyz. The new driver is usually put into the alsa-driver - tree, alsa-driver/pci directory in - the case of PCI cards. - Then the driver is evaluated, audited and tested - by developers and users. After a certain time, the driver - will go to the alsa-kernel tree (to the corresponding directory, - such as alsa-kernel/pci) and eventually - will be integrated into the Linux 2.6 tree (the directory would be - linux/sound/pci). - - - - In the following sections, the driver code is supposed - to be put into alsa-driver tree. The two cases are covered: - a driver consisting of a single source file and one consisting - of several source files. - -
- -
- Driver with A Single Source File - - - - - Modify alsa-driver/pci/Makefile - - - - Suppose you have a file xyz.c. Add the following - two lines - - - - - - - - - - - Create the Kconfig entry - - - - Add the new entry of Kconfig for your xyz driver. - - - - - - - the line, select SND_PCM, specifies that the driver xyz supports - PCM. In addition to SND_PCM, the following components are - supported for select command: - SND_RAWMIDI, SND_TIMER, SND_HWDEP, SND_MPU401_UART, - SND_OPL3_LIB, SND_OPL4_LIB, SND_VX_LIB, SND_AC97_CODEC. - Add the select command for each supported component. - - - - Note that some selections imply the lowlevel selections. - For example, PCM includes TIMER, MPU401_UART includes RAWMIDI, - AC97_CODEC includes PCM, and OPL3_LIB includes HWDEP. - You don't need to give the lowlevel selections again. - - - - For the details of Kconfig script, refer to the kbuild - documentation. - - - - - - - Run cvscompile script to re-generate the configure script and - build the whole stuff again. - - - - -
- -
- Drivers with Several Source Files - - Suppose that the driver snd-xyz have several source files. - They are located in the new subdirectory, - pci/xyz. - - - - - Add a new directory (xyz) in - alsa-driver/pci/Makefile as below - - - - - - - - - - - - Under the directory xyz, create a Makefile - - - Sample Makefile for a driver xyz - - - - - - - - - - Create the Kconfig entry - - - - This procedure is as same as in the last section. - - - - - - Run cvscompile script to re-generate the configure script and - build the whole stuff again. - - - - -
- -
- - - - - - Useful Functions - -
- <function>snd_printk()</function> and friends - - ALSA provides a verbose version of the - printk() function. If a kernel config - CONFIG_SND_VERBOSE_PRINTK is set, this - function prints the given message together with the file name - and the line of the caller. The KERN_XXX - prefix is processed as - well as the original printk() does, so it's - recommended to add this prefix, e.g. - - - - - - - - - - There are also printk()'s for - debugging. snd_printd() can be used for - general debugging purposes. If - CONFIG_SND_DEBUG is set, this function is - compiled, and works just like - snd_printk(). If the ALSA is compiled - without the debugging flag, it's ignored. - - - - snd_printdd() is compiled in only when - CONFIG_SND_DEBUG_VERBOSE is set. Please note - that CONFIG_SND_DEBUG_VERBOSE is not set as default - even if you configure the alsa-driver with - option. You need to give - explicitly option instead. - -
- -
- <function>snd_BUG()</function> - - It shows the BUG? message and - stack trace as well as snd_BUG_ON at the point. - It's useful to show that a fatal error happens there. - - - When no debug flag is set, this macro is ignored. - -
- -
- <function>snd_BUG_ON()</function> - - snd_BUG_ON() macro is similar with - WARN_ON() macro. For example, - - - - - - - - or it can be used as the condition, - - - - - - - - - - The macro takes an conditional expression to evaluate. - When CONFIG_SND_DEBUG, is set, the - expression is actually evaluated. If it's non-zero, it shows - the warning message such as - BUG? (xxx) - normally followed by stack trace. It returns the evaluated - value. - When no CONFIG_SND_DEBUG is set, this - macro always returns zero. - - -
- -
- - - - - - - Acknowledgments - - I would like to thank Phil Kerr for his help for improvement and - corrections of this document. - - - Kevin Conder reformatted the original plain-text to the - DocBook format. - - - Giuliano Pochini corrected typos and contributed the example codes - in the hardware constraints section. - - -
-- cgit v1.2.3 From 753b7aea8e4611433c13ac157f944d8b4bf42482 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 9 Mar 2009 15:14:37 -0400 Subject: [CPUFREQ] Add p4-clockmod sysfs-ui removal to feature-removal schedule. Signed-off-by: Matthew Garrett Signed-off-by: Dave Jones --- Documentation/feature-removal-schedule.txt | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5ddbe350487..20d3b94703a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -335,3 +335,12 @@ Why: In 2.6.18 the Secmark concept was introduced to replace the "compat_net" Secmark, it is time to deprecate the older mechanism and start the process of removing the old code. Who: Paul Moore +--------------------------- + +What: sysfs ui for changing p4-clockmod parameters +When: September 2009 +Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and + e088e4c9cdb618675874becb91b2fd581ee707e6. + Removal is subject to fixing any remaining bugs in ACPI which may + cause the thermal throttling not to happen at the right time. +Who: Dave Jones , Matthew Garrett -- cgit v1.2.3 From 6dfc0d2c4b9a5455c60e0b9ee95bbf22fc516cef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Mar 2009 07:54:20 +0100 Subject: ALSA: hda - Add missing models to documentation Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 80b796e4a80..f9253ea3c19 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -344,7 +344,9 @@ STAC92HD71B* dell-m4-1 Dell desktops dell-m4-2 Dell desktops dell-m4-3 Dell desktops - hp-m4 HP dv laptops + hp-m4 HP mini 1000 + hp-dv5 HP dv series + hp-hdx HP HDX series auto BIOS setup (default) STAC92HD73* @@ -361,6 +363,7 @@ STAC92HD83* =========== ref Reference board mic-ref Reference board with power managment for ports + dell-s14 Dell laptop auto BIOS setup (default) STAC9872 -- cgit v1.2.3 From 0612ea00a010e36fde61e7b7649a1105b0ef1080 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 10 Mar 2009 12:55:57 -0700 Subject: rcu: documentation 1Q09 update Update the RCU documentation to call out the need for callers of primitives like call_rcu() and synchronize_rcu() to prevent subsequent RCU readers from hazard. Signed-off-by: Paul E. McKenney Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/checklist.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'Documentation') diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 6e253407b3d..accfe2f5247 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -298,3 +298,15 @@ over a rather long period of time, but improvements are always welcome! Note that, rcu_assign_pointer() and rcu_dereference() relate to SRCU just as they do to other forms of RCU. + +15. The whole point of call_rcu(), synchronize_rcu(), and friends + is to wait until all pre-existing readers have finished before + carrying out some otherwise-destructive operation. It is + therefore critically important to -first- remove any path + that readers can follow that could be affected by the + destructive operation, and -only- -then- invoke call_rcu(), + synchronize_rcu(), or friends. + + Because these primitives only wait for pre-existing readers, + it is the caller's responsibility to guarantee safety to + any subsequent readers. -- cgit v1.2.3 From 1a51e068c900eb6ea23ce597361ebf3b19a57b23 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 12 Mar 2009 13:36:38 +0100 Subject: hwmon: (lm90) Document support for the MAX6648/6692 chips Update documentation to prevent further confusion/duplication. Signed-off-by: Darrick J. Wong Signed-off-by: Jean Delvare --- Documentation/hwmon/lm90 | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index 0e841171023..93d8e3d5515 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -42,6 +42,11 @@ Supported chips: Addresses scanned: I2C 0x4e Datasheet: Publicly available at the Maxim website http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497 + * Maxim MAX6648 + Prefix: 'max6646' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3500 * Maxim MAX6649 Prefix: 'max6646' Addresses scanned: I2C 0x4c @@ -74,6 +79,11 @@ Supported chips: 0x4c, 0x4d and 0x4e Datasheet: Publicly available at the Maxim website http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370 + * Maxim MAX6692 + Prefix: 'max6646' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3500 Author: Jean Delvare -- cgit v1.2.3 From 307282c8990c5658604b9fda8a64a9a07079b850 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Mar 2009 18:17:58 +0100 Subject: ALSA: hda - Add model=vaio for STAC9872 Add the default pin config for model=vaio (in case of broken BIOS). Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index f9253ea3c19..8eec05bc079 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -368,4 +368,5 @@ STAC92HD83* STAC9872 ======== - N/A + vaio VAIO laptop without SPDIF + auto BIOS setup (default) -- cgit v1.2.3 From ab03eca8d4754ef2ba9821d581975b10b8f317e7 Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Thu, 12 Mar 2009 17:39:23 -0400 Subject: trivial: fix bad links in the ext2 and ext3 documentation Trivial patch to fix bad links in the ext2 and ext3 documentation. Signed-off-by: Jody McIntyre Signed-off-by: Linus Torvalds --- Documentation/filesystems/ext2.txt | 10 +++++----- Documentation/filesystems/ext3.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt index 4333e836c49..23448551cab 100644 --- a/Documentation/filesystems/ext2.txt +++ b/Documentation/filesystems/ext2.txt @@ -373,10 +373,10 @@ Filesystem Resizing http://ext2resize.sourceforge.net/ Compression (*) http://e2compr.sourceforge.net/ Implementations for: -Windows 95/98/NT/2000 http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm -Windows 95 (*) http://www.yipton.demon.co.uk/content.html#FSDEXT2 +Windows 95/98/NT/2000 http://www.chrysocome.net/explore2fs +Windows 95 (*) http://www.yipton.net/content.html#FSDEXT2 DOS client (*) ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ -OS/2 http://perso.wanadoo.fr/matthieu.willm/ext2-os2/ -RISC OS client ftp://ftp.barnet.ac.uk/pub/acorn/armlinux/iscafs/ +OS/2 (*) ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ +RISC OS client http://www.esw-heim.tu-clausthal.de/~marco/smorbrod/IscaFS/ -(*) no longer actively developed/supported (as of Apr 2001) +(*) no longer actively developed/supported (as of Mar 2009) diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt index 9dd2a3bb2ac..e5f3833a6ef 100644 --- a/Documentation/filesystems/ext3.txt +++ b/Documentation/filesystems/ext3.txt @@ -198,5 +198,5 @@ kernel source: programs: http://e2fsprogs.sourceforge.net/ http://ext2resize.sourceforge.net -useful links: http://www-106.ibm.com/developerworks/linux/library/l-fs7/ - http://www-106.ibm.com/developerworks/linux/library/l-fs8/ +useful links: http://www.ibm.com/developerworks/library/l-fs7.html + http://www.ibm.com/developerworks/library/l-fs8.html -- cgit v1.2.3 From 8032b526d1a3bd91ad633dd3a3b5fdbc47ad54f1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 16 Mar 2009 09:05:07 +1030 Subject: linux.conf.au 2009: Tuz Impact: help prevent extinction of species The Tasmanian Devil is a shy iconic Australian creature named for its spine-chilling screech. It is threatened with extinction due to a scientifically interesting but horrific transmissible facial cancer. This one is standing in for Tux for one release using the far less-known Devil Facial Tux Disguise. Save The Tasmanian Devil http://tassiedevil.com.au Signed-off-by: Linux.conf.au Hobart Team Signed-off-by: Rusty Russell Signed-off-by: Linus Torvalds --- Documentation/logo.gif | Bin 16335 -> 0 bytes Documentation/logo.svg | 2911 ++++++++++++++++++++++++++++++++++++++++++++++++ Documentation/logo.txt | 15 +- 3 files changed, 2914 insertions(+), 12 deletions(-) delete mode 100644 Documentation/logo.gif create mode 100644 Documentation/logo.svg (limited to 'Documentation') diff --git a/Documentation/logo.gif b/Documentation/logo.gif deleted file mode 100644 index 2eae75fecfb..00000000000 Binary files a/Documentation/logo.gif and /dev/null differ diff --git a/Documentation/logo.svg b/Documentation/logo.svg new file mode 100644 index 00000000000..cb9e4851d8c --- /dev/null +++ b/Documentation/logo.svg @@ -0,0 +1,2911 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/logo.txt b/Documentation/logo.txt index 296f0f7f67e..a2e62445e28 100644 --- a/Documentation/logo.txt +++ b/Documentation/logo.txt @@ -1,13 +1,4 @@ -This is the full-colour version of the currently unofficial Linux logo -("currently unofficial" just means that there has been no paperwork and -that I have not really announced it yet). It was created by Larry Ewing, -and is freely usable as long as you acknowledge Larry as the original -artist. - -Note that there are black-and-white versions of this available that -scale down to smaller sizes and are better for letterheads or whatever -you want to use it for: for the full range of logos take a look at -Larry's web-page: - - http://www.isc.tamu.edu/~lewing/linux/ +Tux is taking a three month sabbatical to work as a barber, so Tuz is +standing in. He's taken pains to ensure you'll hardly notice. +Image by Andrew McGown and Josh Bush. Image is licensed CC BY-SA. -- cgit v1.2.3 From 1db4b2d221f14b9715c717dbd9a476469a687080 Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 23 Mar 2009 13:13:34 -0400 Subject: trivial: fix orphan dates in ext2 documentation Revert the change to the orphan dates of Windows 95, DOS, compression. Add a new orphan date for OS/2. Signed-off-by: Jody McIntyre Acked-by: Pavel Machek Signed-off-by: Linus Torvalds --- Documentation/filesystems/ext2.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt index 23448551cab..e055acb6b2d 100644 --- a/Documentation/filesystems/ext2.txt +++ b/Documentation/filesystems/ext2.txt @@ -376,7 +376,8 @@ Implementations for: Windows 95/98/NT/2000 http://www.chrysocome.net/explore2fs Windows 95 (*) http://www.yipton.net/content.html#FSDEXT2 DOS client (*) ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ -OS/2 (*) ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ +OS/2 (+) ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ RISC OS client http://www.esw-heim.tu-clausthal.de/~marco/smorbrod/IscaFS/ -(*) no longer actively developed/supported (as of Mar 2009) +(*) no longer actively developed/supported (as of Apr 2001) +(+) no longer actively developed/supported (as of Mar 2009) -- cgit v1.2.3 From 471c604daf73ff549d374ee54f9e6bfd5a54d4e8 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Thu, 19 Feb 2009 22:54:45 -0700 Subject: USB: usbmon: Add binary API v1 This patch adds an extension to the binary API so it reaches parity with existing text API (so-called "1u"). The extension delivers additional data, such as ISO descriptors and the interrupt interval. Signed-Off-By: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usbmon.txt | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index 270481906dc..6c3c625b7f3 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -229,16 +229,26 @@ struct usbmon_packet { int status; /* 28: */ unsigned int length; /* 32: Length of data (submitted or actual) */ unsigned int len_cap; /* 36: Delivered length */ - unsigned char setup[8]; /* 40: Only for Control 'S' */ -}; /* 48 bytes total */ + union { /* 40: */ + unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ + struct iso_rec { /* Only for ISO */ + int error_count; + int numdesc; + } iso; + } s; + int interval; /* 48: Only for Interrupt and ISO */ + int start_frame; /* 52: For ISO */ + unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */ + unsigned int ndesc; /* 60: Actual number of ISO descriptors */ +}; /* 64 total length */ These events can be received from a character device by reading with read(2), -with an ioctl(2), or by accessing the buffer with mmap. +with an ioctl(2), or by accessing the buffer with mmap. However, read(2) +only returns first 48 bytes for compatibility reasons. The character device is usually called /dev/usbmonN, where N is the USB bus number. Number zero (/dev/usbmon0) is special and means "all buses". -However, this feature is not implemented yet. Note that specific naming -policy is set by your Linux distribution. +Note that specific naming policy is set by your Linux distribution. If you create /dev/usbmon0 by hand, make sure that it is owned by root and has mode 0600. Otherwise, unpriviledged users will be able to snoop @@ -279,9 +289,10 @@ size is out of [unspecified] bounds for this kernel, the call fails with This call returns the current size of the buffer in bytes. MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg) + MON_IOCX_GETX, defined as _IOW(MON_IOC_MAGIC, 10, struct mon_get_arg) -This call waits for events to arrive if none were in the kernel buffer, -then returns the first event. Its argument is a pointer to the following +These calls wait for events to arrive if none were in the kernel buffer, +then return the first event. The argument is a pointer to the following structure: struct mon_get_arg { @@ -294,6 +305,8 @@ Before the call, hdr, data, and alloc should be filled. Upon return, the area pointed by hdr contains the next event structure, and the data buffer contains the data, if any. The event is removed from the kernel buffer. +The MON_IOCX_GET copies 48 bytes, MON_IOCX_GETX copies 64 bytes. + MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg) This ioctl is primarily used when the application accesses the buffer -- cgit v1.2.3 From 8205779114e8f612549d191f8e151526a74ab9f2 Mon Sep 17 00:00:00 2001 From: "Hans J. Koch" Date: Wed, 7 Jan 2009 00:15:39 +0100 Subject: UIO: Add name attributes for mappings and port regions If a UIO device has several memory mappings, it can be difficult for userspace to find the right one. The situation becomes even worse if the UIO driver can handle different versions of a card that have different numbers of mappings. Benedikt Spranger has such cards and pointed this out to me. Thanks, Bene! To address this problem, this patch adds "name" sysfs attributes for each mapping. Userspace can use these to clearly identify each mapping. The name string is optional. If a driver doesn't set it, an empty string will be returned, so this patch won't break existing drivers. The same problem exists for port region information, so a "name" attribute is added there, too. Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman --- Documentation/DocBook/uio-howto.tmpl | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index 52e1b79ce0e..8f6e3b2403c 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -41,6 +41,13 @@ GPL version 2. + + 0.8 + 2008-12-24 + hjk + Added name attributes in mem and portio sysfs directories. + + 0.7 2008-12-23 @@ -303,10 +310,17 @@ interested in translating it, please email me appear if the size of the mapping is not 0.
- Each mapX/ directory contains two read-only files - that show start address and size of the memory: + Each mapX/ directory contains four read-only files + that show attributes of the memory: + + + name: A string identifier for this mapping. This + is optional, the string can be empty. Drivers can set this to make it + easier for userspace to find the correct mapping. + + addr: The address of memory that can be mapped. @@ -366,10 +380,17 @@ offset = N * getpagesize(); /sys/class/uio/uioX/portio/. - Each portX/ directory contains three read-only - files that show start, size, and type of the port region: + Each portX/ directory contains four read-only + files that show name, start, size, and type of the port region: + + + name: A string identifier for this port region. + The string is optional and can be empty. Drivers can set it to make it + easier for userspace to find a certain port region. + + start: The first port of this region. -- cgit v1.2.3 From e9d376f0fa66bd630fe27403669c6ae6c22a868f Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Thu, 5 Feb 2009 11:51:38 -0500 Subject: dynamic debug: combine dprintk and dynamic printk This patch combines Greg Bank's dprintk() work with the existing dynamic printk patchset, we are now calling it 'dynamic debug'. The new feature of this patchset is a richer /debugfs control file interface, (an example output from my system is at the bottom), which allows fined grained control over the the debug output. The output can be controlled by function, file, module, format string, and line number. for example, enabled all debug messages in module 'nf_conntrack': echo -n 'module nf_conntrack +p' > /mnt/debugfs/dynamic_debug/control to disable them: echo -n 'module nf_conntrack -p' > /mnt/debugfs/dynamic_debug/control A further explanation can be found in the documentation patch. Signed-off-by: Greg Banks Signed-off-by: Jason Baron Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 5 ----- 1 file changed, 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 54f21a5c262..3a1aa8a4aff 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1816,11 +1816,6 @@ and is between 256 and 4096 characters. It is defined in the file autoconfiguration. Ranges are in pairs (memory base and size). - dynamic_printk Enables pr_debug()/dev_dbg() calls if - CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. - These can also be switched on/off via - /dynamic_printk/modules - print-fatal-signals= [KNL] debug: print fatal signals print-fatal-signals=1: print segfault info to -- cgit v1.2.3 From 86151fdf38b3795f292b39defbff39d2684b9c8c Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Thu, 5 Feb 2009 11:53:15 -0500 Subject: dynamic debug: update docs updates the documentation for 'dynamic debug' feature. Signed-off-by: Greg Banks Signed-off-by: Jason Baron Signed-off-by: Greg Kroah-Hartman --- Documentation/dynamic-debug-howto.txt | 232 ++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 Documentation/dynamic-debug-howto.txt (limited to 'Documentation') diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt new file mode 100644 index 00000000000..68394825e86 --- /dev/null +++ b/Documentation/dynamic-debug-howto.txt @@ -0,0 +1,232 @@ + +Introduction +============ + +This document describes how to use the dynamic debug (ddebug) feature. + +Dynamic debug is designed to allow you to dynamically enable/disable kernel +code to obtain additional kernel information. Currently, if +CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_debug() calls can be +dynamically enabled per-callsite. + +Dynamic debug has even more useful features: + + * Simple query language allows turning on and off debugging statements by + matching any combination of: + + - source filename + - function name + - line number (including ranges of line numbers) + - module name + - format string + + * Provides a debugfs control file: /dynamic_debug/control which can be + read to display the complete list of known debug statements, to help guide you + +Controlling dynamic debug Behaviour +=============================== + +The behaviour of pr_debug()/dev_debug()s are controlled via writing to a +control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs +filesystem, in order to make use of this feature. Subsequently, we refer to the +control file as: /dynamic_debug/control. For example, if you want to +enable printing from source file 'svcsock.c', line 1603 you simply do: + +nullarbor:~ # echo 'file svcsock.c line 1603 +p' > + /dynamic_debug/control + +If you make a mistake with the syntax, the write will fail thus: + +nullarbor:~ # echo 'file svcsock.c wtf 1 +p' > + /dynamic_debug/control +-bash: echo: write error: Invalid argument + +Viewing Dynamic Debug Behaviour +=========================== + +You can view the currently configured behaviour of all the debug statements +via: + +nullarbor:~ # cat /dynamic_debug/control +# filename:lineno [module]function flags format +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA\040Module\040Removed,\040deregister\040RPC\040RDMA\040transport\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init - "\011max_inline\040\040\040\040\040\040\040:\040%d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init - "\011sq_depth\040\040\040\040\040\040\040\040\040:\040%d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init - "\011max_requests\040\040\040\040\040:\040%d\012" +... + + +You can also apply standard Unix text manipulation filters to this +data, e.g. + +nullarbor:~ # grep -i rdma /dynamic_debug/control | wc -l +62 + +nullarbor:~ # grep -i tcp /dynamic_debug/control | wc -l +42 + +Note in particular that the third column shows the enabled behaviour +flags for each debug statement callsite (see below for definitions of the +flags). The default value, no extra behaviour enabled, is "-". So +you can view all the debug statement callsites with any non-default flags: + +nullarbor:~ # awk '$3 != "-"' /dynamic_debug/control +# filename:lineno [module]function flags format +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process:\040st_sendto\040returned\040%d\012" + + +Command Language Reference +========================== + +At the lexical level, a command comprises a sequence of words separated +by whitespace characters. Note that newlines are treated as word +separators and do *not* end a command or allow multiple commands to +be done together. So these are all equivalent: + +nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' > + /dynamic_debug/control +nullarbor:~ # echo -c ' file svcsock.c line 1603 +p ' > + /dynamic_debug/control +nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' > + /dynamic_debug/control +nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' > + /dynamic_debug/control + +Commands are bounded by a write() system call. If you want to do +multiple commands you need to do a separate "echo" for each, like: + +nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\ +> echo 'file svcsock.c line 1563 +p' > /proc/dprintk + +or even like: + +nullarbor:~ # ( +> echo 'file svcsock.c line 1603 +p' ;\ +> echo 'file svcsock.c line 1563 +p' ;\ +> ) > /proc/dprintk + +At the syntactical level, a command comprises a sequence of match +specifications, followed by a flags change specification. + +command ::= match-spec* flags-spec + +The match-spec's are used to choose a subset of the known dprintk() +callsites to which to apply the flags-spec. Think of them as a query +with implicit ANDs between each pair. Note that an empty list of +match-specs is possible, but is not very useful because it will not +match any debug statement callsites. + +A match specification comprises a keyword, which controls the attribute +of the callsite to be compared, and a value to compare against. Possible +keywords are: + +match-spec ::= 'func' string | + 'file' string | + 'module' string | + 'format' string | + 'line' line-range + +line-range ::= lineno | + '-'lineno | + lineno'-' | + lineno'-'lineno +// Note: line-range cannot contain space, e.g. +// "1-30" is valid range but "1 - 30" is not. + +lineno ::= unsigned-int + +The meanings of each keyword are: + +func + The given string is compared against the function name + of each callsite. Example: + + func svc_tcp_accept + +file + The given string is compared against either the full + pathname or the basename of the source file of each + callsite. Examples: + + file svcsock.c + file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c + +module + The given string is compared against the module name + of each callsite. The module name is the string as + seen in "lsmod", i.e. without the directory or the .ko + suffix and with '-' changed to '_'. Examples: + + module sunrpc + module nfsd + +format + The given string is searched for in the dynamic debug format + string. Note that the string does not need to match the + entire format, only some part. Whitespace and other + special characters can be escaped using C octal character + escape \ooo notation, e.g. the space character is \040. + Examples: + + format svcrdma: // many of the NFS/RDMA server dprintks + format readahead // some dprintks in the readahead cache + format nfsd:\040SETATTR // how to match a format with whitespace + +line + The given line number or range of line numbers is compared + against the line number of each dprintk() callsite. A single + line number matches the callsite line number exactly. A + range of line numbers matches any callsite between the first + and last line number inclusive. An empty first number means + the first line in the file, an empty line number means the + last number in the file. Examples: + + line 1603 // exactly line 1603 + line 1600-1605 // the six lines from line 1600 to line 1605 + line -1605 // the 1605 lines from line 1 to line 1605 + line 1600- // all lines from line 1600 to the end of the file + +The flags specification comprises a change operation followed +by one or more flag characters. The change operation is one +of the characters: + +- + remove the given flags + ++ + add the given flags + += + set the flags to the given flags + +The flags are: + +p + Causes a printk() message to be emitted to dmesg + +Note the regexp ^[-+=][scp]+$ matches a flags specification. +Note also that there is no convenient syntax to remove all +the flags at once, you need to use "-psc". + +Examples +======== + +// enable the message at line 1603 of file svcsock.c +nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' > + /dynamic_debug/control + +// enable all the messages in file svcsock.c +nullarbor:~ # echo -n 'file svcsock.c +p' > + /dynamic_debug/control + +// enable all the messages in the NFS server module +nullarbor:~ # echo -n 'module nfsd +p' > + /dynamic_debug/control + +// enable all 12 messages in the function svc_process() +nullarbor:~ # echo -n 'func svc_process +p' > + /dynamic_debug/control + +// disable all 12 messages in the function svc_process() +nullarbor:~ # echo -n 'func svc_process -p' > + /dynamic_debug/control -- cgit v1.2.3 From 9898abb3d23311fa227a7f46bf4e40fd2954057f Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Fri, 6 Feb 2009 12:54:26 +1100 Subject: Dynamic debug: allow simple quoting of words Allow simple quoting of words in the dynamic debug control language. This allows more natural specification when using the control language to match against printk formats, e.g #echo -n 'format "Setting node for non-present cpu" +p' > /mnt/debugfs/dynamic_debug/control instead of #echo -n 'format Setting\040node\040for\040non-present\040cpu +p' > /mnt/debugfs/dynamic_debug/control Adjust the dynamic debug documention to describe that and provide a new example. Adjust the existing examples in the documentation to reflect the current whitespace escaping behaviour when reading the control file. Fix some minor documentation trailing whitespace. Signed-off-by: Greg Banks Acked-by: Jason Baron Signed-off-by: Greg Kroah-Hartman --- Documentation/dynamic-debug-howto.txt | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt index 68394825e86..674c5663d34 100644 --- a/Documentation/dynamic-debug-howto.txt +++ b/Documentation/dynamic-debug-howto.txt @@ -49,10 +49,10 @@ via: nullarbor:~ # cat /dynamic_debug/control # filename:lineno [module]function flags format -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA\040Module\040Removed,\040deregister\040RPC\040RDMA\040transport\012" -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init - "\011max_inline\040\040\040\040\040\040\040:\040%d\012" -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init - "\011sq_depth\040\040\040\040\040\040\040\040\040:\040%d\012" -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init - "\011max_requests\040\040\040\040\040:\040%d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA Module Removed, deregister RPC RDMA transport\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init - "\011max_inline : %d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init - "\011sq_depth : %d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init - "\011max_requests : %d\012" ... @@ -72,7 +72,7 @@ you can view all the debug statement callsites with any non-default flags: nullarbor:~ # awk '$3 != "-"' /dynamic_debug/control # filename:lineno [module]function flags format -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process:\040st_sendto\040returned\040%d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012" Command Language Reference @@ -166,11 +166,15 @@ format entire format, only some part. Whitespace and other special characters can be escaped using C octal character escape \ooo notation, e.g. the space character is \040. + Alternatively, the string can be enclosed in double quote + characters (") or single quote characters ('). Examples: format svcrdma: // many of the NFS/RDMA server dprintks format readahead // some dprintks in the readahead cache - format nfsd:\040SETATTR // how to match a format with whitespace + format nfsd:\040SETATTR // one way to match a format with whitespace + format "nfsd: SETATTR" // a neater way to match a format with whitespace + format 'nfsd: SETATTR' // yet another way to match a format with whitespace line The given line number or range of line numbers is compared @@ -230,3 +234,7 @@ nullarbor:~ # echo -n 'func svc_process +p' > // disable all 12 messages in the function svc_process() nullarbor:~ # echo -n 'func svc_process -p' > /dynamic_debug/control + +// enable messages for NFS calls READ, READLINK, READDIR and READDIR+. +nullarbor:~ # echo -n 'format "nfsd: READ" +p' > + /dynamic_debug/control -- cgit v1.2.3