diff options
author | 2007-02-09 08:24:04 -0800 | |
---|---|---|
committer | 2007-02-09 08:24:04 -0800 | |
commit | 6026179519896e7d35b2564e7544487d1c8948e7 (patch) | |
tree | c78c7032abce24d846423572204f1cd4e97d8efc | |
parent | Merge branch 'for-linus' of git://www.atmel.no/~hskinnemoen/linux/kernel/avr32 (diff) | |
parent | [PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED (diff) | |
download | linux-dev-6026179519896e7d35b2564e7544487d1c8948e7.tar.xz linux-dev-6026179519896e7d35b2564e7544487d1c8948e7.zip |
Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (212 commits)
[PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED
[ALSA] version 1.0.14rc2
[ALSA] ASoC documentation updates
[ALSA] ca0106 - Add missing sysfs device assignment
[ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully
[ALSA] hda-codec - Add support for Fujitsu PI1556 Realtek ALC880
[ALSA] aoa: remove suspend/resume printks
[ALSA] Fix possible deadlocks in sequencer at removal of ports
[ALSA] emu10k1 - Fix STAC9758 front channel
[ALSA] soc - Clean up with kmemdup()
[ALSA] snd-ak4114: Fix two array overflows
[ALSA] ac97_bus power management
[ALSA] usbaudio - Add support for Edirol UA-101
[ALSA] hda-codec - Add ALC861VD/ALC660VD support
[ALSA] soc - ASoC 0.13 Sharp poodle machine
[ALSA] soc - ASoC 0.13 Sharp tosa machine
[ALSA] soc - ASoC 0.13 spitz machine
[ALSA] soc - ASoC Sharp corgi machine
[ALSA] soc - ASoC 0.13 pxa2xx DMA
[ALSA] soc - ASoC 0.13 pxa2xx AC97 driver
...
216 files changed, 28241 insertions, 3797 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 9fef210ab50a..c30ff1bb2d10 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -242,6 +242,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ac97_clock - AC'97 clock (default = 48000) ac97_quirk - AC'97 workaround for strange hardware See "AC97 Quirk Option" section below. + ac97_codec - Workaround to specify which AC'97 codec + instead of probing. If this works for you + file a bug with your `lspci -vn` output. + -2 -- Force probing. + -1 -- Default behavior. + 0-2 -- Use the specified codec. spdif_aclink - S/PDIF transfer over AC-link (default = 1) This module supports one card and autoprobe. @@ -779,6 +785,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. asus-dig ASUS with SPDIF out asus-dig2 ASUS with SPDIF out (using GPIO2) uniwill 3-jack + fujitsu Fujitsu Laptops (Pi1536) F1734 2-jack lg LG laptop (m1 express dual) lg-lw LG LW20/LW25 laptop @@ -800,14 +807,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ALC262 fujitsu Fujitsu Laptop hp-bpc HP xw4400/6400/8400/9400 laptops + hp-bpc-d7000 HP BPC D7000 benq Benq ED8 + hippo Hippo (ATI) with jack detection, Sony UX-90s + hippo_1 Hippo (Benq) with jack detection basic fixed pin assignment w/o SPDIF auto auto-config reading BIOS (default) ALC882/885 3stack-dig 3-jack with SPDIF I/O - 6stck-dig 6-jack digital with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O arima Arima W820Di1 + macpro MacPro support auto auto-config reading BIOS (default) ALC883/888 @@ -817,6 +828,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O 6stack-dig-demo 6-jack digital for Intel demo board acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + medion Medion Laptops + targa-dig Targa/MSI + targa-2ch-dig Targs/MSI with 2-channel + laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) auto auto-config reading BIOS (default) ALC861/660 @@ -825,6 +840,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack-dig 6-jack with SPDIF I/O 3stack-660 3-jack (for ALC660) uniwill-m31 Uniwill M31 laptop + toshiba Toshiba laptop support + asus Asus laptop support + asus-laptop ASUS F2/F3 laptops + auto auto-config reading BIOS (default) + + ALC861VD/660VD + 3stack 3-jack + 3stack-dig 3-jack with SPDIF OUT + 6stack-dig 6-jack with SPDIF OUT + 3stack-660 3-jack (for ALC660VD) auto auto-config reading BIOS (default) CMI9880 @@ -845,6 +870,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + ultra 2-channel with EAPD (Samsung Ultra tablet PC) AD1988 6stack 6-jack @@ -854,12 +880,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. laptop 3-jack with hp-jack automute laptop-dig ditto with SPDIF auto auto-config reading BIOS (default) + + Conexant 5045 + laptop Laptop config + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + + Conexant 5047 + laptop Basic Laptop config + laptop-hp Laptop config for some HP models (subdevice 30A5) + laptop-eapd Laptop config with EAPD support + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y STAC9200/9205/9220/9221/9254 ref Reference board 3stack D945 3stack 5stack D945 5stack + SPDIF + STAC9202/9250/9251 + ref Reference board, base config + m2-2 Some Gateway MX series laptops + m6 Some Gateway NX series laptops + STAC9227/9228/9229/927x ref Reference board 3stack D965 3stack @@ -974,6 +1019,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. * MidiMan M Audio Revolution 5.1 * MidiMan M Audio Revolution 7.1 + * MidiMan M Audio Audiophile 192 * AMP Ltd AUDIO2000 * TerraTec Aureon 5.1 Sky * TerraTec Aureon 7.1 Space @@ -993,7 +1039,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. model - Use the given board model, one of the following: revo51, revo71, amp2000, prodigy71, prodigy71lt, - prodigy192, aureon51, aureon71, universe, + prodigy192, aureon51, aureon71, universe, ap192, k8x800, phase22, phase28, ms300, av710 This module supports multiple cards and autoprobe. @@ -1049,6 +1095,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. buggy_semaphore - Enable workaround for hardwares with buggy semaphores (e.g. on some ASUS laptops) (default off) + spdif_aclink - Use S/PDIF over AC-link instead of direct connection + from the controller chip + (0 = off, 1 = on, -1 = default) This module supports one chip and autoprobe. @@ -1371,6 +1420,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards. + Module snd-portman2x4 + --------------------- + + Module for Midiman Portman 2x4 parallel port MIDI interface + + This module supports multiple cards. + Module snd-powermac (on ppc only) --------------------------------- diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl index 1f3ae3e32d69..c4d2e3507af9 100644 --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl @@ -36,7 +36,7 @@ </bookinfo> <chapter><title>Management of Cards and Devices</title> - <sect1><title>Card Managment</title> + <sect1><title>Card Management</title> !Esound/core/init.c </sect1> <sect1><title>Device Components</title> @@ -59,7 +59,7 @@ <sect1><title>PCM Format Helpers</title> !Esound/core/pcm_misc.c </sect1> - <sect1><title>PCM Memory Managment</title> + <sect1><title>PCM Memory Management</title> !Esound/core/pcm_memory.c </sect1> </chapter> diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index ccd0a953953d..74d3a35b59bc 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -1360,8 +1360,7 @@ <informalexample> <programlisting> <![CDATA[ - static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) { struct mychip *chip = dev_id; .... @@ -2127,7 +2126,7 @@ accessible via <constant>substream->runtime</constant>. This runtime pointer holds the various information; it holds the copy of hw_params and sw_params configurations, the buffer - pointers, mmap records, spinlocks, etc. Almost everyhing you + pointers, mmap records, spinlocks, etc. Almost everything you need for controlling the PCM can be found there. </para> @@ -2340,7 +2339,7 @@ struct _snd_pcm_runtime { <para> When the PCM substreams can be synchronized (typically, - synchorinized start/stop of a playback and a capture streams), + synchronized start/stop of a playback and a capture streams), you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>, too. In this case, you'll need to check the linked-list of PCM substreams in the trigger callback. This will be @@ -3062,8 +3061,7 @@ struct _snd_pcm_runtime { <title>Interrupt Handler Case #1</title> <programlisting> <![CDATA[ - static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) { struct mychip *chip = dev_id; spin_lock(&chip->lock); @@ -3106,8 +3104,7 @@ struct _snd_pcm_runtime { <title>Interrupt Handler Case #2</title> <programlisting> <![CDATA[ - static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) { struct mychip *chip = dev_id; spin_lock(&chip->lock); @@ -3247,7 +3244,7 @@ struct _snd_pcm_runtime { 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 <structname>snd_pcm_hardware</structname> stucture (or in any + specified in the <structname>snd_pcm_hardware</structname> structure (or in any other constraint_list). You can build a rule like this: <example> @@ -3691,16 +3688,6 @@ struct _snd_pcm_runtime { </para> <para> - Here, the chip instance is retrieved via - <function>snd_kcontrol_chip()</function> macro. This macro - just accesses to kcontrol->private_data. The - kcontrol->private_data field is - given as the argument of <function>snd_ctl_new()</function> - (see the later subsection - <link linkend="control-interface-constructor"><citetitle>Constructor</citetitle></link>). - </para> - - <para> The <structfield>value</structfield> field is depending on the type of control as well as on info callback. For example, the sb driver uses this field to store the register offset, @@ -3780,7 +3767,7 @@ struct _snd_pcm_runtime { <para> Like <structfield>get</structfield> callback, when the control has more than one elements, - all elemehts must be evaluated in this callback, too. + all elements must be evaluated in this callback, too. </para> </section> @@ -5541,12 +5528,12 @@ struct _snd_pcm_runtime { #ifdef CONFIG_PM static int snd_my_suspend(struct pci_dev *pci, pm_message_t state) { - .... /* do things for suspsend */ + .... /* do things for suspend */ return 0; } static int snd_my_resume(struct pci_dev *pci) { - .... /* do things for suspsend */ + .... /* do things for suspend */ return 0; } #endif @@ -6111,7 +6098,7 @@ struct _snd_pcm_runtime { <!-- ****************************************************** --> <!-- Acknowledgments --> <!-- ****************************************************** --> - <chapter id="acknowledments"> + <chapter id="acknowledgments"> <title>Acknowledgments</title> <para> I would like to thank Phil Kerr for his help for improvement and diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt index 0be57ed81302..4eaae2a45534 100644 --- a/Documentation/sound/alsa/hda_codec.txt +++ b/Documentation/sound/alsa/hda_codec.txt @@ -277,11 +277,11 @@ Helper Functions snd_hda_get_codec_name() stores the codec name on the given string. snd_hda_check_board_config() can be used to obtain the configuration -information matching with the device. Define the table with struct -hda_board_config entries (zero-terminated), and pass it to the -function. The function checks the modelname given as a module -parameter, and PCI subsystem IDs. If the matching entry is found, it -returns the config field value. +information matching with the device. Define the model string table +and the table with struct snd_pci_quirk entries (zero-terminated), +and pass it to the function. The function checks the modelname given +as a module parameter, and PCI subsystem IDs. If the matching entry +is found, it returns the config field value. snd_hda_add_new_ctls() can be used to create and add control entries. Pass the zero-terminated array of struct snd_kcontrol_new. The same array diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt new file mode 100644 index 000000000000..58cbfd01ea8f --- /dev/null +++ b/Documentation/sound/alsa/soc/DAI.txt @@ -0,0 +1,56 @@ +ASoC currently supports the three main Digital Audio Interfaces (DAI) found on +SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM. + + +AC97 +==== + + AC97 is a five wire interface commonly found on many PC sound cards. It is +now also popular in many portable devices. This DAI has a reset line and time +multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines. +The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the +frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97 +frame is 21uS long and is divided into 13 time slots. + +The AC97 specification can be found at :- +http://www.intel.com/design/chipsets/audio/ac97_r23.pdf + + +I2S +=== + + I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and +Rx lines are used for audio transmision, whilst the bit clock (BCLK) and +left/right clock (LRC) synchronise the link. I2S is flexible in that either the +controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock +usually varies depending on the sample rate and the master system clock +(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate +ADC and DAC LRCLK's, this allows for similtanious capture and playback at +different sample rates. + +I2S has several different operating modes:- + + o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC + transition. + + o Left Justified - MSB is transmitted on transition of LRC. + + o Right Justified - MSB is transmitted sample size BCLK's before LRC + transition. + +PCM +=== + +PCM is another 4 wire interface, very similar to I2S, that can support a more +flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used +to synchronise the link whilst the Tx and Rx lines are used to transmit and +receive the audio data. Bit clock usually varies depending on sample rate +whilst sync runs at the sample rate. PCM also supports Time Division +Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This +is sometimes referred to as network mode). + +Common PCM operating modes:- + + o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC. + + o Mode B - MSB is transmitted on rising edge of FRAME/SYNC. diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt new file mode 100644 index 000000000000..e93960d53a1e --- /dev/null +++ b/Documentation/sound/alsa/soc/clocking.txt @@ -0,0 +1,51 @@ +Audio Clocking +============== + +This text describes the audio clocking terms in ASoC and digital audio in +general. Note: Audio clocking can be complex ! + + +Master Clock +------------ + +Every audio subsystem is driven by a master clock (sometimes refered to as MCLK +or SYSCLK). This audio master clock can be derived from a number of sources +(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct +audio playback and capture sample rates. + +Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that +their speed can be altered by software (depending on the system use and to save +power). Other master clocks are fixed at at set frequency (i.e. crystals). + + +DAI Clocks +---------- +The Digital Audio Interface is usually driven by a Bit Clock (often referred to +as BCLK). This clock is used to drive the digital audio data across the link +between the codec and CPU. + +The DAI also has a frame clock to signal the start of each audio frame. This +clock is sometimes referred to as LRC (left right clock) or FRAME. This clock +runs at exactly the sample rate (LRC = Rate). + +Bit Clock can be generated as follows:- + +BCLK = MCLK / x + + or + +BCLK = LRC * x + + or + +BCLK = LRC * Channels * Word Size + +This relationship depends on the codec or SoC CPU in particular. In general +it's best to configure BCLK to the lowest possible speed (depending on your +rate, number of channels and wordsize) to save on power. + +It's also desireable to use the codec (if possible) to drive (or master) the +audio clocks as it's usually gives more accurate sample rates than the CPU. + + + diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt new file mode 100644 index 000000000000..48983c75aad9 --- /dev/null +++ b/Documentation/sound/alsa/soc/codec.txt @@ -0,0 +1,197 @@ +ASoC Codec Driver +================= + +The codec driver is generic and hardware independent code that configures the +codec to provide audio capture and playback. It should contain no code that is +specific to the target platform or machine. All platform and machine specific +code should be added to the platform and machine drivers respectively. + +Each codec driver *must* provide the following features:- + + 1) Codec DAI and PCM configuration + 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's + 3) Mixers and audio controls + 4) Codec audio operations + +Optionally, codec drivers can also provide:- + + 5) DAPM description. + 6) DAPM event handler. + 7) DAC Digital mute control. + +It's probably best to use this guide in conjuction with the existing codec +driver code in sound/soc/codecs/ + +ASoC Codec driver breakdown +=========================== + +1 - Codec DAI and PCM configuration +----------------------------------- +Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and +PCM's capablities and operations. This struct is exported so that it can be +registered with the core by your machine driver. + +e.g. + +struct snd_soc_codec_dai wm8731_dai = { + .name = "WM8731", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* pcm operations - see section 4 below */ + .ops = { + .prepare = wm8731_pcm_prepare, + .hw_params = wm8731_hw_params, + .shutdown = wm8731_shutdown, + }, + /* DAI operations - see DAI.txt */ + .dai_ops = { + .digital_mute = wm8731_mute, + .set_sysclk = wm8731_set_dai_sysclk, + .set_fmt = wm8731_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(wm8731_dai); + + +2 - Codec control IO +-------------------- +The codec can ususally be controlled via an I2C or SPI style interface (AC97 +combines control with data in the DAI). The codec drivers will have to provide +functions to read and write the codec registers along with supplying a register +cache:- + + /* IO control data and register cache */ + void *control_data; /* codec control (i2c/3wire) data */ + void *reg_cache; + +Codec read/write should do any data formatting and call the hardware read write +below to perform the IO. These functions are called by the core and alsa when +performing DAPM or changing the mixer:- + + unsigned int (*read)(struct snd_soc_codec *, unsigned int); + int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + +Codec hardware IO functions - usually points to either the I2C, SPI or AC97 +read/write:- + + hw_write_t hw_write; + hw_read_t hw_read; + + +3 - Mixers and audio controls +----------------------------- +All the codec mixers and audio controls can be defined using the convenience +macros defined in soc.h. + + #define SOC_SINGLE(xname, reg, shift, mask, invert) + +Defines a single control as follows:- + + xname = Control name e.g. "Playback Volume" + reg = codec register + shift = control bit(s) offset in register + mask = control bit size(s) e.g. mask of 7 = 3 bits + invert = the control is inverted + +Other macros include:- + + #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) + +A stereo control + + #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) + +A stereo control spanning 2 registers + + #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) + +Defines an single enumerated control as follows:- + + xreg = register + xshift = control bit(s) offset in register + xmask = control bit(s) size + xtexts = pointer to array of strings that describe each setting + + #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) + +Defines a stereo enumerated control + + +4 - Codec Audio Operations +-------------------------- +The codec driver also supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); +}; + +Please refer to the alsa driver PCM documentation for details. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + + +5 - DAPM description. +--------------------- +The Dynamic Audio Power Management description describes the codec's power +components, their relationships and registers to the ASoC core. Please read +dapm.txt for details of building the description. + +Please also see the examples in other codec drivers. + + +6 - DAPM event handler +---------------------- +This function is a callback that handles codec domain PM calls and system +domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep +when not in use. + +Power states:- + + SNDRV_CTL_POWER_D0: /* full On */ + /* vref/mid, clk and osc on, active */ + + SNDRV_CTL_POWER_D1: /* partial On */ + SNDRV_CTL_POWER_D2: /* partial On */ + + SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* everything off except vref/vmid, inactive */ + + SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ + + +7 - Codec DAC digital mute control. +------------------------------------ +Most codecs have a digital mute before the DAC's that can be used to minimise +any system noise. The mute stops any digital data from entering the DAC. + +A callback can be created that is called by the core for each codec DAI when the +mute is applied or freed. + +i.e. + +static int wm8974_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; + if(mute) + wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); + else + wm8974_write(codec, WM8974_DAC, mute_reg); + return 0; +} diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt new file mode 100644 index 000000000000..c11877f5b4a1 --- /dev/null +++ b/Documentation/sound/alsa/soc/dapm.txt @@ -0,0 +1,297 @@ +Dynamic Audio Power Management for Portable Devices +=================================================== + +1. Description +============== + +Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices +to use the minimum amount of power within the audio subsystem at all times. It +is independent of other kernel PM and as such, can easily co-exist with the +other PM systems. + +DAPM is also completely transparent to all user space applications as all power +switching is done within the ASoC core. No code changes or recompiling are +required for user space applications. DAPM makes power switching descisions based +upon any audio stream (capture/playback) activity and audio mixer settings +within the device. + +DAPM spans the whole machine. It covers power control within the entire audio +subsystem, this includes internal codec power blocks and machine level power +systems. + +There are 4 power domains within DAPM + + 1. Codec domain - VREF, VMID (core codec and audio power) + Usually controlled at codec probe/remove and suspend/resume, although + can be set at stream time if power is not needed for sidetone, etc. + + 2. Platform/Machine domain - physically connected inputs and outputs + Is platform/machine and user action specific, is configured by the + machine driver and responds to asynchronous events e.g when HP + are inserted + + 3. Path domain - audio susbsystem signal paths + Automatically set when mixer and mux settings are changed by the user. + e.g. alsamixer, amixer. + + 4. Stream domain - DAC's and ADC's. + Enabled and disabled when stream playback/capture is started and + stopped respectively. e.g. aplay, arecord. + +All DAPM power switching descisons are made automatically by consulting an audio +routing map of the whole machine. This map is specific to each machine and +consists of the interconnections between every audio component (including +internal codec components). All audio components that effect power are called +widgets hereafter. + + +2. DAPM Widgets +=============== + +Audio DAPM widgets fall into a number of types:- + + o Mixer - Mixes several analog signals into a single analog signal. + o Mux - An analog switch that outputs only 1 of it's inputs. + o PGA - A programmable gain amplifier or attenuation widget. + o ADC - Analog to Digital Converter + o DAC - Digital to Analog Converter + o Switch - An analog switch + o Input - A codec input pin + o Output - A codec output pin + o Headphone - Headphone (and optional Jack) + o Mic - Mic (and optional Jack) + o Line - Line Input/Output (and optional Jack) + o Speaker - Speaker + o Pre - Special PRE widget (exec before all others) + o Post - Special POST widget (exec after all others) + +(Widgets are defined in include/sound/soc-dapm.h) + +Widgets are usually added in the codec driver and the machine driver. There are +convience macros defined in soc-dapm.h that can be used to quickly build a +list of widgets of the codecs and machines DAPM widgets. + +Most widgets have a name, register, shift and invert. Some widgets have extra +parameters for stream name and kcontrols. + + +2.1 Stream Domain Widgets +------------------------- + +Stream Widgets relate to the stream power domain and only consist of ADC's +(analog to digital converters) and DAC's (digital to analog converters). + +Stream widgets have the following format:- + +SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), + +NOTE: the stream name must match the corresponding stream name in your codecs +snd_soc_codec_dai. + +e.g. stream widgets for HiFi playback and capture + +SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), +SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), + + +2.2 Path Domain Widgets +----------------------- + +Path domain widgets have a ability to control or effect the audio signal or +audio paths within the audio subsystem. They have the following form:- + +SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls) + +Any widget kcontrols can be set using the controls and num_controls members. + +e.g. Mixer widget (the kcontrols are declared first) + +/* Output Mixer */ +static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), +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)), + + +2.3 Platform/Machine domain Widgets +----------------------------------- + +Machine widgets are different from codec widgets in that they don't have a +codec register bit associated with them. A machine widget is assigned to each +machine audio component (non codec) that can be independently powered. e.g. + + o Speaker Amp + o Microphone Bias + o Jack connectors + +A machine widget can have an optional call back. + +e.g. Jack connector widget for an external Mic that enables Mic Bias +when the Mic is inserted:- + +static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) +{ + if(SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + else + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + + return 0; +} + +SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), + + +2.4 Codec Domain +---------------- + +The Codec power domain has no widgets and is handled by the codecs DAPM event +handler. This handler is called when the codec powerstate is changed wrt to any +stream event or by kernel PM events. + + +2.5 Virtual Widgets +------------------- + +Sometimes widgets exist in the codec or machine audio map that don't have any +corresponding register bit for power control. In this case it's necessary to +create a virtual widget - a widget with no control bits e.g. + +SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), + +This can be used to merge to signal paths together in software. + +After all the widgets have been defined, they can then be added to the DAPM +subsystem individually with a call to snd_soc_dapm_new_control(). + + +3. Codec Widget Interconnections +================================ + +Widgets are connected to each other within the codec and machine by audio +paths (called interconnections). Each interconnection must be defined in order +to create a map of all audio paths between widgets. +This is easiest with a diagram of the codec (and schematic of the machine audio +system), as it requires joining widgets together via their audio signal paths. + +i.e. from the WM8731 codec's output mixer (wm8731.c) + +The WM8731 output mixer has 3 inputs (sources) + + 1. Line Bypass Input + 2. DAC (HiFi playback) + 3. Mic Sidetone Input + +Each input in this example has a kcontrol associated with it (defined in example +above) and is connected to the output mixer via it's kcontrol name. We can now +connect the destination widget (wrt audio signal) with it's source widgets. + + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, + {"Output Mixer", "HiFi Playback Switch", "DAC"}, + {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, + +So we have :- + + Destination Widget <=== Path Name <=== Source Widget + +Or:- + + Sink, Path, Source + +Or :- + + "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch". + +When there is no path name connecting widgets (e.g. a direct connection) we +pass NULL for the path name. + +Interconnections are created with a call to:- + +snd_soc_dapm_connect_input(codec, sink, path, source); + +Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and +interconnections have been registered with the core. This causes the core to +scan the codec and machine so that the internal DAPM state matches the +physical state of the machine. + + +3.1 Machine Widget Interconnections +----------------------------------- +Machine widget interconnections are created in the same way as codec ones and +directly connect the codec pins to machine level widgets. + +e.g. connects the speaker out codec pins to the internal speaker. + + /* ext speaker connected to codec pins LOUT2, ROUT2 */ + {"Ext Spk", NULL , "ROUT2"}, + {"Ext Spk", NULL , "LOUT2"}, + +This allows the DAPM to power on and off pins that are connected (and in use) +and pins that are NC respectively. + + +4 Endpoint Widgets +=================== +An endpoint is a start or end point (widget) of an audio signal within the +machine and includes the codec. e.g. + + o Headphone Jack + o Internal Speaker + o Internal Mic + o Mic Jack + o Codec Pins + +When a codec pin is NC it can be marked as not used with a call to + +snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); + +The last argument is 0 for inactive and 1 for active. This way the pin and its +input widget will never be powered up and consume power. + +This also applies to machine widgets. e.g. if a headphone is connected to a +jack then the jack can be marked active. If the headphone is removed, then +the headphone jack can be marked inactive. + + +5 DAPM Widget Events +==================== + +Some widgets can register their interest with the DAPM core in PM events. +e.g. A Speaker with an amplifier registers a widget so the amplifier can be +powered only when the spk is in use. + +/* turn speaker amplifier on/off depending on use */ +static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + + return 0; +} + +/* corgi machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8731_dapm_widgets = + SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event); + +Please see soc-dapm.h for all other widgets that support events. + + +5.1 Event types +--------------- + +The following event types are supported by event widgets. + +/* dapm event types */ +#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ +#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ +#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ +#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ +#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ +#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt new file mode 100644 index 000000000000..72bd222f2a21 --- /dev/null +++ b/Documentation/sound/alsa/soc/machine.txt @@ -0,0 +1,113 @@ +ASoC Machine Driver +=================== + +The ASoC machine (or board) driver is the code that glues together the platform +and codec drivers. + +The machine driver can contain codec and platform specific code. It registers +the audio subsystem with the kernel as a platform device and is represented by +the following struct:- + +/* SoC machine */ +struct snd_soc_machine { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + + /* the pre and post PM functions are used to do any PM work before and + * after the codec and DAI's do any PM work. */ + int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); + int (*suspend_post)(struct platform_device *pdev, pm_message_t state); + int (*resume_pre)(struct platform_device *pdev); + int (*resume_post)(struct platform_device *pdev); + + /* machine stream operations */ + struct snd_soc_ops *ops; + + /* CPU <--> Codec DAI links */ + struct snd_soc_dai_link *dai_link; + int num_links; +}; + +probe()/remove() +---------------- +probe/remove are optional. Do any machine specific probe here. + + +suspend()/resume() +------------------ +The machine driver has pre and post versions of suspend and resume to take care +of any machine audio tasks that have to be done before or after the codec, DAI's +and DMA is suspended and resumed. Optional. + + +Machine operations +------------------ +The machine specific audio operations can be set here. Again this is optional. + + +Machine DAI Configuration +------------------------- +The machine DAI configuration glues all the codec and CPU DAI's together. It can +also be used to set up the DAI system clock and for any machine related DAI +initialisation e.g. the machine audio map can be connected to the codec audio +map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c +for examples. + +struct snd_soc_dai_link is used to set up each DAI in your machine. e.g. + +/* corgi digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link corgi_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8731_dai, + .init = corgi_wm8731_init, + .ops = &corgi_ops, +}; + +struct snd_soc_machine then sets up the machine with it's DAI's. e.g. + +/* corgi audio machine driver */ +static struct snd_soc_machine snd_soc_machine_corgi = { + .name = "Corgi", + .dai_link = &corgi_dai, + .num_links = 1, +}; + + +Machine Audio Subsystem +----------------------- + +The machine soc device glues the platform, machine and codec driver together. +Private data can also be set here. e.g. + +/* corgi audio private data */ +static struct wm8731_setup_data corgi_wm8731_setup = { + .i2c_address = 0x1b, +}; + +/* corgi audio subsystem */ +static struct snd_soc_device corgi_snd_devdata = { + .machine = &snd_soc_machine_corgi, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &corgi_wm8731_setup, +}; + + +Machine Power Map +----------------- + +The machine driver can optionally extend the codec power map and to become an +audio power map of the audio subsystem. This allows for automatic power up/down +of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack +sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for +details. + + +Machine Controls +---------------- + +Machine specific audio mixer controls can be added in the dai init function.
\ No newline at end of file diff --git a/Documentation/sound/alsa/soc/overview.txt b/Documentation/sound/alsa/soc/overview.txt new file mode 100644 index 000000000000..753c5cc5984a --- /dev/null +++ b/Documentation/sound/alsa/soc/overview.txt @@ -0,0 +1,83 @@ +ALSA SoC Layer +============== + +The overall project goal of the ALSA System on Chip (ASoC) layer is to provide +better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00, +iMX, etc) and portable audio codecs. Currently there is some support in the +kernel for SoC audio, however it has some limitations:- + + * Currently, codec drivers are often tightly coupled to the underlying SoC + cpu. This is not ideal and leads to code duplication i.e. Linux now has 4 + different wm8731 drivers for 4 different SoC platforms. + + * There is no standard method to signal user initiated audio events. + e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion + event. These are quite common events on portable devices and ofter require + machine specific code to re route audio, enable amps etc after such an event. + + * Current drivers tend to power up the entire codec when playing + (or recording) audio. This is fine for a PC, but tends to waste a lot of + power on portable devices. There is also no support for saving power via + changing codec oversampling rates, bias currents, etc. + + +ASoC Design +=========== + +The ASoC layer is designed to address these issues and provide the following +features :- + + * Codec independence. Allows reuse of codec drivers on other platforms + and machines. + + * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface + and codec registers it's audio interface capabilities with the core and are + subsequently matched and configured when the application hw params are known. + + * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to + it's minimum power state at all times. This includes powering up/down + internal power blocks depending on the internal codec audio routing and any + active streams. + + * Pop and click reduction. Pops and clicks can be reduced by powering the + codec up/down in the correct sequence (including using digital mute). ASoC + signals the codec when to change power states. + + * Machine specific controls: Allow machines to add controls to the sound card + e.g. volume control for speaker amp. + +To achieve all this, ASoC basically splits an embedded audio system into 3 +components :- + + * Codec driver: The codec driver is platform independent and contains audio + controls, audio interface capabilities, codec dapm definition and codec IO + functions. + + * Platform driver: The platform driver contains the audio dma engine and audio + interface drivers (e.g. I2S, AC97, PCM) for that platform. + + * Machine driver: The machine driver handles any machine specific controls and + audio events. i.e. turing on an amp at start of playback. + + +Documentation +============= + +The documentation is spilt into the following sections:- + +overview.txt: This file. + +codec.txt: Codec driver internals. + +DAI.txt: Description of Digital Audio Interface standards and how to configure +a DAI within your codec and CPU DAI drivers. + +dapm.txt: Dynamic Audio Power Management + +platform.txt: Platform audio DMA and DAI. + +machine.txt: Machine driver internals. + +pop_clicks.txt: How to minimise audio artifacts. + +clocking.txt: ASoC clocking for best power performance.
\ No newline at end of file diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt new file mode 100644 index 000000000000..e95b16d5a53b --- /dev/null +++ b/Documentation/sound/alsa/soc/platform.txt @@ -0,0 +1,58 @@ +ASoC Platform Driver +==================== + +An ASoC platform driver can be divided into audio DMA and SoC DAI configuration +and control. The platform drivers only target the SoC CPU and must have no board +specific code. + +Audio DMA +========= + +The platform DMA driver optionally supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); + int (*trigger)(struct snd_pcm_substream *, int); +}; + +The platform driver exports it's DMA functionailty via struct snd_soc_platform:- + +struct snd_soc_platform { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *); + void (*pcm_free)(struct snd_pcm *); + + /* platform stream ops */ + struct snd_pcm_ops *pcm_ops; +}; + +Please refer to the alsa driver documentation for details of audio DMA. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + +An example DMA driver is soc/pxa/pxa2xx-pcm.c + + +SoC DAI Drivers +=============== + +Each SoC DAI driver must provide the following features:- + + 1) Digital audio interface (DAI) description + 2) Digital audio interface configuration + 3) PCM's description + 4) Sysclk configuration + 5) Suspend and resume (optional) + +Please see codec.txt for a description of items 1 - 4. diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt new file mode 100644 index 000000000000..2cf7ee5b3d74 --- /dev/null +++ b/Documentation/sound/alsa/soc/pops_clicks.txt @@ -0,0 +1,52 @@ +Audio Pops and Clicks +===================== + +Pops and clicks are unwanted audio artifacts caused by the powering up and down +of components within the audio subsystem. This is noticable on PC's when an +audio module is either loaded or unloaded (at module load time the sound card is +powered up and causes a popping noise on the speakers). + +Pops and clicks can be more frequent on portable systems with DAPM. This is +because the components within the subsystem are being dynamically powered +depending on the audio usage and this can subsequently cause a small pop or +click every time a component power state is changed. + + +Minimising Playback Pops and Clicks +=================================== + +Playback pops in portable audio subsystems cannot be completely eliminated atm, +however future audio codec hardware will have better pop and click supression. +Pops can be reduced within playback by powering the audio components in a +specific order. This order is different for startup and shutdown and follows +some basic rules:- + + Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute + + Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC + +This assumes that the codec PCM output path from the DAC is via a mixer and then +a PGA (programmable gain amplifier) before being output to the speakers. + + +Minimising Capture Pops and Clicks +================================== + +Capture artifacts are somewhat easier to get rid as we can delay activating the +ADC until all the pops have occured. This follows similar power rules to +playback in that components are powered in a sequence depending upon stream +startup or shutdown. + + Startup Order - Input PGA --> Mixers --> ADC + + Shutdown Order - ADC --> Mixers --> Input PGA + + +Zipper Noise +============ +An unwanted zipper noise can occur within the audio playback or capture stream +when a volume control is changed near its maximum gain value. The zipper noise +is heard when the gain increase or decrease changes the mean audio signal +amplitude too quickly. It can be minimised by enabling the zero cross setting +for each volume control. The ZC forces the gain change to occur when the signal +crosses the zero amplitude line. diff --git a/MAINTAINERS b/MAINTAINERS index 6ddae2bb6821..f2a79481f1c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3037,6 +3037,12 @@ M: perex@suse.cz L: alsa-devel@alsa-project.org S: Maintained +SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT +P: Liam Girdwood +M: liam.girdwood@wolfsonmicro.com +L: alsa-devel@alsa-project.org +S: Supported + SPI SUBSYSTEM P: David Brownell M: dbrownell@users.sourceforge.net diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 4358a0a78eaa..c7db4032ef02 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -83,7 +83,7 @@ struct ucb1400 { - ac97_t *ac97; + struct snd_ac97 *ac97; struct input_dev *ts_idev; int irq; diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index d38778f2fbec..6e7ec4c76178 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -115,6 +115,8 @@ #define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */ #define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */ #define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */ +#define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */ +#define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 33720397a904..246ac23534bd 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -375,6 +375,7 @@ #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */ #define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */ #define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */ +#define AC97_SCAP_POWER_SAVE (1<<11) /* capable for aggresive power-saving */ /* ac97->flags */ #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ @@ -425,6 +426,7 @@ struct snd_ac97_build_ops { struct snd_ac97_bus_ops { void (*reset) (struct snd_ac97 *ac97); + void (*warm_reset)(struct snd_ac97 *ac97); void (*write) (struct snd_ac97 *ac97, unsigned short reg, unsigned short val); unsigned short (*read) (struct snd_ac97 *ac97, unsigned short reg); void (*wait) (struct snd_ac97 *ac97); @@ -501,6 +503,7 @@ struct snd_ac97 { unsigned short id[3]; // codec IDs (lower 16-bit word) unsigned short pcmreg[3]; // PCM registers unsigned short codec_cfg[3]; // CODEC_CFG bits + unsigned char swap_mic_linein; // AD1986/AD1986A only } ad18xx; unsigned int dev_flags; /* device specific */ } spec; @@ -510,7 +513,6 @@ struct snd_ac97 { #ifdef CONFIG_SND_AC97_POWER_SAVE unsigned int power_up; /* power states */ - struct workqueue_struct *power_workq; struct delayed_work power_work; #endif struct device dev; diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h index c8de6f83338f..b2c3f00a9b35 100644 --- a/include/sound/ad1848.h +++ b/include/sound/ad1848.h @@ -185,7 +185,7 @@ struct ad1848_mix_elem { int index; int type; unsigned long private_value; - unsigned int *tlv; + const unsigned int *tlv; }; #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \ diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h index 2ee061625fd0..c149d3b2558b 100644 --- a/include/sound/ak4114.h +++ b/include/sound/ak4114.h @@ -181,7 +181,6 @@ struct ak4114 { unsigned long ccrc_errors; unsigned char rcs0; unsigned char rcs1; - struct workqueue_struct *workqueue; struct delayed_work work; void *change_callback_private; void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1); @@ -189,7 +188,7 @@ struct ak4114 { int snd_ak4114_create(struct snd_card *card, ak4114_read_t *read, ak4114_write_t *write, - unsigned char pgm[7], unsigned char txcsb[5], + const unsigned char pgm[7], const unsigned char txcsb[5], void *private_data, struct ak4114 **r_ak4114); void snd_ak4114_reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char mask, unsigned char val); void snd_ak4114_reinit(struct ak4114 *ak4114); diff --git a/include/sound/ak4117.h b/include/sound/ak4117.h index 2b96c32f06fd..d650d52e3d29 100644 --- a/include/sound/ak4117.h +++ b/include/sound/ak4117.h @@ -178,7 +178,7 @@ struct ak4117 { }; int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, - unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117); + const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117); void snd_ak4117_reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char mask, unsigned char val); void snd_ak4117_reinit(struct ak4117 *ak4117); int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *capture_substream); diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h index d0deca669b92..aa49dda4f410 100644 --- a/include/sound/ak4xxx-adda.h +++ b/include/sound/ak4xxx-adda.h @@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel { char *name; /* capture gain volume label */ char *switch_name; /* capture switch */ unsigned int num_channels; + char *selector_name; /* capture source select label */ + const char **input_names; /* capture source names (NULL terminated) */ }; struct snd_akm4xxx { @@ -69,8 +71,8 @@ struct snd_akm4xxx { } type; /* (array) information of combined codecs */ - struct snd_akm4xxx_dac_channel *dac_info; - struct snd_akm4xxx_adc_channel *adc_info; + const struct snd_akm4xxx_dac_channel *dac_info; + const struct snd_akm4xxx_adc_channel *adc_info; struct snd_ak4xxx_ops ops; }; diff --git a/include/sound/control.h b/include/sound/control.h index 1de148b0fd94..72e759f619b1 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -49,7 +49,7 @@ struct snd_kcontrol_new { snd_kcontrol_put_t *put; union { snd_kcontrol_tlv_rw_t *c; - unsigned int *p; + const unsigned int *p; } tlv; unsigned long private_value; }; @@ -69,7 +69,7 @@ struct snd_kcontrol { snd_kcontrol_put_t *put; union { snd_kcontrol_tlv_rw_t *c; - unsigned int *p; + const unsigned int *p; } tlv; unsigned long private_value; void *private_data; @@ -108,7 +108,6 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card, void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id); -struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol * kcontrol, unsigned int access); struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data); void snd_ctl_free_one(struct snd_kcontrol * kcontrol); int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol); diff --git a/include/sound/core.h b/include/sound/core.h index 521f036cce99..4b9e609975ab 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -211,9 +211,40 @@ extern struct class *sound_class; void snd_request_card(int card); -int snd_register_device(int type, struct snd_card *card, int dev, - const struct file_operations *f_ops, void *private_data, - const char *name); +int snd_register_device_for_dev(int type, struct snd_card *card, + int dev, + const struct file_operations *f_ops, + void *private_data, + const char *name, + struct device *device); + +/** + * snd_register_device - Register the ALSA device file for the card + * @type: the device type, SNDRV_DEVICE_TYPE_XXX + * @card: the card instance + * @dev: the device index + * @f_ops: the file operations + * @private_data: user pointer for f_ops->open() + * @name: the device file name + * + * Registers an ALSA device file for the given card. + * The operators have to be set in reg parameter. + * + * This function uses the card's device pointer to link to the + * correct &struct device. + * + * Returns zero if successful, or a negative error code on failure. + */ +static inline int snd_register_device(int type, struct snd_card *card, int dev, + const struct file_operations *f_ops, + void *private_data, + const char *name) +{ + return snd_register_device_for_dev(type, card, dev, f_ops, + private_data, name, + snd_card_get_device_link(card)); +} + int snd_unregister_device(int type, struct snd_card *card, int dev); void *snd_lookup_minor_data(unsigned int minor, int type); int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, @@ -396,6 +427,29 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) #endif #endif -#include "typedefs.h" +/* PCI quirk list helper */ +struct snd_pci_quirk { + unsigned short subvendor; /* PCI subvendor ID */ + unsigned short subdevice; /* PCI subdevice ID */ + int value; /* value */ +#ifdef CONFIG_SND_DEBUG_DETECT + const char *name; /* name of the device (optional) */ +#endif +}; + +#define _SND_PCI_QUIRK_ID(vend,dev) \ + .subvendor = (vend), .subdevice = (dev) +#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)} +#ifdef CONFIG_SND_DEBUG_DETECT +#define SND_PCI_QUIRK(vend,dev,xname,val) \ + {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)} +#else +#define SND_PCI_QUIRK(vend,dev,xname,val) \ + {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)} +#endif + +const struct snd_pci_quirk * +snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); + #endif /* __SOUND_CORE_H */ diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 3d3c1514cf71..eb7ce96ddf3a 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -188,7 +188,35 @@ #define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */ /* NOTE: The rest of the bits in this register */ /* _are_ relevant under Linux. */ -#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */ +#define HCFG_PUSH_BUTTON_ENABLE 0x00100000 /* Enables Volume Inc/Dec and Mute functions */ +#define HCFG_BAUD_RATE 0x00080000 /* 0 = 48kHz, 1 = 44.1kHz */ +#define HCFG_EXPANDED_MEM 0x00040000 /* 1 = any 16M of 4G addr, 0 = 32M of 2G addr */ +#define HCFG_CODECFORMAT_MASK 0x00030000 /* CODEC format */ + +/* Specific to Alice2, CA0102 */ +#define HCFG_CODECFORMAT_AC97_1 0x00000000 /* AC97 CODEC format -- Ver 1.03 */ +#define HCFG_CODECFORMAT_AC97_2 0x00010000 /* AC97 CODEC format -- Ver 2.1 */ +#define HCFG_AUTOMUTE_ASYNC 0x00008000 /* When set, the async sample rate convertors */ + /* will automatically mute their output when */ + /* they are not rate-locked to the external */ + /* async audio source */ +#define HCFG_AUTOMUTE_SPDIF 0x00004000 /* When set, the async sample rate convertors */ + /* will automatically mute their output when */ + /* the SPDIF V-bit indicates invalid audio */ +#define HCFG_EMU32_SLAVE 0x00002000 /* 0 = Master, 1 = Slave. Slave for EMU1010 */ +#define HCFG_SLOW_RAMP 0x00001000 /* Increases Send Smoothing time constant */ +/* 0x00000800 not used on Alice2 */ +#define HCFG_PHASE_TRACK_MASK 0x00000700 /* When set, forces corresponding input to */ + /* phase track the previous input. */ + /* I2S0 can phase track the last S/PDIF input */ +#define HCFG_I2S_ASRC_ENABLE 0x00000070 /* When set, enables asynchronous sample rate */ + /* conversion for the corresponding */ + /* I2S format input */ +/* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc. */ + + + +/* Older chips */ #define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */ #define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */ #define HCFG_GPINPUT0 0x00004000 /* External pin112 */ @@ -432,6 +460,7 @@ #define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */ #define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */ +#define A_HR 0x0b /* High Resolution. 24bit playback from host to DSP. */ #define MAPA 0x0c /* Cache map A */ #define MAPB 0x0d /* Cache map B */ @@ -439,6 +468,8 @@ #define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ #define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ +/* 0x0e, 0x0f: Not used */ + #define ENVVOL 0x10 /* Volume envelope register */ #define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */ /* 0x8000-n == 666*n usec delay */ @@ -527,7 +558,7 @@ /* NOTE: All channels contain internal variables; do */ /* not write to these locations. */ -/* 1f something */ +/* 0x1f: not used */ #define CD0 0x20 /* Cache data 0 register */ #define CD1 0x21 /* Cache data 1 register */ @@ -597,6 +628,8 @@ #define FXWC_SPDIFLEFT (1<<22) /* 0x00400000 */ #define FXWC_SPDIFRIGHT (1<<23) /* 0x00800000 */ +#define A_TBLSZ ` 0x43 /* Effects Tank Internal Table Size. Only low byte or register used */ + #define TCBS 0x44 /* Tank cache buffer size register */ #define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ #define TCBS_BUFFSIZE_16K 0x00000000 @@ -617,7 +650,7 @@ #define FXBA 0x47 /* FX Buffer Address */ #define FXBA_MASK 0xfffff000 /* 20 bit base address */ -/* 0x48 something - word access, defaults to 3f */ +#define A_HWM 0x48 /* High PCI Water Mark - word access, defaults to 3f */ #define MICBS 0x49 /* Microphone buffer size register */ @@ -661,6 +694,18 @@ #define ADCBS_BUFSIZE_57344 0x0000001e #define ADCBS_BUFSIZE_65536 0x0000001f +/* Current Send B, A Amounts */ +#define A_CSBA 0x4c + +/* Current Send D, C Amounts */ +#define A_CSDC 0x4d + +/* Current Send F, E Amounts */ +#define A_CSFE 0x4e + +/* Current Send H, G Amounts */ +#define A_CSHG 0x4f + #define CDCS 0x50 /* CD-ROM digital channel status register */ @@ -668,6 +713,9 @@ #define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ +/* S/PDIF Input C Channel Status */ +#define A_SPSC 0x52 + #define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ #define A_DBG 0x53 @@ -708,6 +756,8 @@ #define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */ #define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */ +/* 0x57: Not used */ + /* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */ #define CLIEL 0x58 /* Channel loop interrupt enable low register */ @@ -733,6 +783,9 @@ #define AC97SLOT_CNTR 0x10 /* Center enable */ #define AC97SLOT_LFE 0x20 /* LFE enable */ +/* PCB Revision */ +#define A_PCB 0x5f + // NOTE: 0x60,61,62: 64-bit #define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ @@ -780,9 +833,18 @@ #define HLIPH 0x69 /* Channel half loop interrupt pending high register */ -// 0x6a,6b,6c used for some recording -// 0x6d unused -// 0x6e,6f - tanktable base / offset +/* S/PDIF Host Record Index (bypasses SRC) */ +#define A_SPRI 0x6a +/* S/PDIF Host Record Address */ +#define A_SPRA 0x6b +/* S/PDIF Host Record Control */ +#define A_SPRC 0x6c +/* Delayed Interrupt Counter & Enable */ +#define A_DICE 0x6d +/* Tank Table Base */ +#define A_TTB 0x6e +/* Tank Delay Offset */ +#define A_TDOF 0x6f /* This is the MPU port on the card (via the game port) */ #define A_MUDATA1 0x70 @@ -800,6 +862,7 @@ #define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */ #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ +/* Extended Hardware Control */ #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ #define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */ #define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */ @@ -822,8 +885,20 @@ #define A_PCM_96000 0x00004000 #define A_PCM_44100 0x00008000 -/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */ -/* 0x7a, 0x7b - lookup tables */ +/* I2S0 Sample Rate Tracker Status */ +#define A_SRT3 0x77 + +/* I2S1 Sample Rate Tracker Status */ +#define A_SRT4 0x78 + +/* I2S2 Sample Rate Tracker Status */ +#define A_SRT5 0x79 +/* - default to 0x01080000 on my audigy 2 ZS --rlrevell */ + +/* Tank Table DMA Address */ +#define A_TTDA 0x7a +/* Tank Table DMA Data */ +#define A_TTDD 0x7b #define A_FXRT2 0x7c #define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ @@ -845,7 +920,7 @@ #define A_FXRT_CHANNELC 0x003f0000 #define A_FXRT_CHANNELD 0x3f000000 - +/* 0x7f: Not used */ /* Each FX general purpose register is 32 bits in length, all bits are used */ #define FXGPREGBASE 0x100 /* FX general purpose registers base */ #define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */ @@ -886,6 +961,293 @@ #define A_HIWORD_RESULT_MASK 0x007ff000 #define A_HIWORD_OPA_MASK 0x000007ff +/************************************************************************************************/ +/* EMU1010m HANA FPGA registers */ +/************************************************************************************************/ +#define EMU_HANA_DESTHI 0x00 /* 0000xxx 3 bits Link Destination */ +#define EMU_HANA_DESTLO 0x01 /* 00xxxxx 5 bits */ +#define EMU_HANA_SRCHI 0x02 /* 0000xxx 3 bits Link Source */ +#define EMU_HANA_SRCLO 0x03 /* 00xxxxx 5 bits */ +#define EMU_HANA_DOCK_PWR 0x04 /* 000000x 1 bits Audio Dock power */ +#define EMU_HANA_DOCK_PWR_ON 0x01 /* Audio Dock power on */ +#define EMU_HANA_WCLOCK 0x05 /* 0000xxx 3 bits Word Clock source select */ + /* Must be written after power on to reset DLL */ + /* One is unable to detect the Audio dock without this */ +#define EMU_HANA_WCLOCK_SRC_MASK 0x07 +#define EMU_HANA_WCLOCK_INT_48K 0x00 +#define EMU_HANA_WCLOCK_INT_44_1K 0x01 +#define EMU_HANA_WCLOCK_HANA_SPDIF_IN 0x02 +#define EMU_HANA_WCLOCK_HANA_ADAT_IN 0x03 +#define EMU_HANA_WCLOCK_SYNC_BNCN 0x04 +#define EMU_HANA_WCLOCK_2ND_HANA 0x05 +#define EMU_HANA_WCLOCK_SRC_RESERVED 0x06 +#define EMU_HANA_WCLOCK_OFF 0x07 /* For testing, forces fallback to DEFCLOCK */ +#define EMU_HANA_WCLOCK_MULT_MASK 0x18 +#define EMU_HANA_WCLOCK_1X 0x00 +#define EMU_HANA_WCLOCK_2X 0x08 +#define EMU_HANA_WCLOCK_4X 0x10 +#define EMU_HANA_WCLOCK_MULT_RESERVED 0x18 + +#define EMU_HANA_DEFCLOCK 0x06 /* 000000x 1 bits Default Word Clock */ +#define EMU_HANA_DEFCLOCK_48K 0x00 +#define EMU_HANA_DEFCLOCK_44_1K 0x01 + +#define EMU_HANA_UNMUTE 0x07 /* 000000x 1 bits Mute all audio outputs */ +#define EMU_MUTE 0x00 +#define EMU_UNMUTE 0x01 + +#define EMU_HANA_FPGA_CONFIG 0x08 /* 00000xx 2 bits Config control of FPGAs */ +#define EMU_HANA_FPGA_CONFIG_AUDIODOCK 0x01 /* Set in order to program FPGA on Audio Dock */ +#define EMU_HANA_FPGA_CONFIG_HANA 0x02 /* Set in order to program FPGA on Hana */ + +#define EMU_HANA_IRQ_ENABLE 0x09 /* 000xxxx 4 bits IRQ Enable */ +#define EMU_HANA_IRQ_WCLK_CHANGED 0x01 +#define EMU_HANA_IRQ_ADAT 0x02 +#define EMU_HANA_IRQ_DOCK 0x04 +#define EMU_HANA_IRQ_DOCK_LOST 0x08 + +#define EMU_HANA_SPDIF_MODE 0x0a /* 00xxxxx 5 bits SPDIF MODE */ +#define EMU_HANA_SPDIF_MODE_TX_COMSUMER 0x00 +#define EMU_HANA_SPDIF_MODE_TX_PRO 0x01 +#define EMU_HANA_SPDIF_MODE_TX_NOCOPY 0x02 +#define EMU_HANA_SPDIF_MODE_RX_COMSUMER 0x00 +#define EMU_HANA_SPDIF_MODE_RX_PRO 0x04 +#define EMU_HANA_SPDIF_MODE_RX_NOCOPY 0x08 +#define EMU_HANA_SPDIF_MODE_RX_INVALID 0x10 + +#define EMU_HANA_OPTICAL_TYPE 0x0b /* 00000xx 2 bits ADAT or SPDIF in/out */ +#define EMU_HANA_OPTICAL_IN_SPDIF 0x00 +#define EMU_HANA_OPTICAL_IN_ADAT 0x01 +#define EMU_HANA_OPTICAL_OUT_SPDIF 0x00 +#define EMU_HANA_OPTICAL_OUT_ADAT 0x02 + +#define EMU_HANA_MIDI_IN 0x0c /* 000000x 1 bit Control MIDI */ +#define EMU_HANA_MIDI_IN_FROM_HAMOA 0x00 /* HAMOA MIDI in to Alice 2 MIDI B */ +#define EMU_HANA_MIDI_IN_FROM_DOCK 0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */ + +#define EMU_HANA_DOCK_LEDS_1 0x0d /* 000xxxx 4 bit Audio Dock LEDs */ +#define EMU_HANA_DOCK_LEDS_1_MIDI1 0x01 /* MIDI 1 LED on */ +#define EMU_HANA_DOCK_LEDS_1_MIDI2 0x02 /* MIDI 2 LED on */ +#define EMU_HANA_DOCK_LEDS_1_SMPTE_IN 0x04 /* SMPTE IN LED on */ +#define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT 0x08 /* SMPTE OUT LED on */ + +#define EMU_HANA_DOCK_LEDS_2 0x0e /* 0xxxxxx 6 bit Audio Dock LEDs */ +#define EMU_HANA_DOCK_LEDS_2_44K 0x01 /* 44.1 kHz LED on */ +#define EMU_HANA_DOCK_LEDS_2_48K 0x02 /* 48 kHz LED on */ +#define EMU_HANA_DOCK_LEDS_2_96K 0x04 /* 96 kHz LED on */ +#define EMU_HANA_DOCK_LEDS_2_192K 0x08 /* 192 kHz LED on */ +#define EMU_HANA_DOCK_LEDS_2_LOCK 0x10 /* LOCK LED on */ +#define EMU_HANA_DOCK_LEDS_2_EXT 0x20 /* EXT LED on */ + +#define EMU_HANA_DOCK_LEDS_3 0x0f /* 0xxxxxx 6 bit Audio Dock LEDs */ +#define EMU_HANA_DOCK_LEDS_3_CLIP_A 0x01 /* Mic A Clip LED on */ +#define EMU_HANA_DOCK_LEDS_3_CLIP_B 0x02 /* Mic B Clip LED on */ +#define EMU_HANA_DOCK_LEDS_3_SIGNAL_A 0x04 /* Signal A Clip LED on */ +#define EMU_HANA_DOCK_LEDS_3_SIGNAL_B 0x08 /* Signal B Clip LED on */ +#define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP 0x10 /* Manual Clip detection */ +#define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL 0x20 /* Manual Signal detection */ + +#define EMU_HANA_ADC_PADS 0x10 /* 0000xxx 3 bit Audio Dock ADC 14dB pads */ +#define EMU_HANA_DOCK_ADC_PAD1 0x01 /* 14dB Attenuation on Audio Dock ADC 1 */ +#define EMU_HANA_DOCK_ADC_PAD2 0x02 /* 14dB Attenuation on Audio Dock ADC 2 */ +#define EMU_HANA_DOCK_ADC_PAD3 0x04 /* 14dB Attenuation on Audio Dock ADC 3 */ +#define EMU_HANA_0202_ADC_PAD1 0x08 /* 14dB Attenuation on 0202 ADC 1 */ + +#define EMU_HANA_DOCK_MISC 0x11 /* 0xxxxxx 6 bit Audio Dock misc bits */ +#define EMU_HANA_DOCK_DAC1_MUTE 0x01 /* DAC 1 Mute */ +#define EMU_HANA_DOCK_DAC2_MUTE 0x02 /* DAC 2 Mute */ +#define EMU_HANA_DOCK_DAC3_MUTE 0x04 /* DAC 3 Mute */ +#define EMU_HANA_DOCK_DAC4_MUTE 0x08 /* DAC 4 Mute */ +#define EMU_HANA_DOCK_PHONES_192_DAC1 0x00 /* DAC 1 Headphones source at 192kHz */ +#define EMU_HANA_DOCK_PHONES_192_DAC2 0x10 /* DAC 2 Headphones source at 192kHz */ +#define EMU_HANA_DOCK_PHONES_192_DAC3 0x20 /* DAC 3 Headphones source at 192kHz */ +#define EMU_HANA_DOCK_PHONES_192_DAC4 0x30 /* DAC 4 Headphones source at 192kHz */ + +#define EMU_HANA_MIDI_OUT 0x12 /* 00xxxxx 5 bit Source for each MIDI out port */ +#define EMU_HANA_MIDI_OUT_0202 0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */ +#define EMU_HANA_MIDI_OUT_DOCK1 0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */ +#define EMU_HANA_MIDI_OUT_DOCK2 0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */ +#define EMU_HANA_MIDI_OUT_SYNC2 0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */ +#define EMU_HANA_MIDI_OUT_LOOP 0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */ + +#define EMU_HANA_DAC_PADS 0x13 /* 00xxxxx 5 bit DAC 14dB attenuation pads */ +#define EMU_HANA_DOCK_DAC_PAD1 0x01 /* 14dB Attenuation on AudioDock DAC 1. Left and Right */ +#define EMU_HANA_DOCK_DAC_PAD2 0x02 /* 14dB Attenuation on AudioDock DAC 2. Left and Right */ +#define EMU_HANA_DOCK_DAC_PAD3 0x04 /* 14dB Attenuation on AudioDock DAC 3. Left and Right */ +#define EMU_HANA_DOCK_DAC_PAD4 0x08 /* 14dB Attenuation on AudioDock DAC 4. Left and Right */ +#define EMU_HANA_0202_DAC_PAD1 0x10 /* 14dB Attenuation on 0202 DAC 1. Left and Right */ + +/* 0x14 - 0x1f Unused R/W registers */ +#define EMU_HANA_IRQ_STATUS 0x20 /* 000xxxx 4 bits IRQ Status */ +#if 0 /* Already defined for reg 0x09 IRQ_ENABLE */ +#define EMU_HANA_IRQ_WCLK_CHANGED 0x01 +#define EMU_HANA_IRQ_ADAT 0x02 +#define EMU_HANA_IRQ_DOCK 0x04 +#define EMU_HANA_IRQ_DOCK_LOST 0x08 +#endif + +#define EMU_HANA_OPTION_CARDS 0x21 /* 000xxxx 4 bits Presence of option cards */ +#define EMU_HANA_OPTION_HAMOA 0x01 /* HAMOA card present */ +#define EMU_HANA_OPTION_SYNC 0x02 /* Sync card present */ +#define EMU_HANA_OPTION_DOCK_ONLINE 0x04 /* Audio Dock online and FPGA configured */ +#define EMU_HANA_OPTION_DOCK_OFFLINE 0x08 /* Audio Dock online and FPGA not configured */ + +#define EMU_HANA_ID 0x22 /* 1010101 7 bits ID byte & 0x7f = 0x55 */ + +#define EMU_HANA_MAJOR_REV 0x23 /* 0000xxx 3 bit Hana FPGA Major rev */ +#define EMU_HANA_MINOR_REV 0x24 /* 0000xxx 3 bit Hana FPGA Minor rev */ + +#define EMU_DOCK_MAJOR_REV 0x25 /* 0000xxx 3 bit Audio Dock FPGA Major rev */ +#define EMU_DOCK_MINOR_REV 0x26 /* 0000xxx 3 bit Audio Dock FPGA Minor rev */ + +#define EMU_DOCK_BOARD_ID 0x27 /* 00000xx 2 bits Audio Dock ID pins */ +#define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */ +#define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */ + +#define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */ +#define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */ + +#define EMU_HANA_WC_ADAT_HI 0x2a /* 0xxxxxx 6 bit ADAT IN Word clock, upper 6 bits */ +#define EMU_HANA_WC_ADAT_LO 0x2b /* 0xxxxxx 6 bit ADAT IN Word clock, lower 6 bits */ + +#define EMU_HANA_WC_BNC_LO 0x2c /* 0xxxxxx 6 bit BNC IN Word clock, lower 6 bits */ +#define EMU_HANA_WC_BNC_HI 0x2d /* 0xxxxxx 6 bit BNC IN Word clock, upper 6 bits */ + +#define EMU_HANA2_WC_SPDIF_HI 0x2e /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, upper 6 bits */ +#define EMU_HANA2_WC_SPDIF_LO 0x2f /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, lower 6 bits */ +/* 0x30 - 0x3f Unused Read only registers */ + +/************************************************************************************************/ +/* EMU1010m HANA Destinations */ +/************************************************************************************************/ +#define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_3 0x0002 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_4 0x0003 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_5 0x0004 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_6 0x0005 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_7 0x0006 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_8 0x0007 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_9 0x0008 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_A 0x0009 /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_B 0x000a /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_C 0x000b /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_D 0x000c /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_E 0x000d /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_ALICE2_EMU32_F 0x000e /* 16 EMU32 channels to Alice2 +0 to +0xf */ +#define EMU_DST_DOCK_DAC1_LEFT1 0x0100 /* Audio Dock DAC1 Left, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC1_LEFT2 0x0101 /* Audio Dock DAC1 Left, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC1_LEFT3 0x0102 /* Audio Dock DAC1 Left, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC1_LEFT4 0x0103 /* Audio Dock DAC1 Left, 4th or 192kHz */ +#define EMU_DST_DOCK_DAC1_RIGHT1 0x0104 /* Audio Dock DAC1 Right, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC1_RIGHT2 0x0105 /* Audio Dock DAC1 Right, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC1_RIGHT3 0x0106 /* Audio Dock DAC1 Right, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC1_RIGHT4 0x0107 /* Audio Dock DAC1 Right, 4th or 192kHz */ +#define EMU_DST_DOCK_DAC2_LEFT1 0x0108 /* Audio Dock DAC2 Left, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC2_LEFT2 0x0109 /* Audio Dock DAC2 Left, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC2_LEFT3 0x010a /* Audio Dock DAC2 Left, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC2_LEFT4 0x010b /* Audio Dock DAC2 Left, 4th or 192kHz */ +#define EMU_DST_DOCK_DAC2_RIGHT1 0x010c /* Audio Dock DAC2 Right, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC2_RIGHT2 0x010d /* Audio Dock DAC2 Right, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC2_RIGHT3 0x010e /* Audio Dock DAC2 Right, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC2_RIGHT4 0x010f /* Audio Dock DAC2 Right, 4th or 192kHz */ +#define EMU_DST_DOCK_DAC3_LEFT1 0x0110 /* Audio Dock DAC1 Left, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC3_LEFT2 0x0111 /* Audio Dock DAC1 Left, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC3_LEFT3 0x0112 /* Audio Dock DAC1 Left, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC3_LEFT4 0x0113 /* Audio Dock DAC1 Left, 4th or 192kHz */ +#define EMU_DST_DOCK_PHONES_LEFT1 0x0112 /* Audio Dock PHONES Left, 1st or 48kHz only */ +#define EMU_DST_DOCK_PHONES_LEFT2 0x0113 /* Audio Dock PHONES Left, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC3_RIGHT1 0x0114 /* Audio Dock DAC1 Right, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC3_RIGHT2 0x0115 /* Audio Dock DAC1 Right, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC3_RIGHT3 0x0116 /* Audio Dock DAC1 Right, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC3_RIGHT4 0x0117 /* Audio Dock DAC1 Right, 4th or 192kHz */ +#define EMU_DST_DOCK_PHONES_RIGHT1 0x0116 /* Audio Dock PHONES Right, 1st or 48kHz only */ +#define EMU_DST_DOCK_PHONES_RIGHT2 0x0117 /* Audio Dock PHONES Right, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC4_LEFT1 0x0118 /* Audio Dock DAC2 Left, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC4_LEFT2 0x0119 /* Audio Dock DAC2 Left, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC4_LEFT3 0x011a /* Audio Dock DAC2 Left, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC4_LEFT4 0x011b /* Audio Dock DAC2 Left, 4th or 192kHz */ +#define EMU_DST_DOCK_SPDIF_LEFT1 0x011a /* Audio Dock SPDIF Left, 1st or 48kHz only */ +#define EMU_DST_DOCK_SPDIF_LEFT2 0x011b /* Audio Dock SPDIF Left, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC4_RIGHT1 0x011c /* Audio Dock DAC2 Right, 1st or 48kHz only */ +#define EMU_DST_DOCK_DAC4_RIGHT2 0x011d /* Audio Dock DAC2 Right, 2nd or 96kHz */ +#define EMU_DST_DOCK_DAC4_RIGHT3 0x011e /* Audio Dock DAC2 Right, 3rd or 192kHz */ +#define EMU_DST_DOCK_DAC4_RIGHT4 0x011f /* Audio Dock DAC2 Right, 4th or 192kHz */ +#define EMU_DST_DOCK_SPDIF_RIGHT1 0x011e /* Audio Dock SPDIF Right, 1st or 48kHz only */ +#define EMU_DST_DOCK_SPDIF_RIGHT2 0x011f /* Audio Dock SPDIF Right, 2nd or 96kHz */ +#define EMU_DST_HANA_SPDIF_LEFT1 0x0200 /* Hana SPDIF Left, 1st or 48kHz only */ +#define EMU_DST_HANA_SPDIF_LEFT2 0x0202 /* Hana SPDIF Left, 2nd or 96kHz */ +#define EMU_DST_HANA_SPDIF_RIGHT1 0x0201 /* Hana SPDIF Right, 1st or 48kHz only */ +#define EMU_DST_HANA_SPDIF_RIGHT2 0x0203 /* Hana SPDIF Right, 2nd or 96kHz */ +#define EMU_DST_HAMOA_DAC_LEFT1 0x0300 /* Hamoa DAC Left, 1st or 48kHz only */ +#define EMU_DST_HAMOA_DAC_LEFT2 0x0302 /* Hamoa DAC Left, 2nd or 96kHz */ +#define EMU_DST_HAMOA_DAC_LEFT3 0x0304 /* Hamoa DAC Left, 3rd or 192kHz */ +#define EMU_DST_HAMOA_DAC_LEFT4 0x0306 /* Hamoa DAC Left, 4th or 192kHz */ +#define EMU_DST_HAMOA_DAC_RIGHT1 0x0301 /* Hamoa DAC Right, 1st or 48kHz only */ +#define EMU_DST_HAMOA_DAC_RIGHT2 0x0303 /* Hamoa DAC Right, 2nd or 96kHz */ +#define EMU_DST_HAMOA_DAC_RIGHT3 0x0305 /* Hamoa DAC Right, 3rd or 192kHz */ +#define EMU_DST_HAMOA_DAC_RIGHT4 0x0307 /* Hamoa DAC Right, 4th or 192kHz */ +#define EMU_DST_HANA_ADAT 0x0400 /* Hana ADAT 8 channel out +0 to +7 */ +#define EMU_DST_ALICE_I2S0_LEFT 0x0500 /* Alice2 I2S0 Left */ +#define EMU_DST_ALICE_I2S0_RIGHT 0x0501 /* Alice2 I2S0 Right */ +#define EMU_DST_ALICE_I2S1_LEFT 0x0600 /* Alice2 I2S1 Left */ +#define EMU_DST_ALICE_I2S1_RIGHT 0x0601 /* Alice2 I2S1 Right */ +#define EMU_DST_ALICE_I2S2_LEFT 0x0700 /* Alice2 I2S2 Left */ +#define EMU_DST_ALICE_I2S2_RIGHT 0x0701 /* Alice2 I2S2 Right */ + +/************************************************************************************************/ +/* EMU1010m HANA Sources */ +/************************************************************************************************/ +#define EMU_SRC_SILENCE 0x0000 /* Silence */ +#define EMU_SRC_DOCK_MIC_A1 0x0100 /* Audio Dock Mic A, 1st or 48kHz only */ +#define EMU_SRC_DOCK_MIC_A2 0x0101 /* Audio Dock Mic A, 2nd or 96kHz */ +#define EMU_SRC_DOCK_MIC_A3 0x0102 /* Audio Dock Mic A, 3rd or 192kHz */ +#define EMU_SRC_DOCK_MIC_A4 0x0103 /* Audio Dock Mic A, 4th or 192kHz */ +#define EMU_SRC_DOCK_MIC_B1 0x0104 /* Audio Dock Mic B, 1st or 48kHz only */ +#define EMU_SRC_DOCK_MIC_B2 0x0105 /* Audio Dock Mic B, 2nd or 96kHz */ +#define EMU_SRC_DOCK_MIC_B3 0x0106 /* Audio Dock Mic B, 3rd or 192kHz */ +#define EMU_SRC_DOCK_MIC_B4 0x0107 /* Audio Dock Mic B, 4th or 192kHz */ +#define EMU_SRC_DOCK_ADC1_LEFT1 0x0108 /* Audio Dock ADC1 Left, 1st or 48kHz only */ +#define EMU_SRC_DOCK_ADC1_LEFT2 0x0109 /* Audio Dock ADC1 Left, 2nd or 96kHz */ +#define EMU_SRC_DOCK_ADC1_LEFT3 0x010a /* Audio Dock ADC1 Left, 3rd or 192kHz */ +#define EMU_SRC_DOCK_ADC1_LEFT4 0x010b /* Audio Dock ADC1 Left, 4th or 192kHz */ +#define EMU_SRC_DOCK_ADC1_RIGHT1 0x010c /* Audio Dock ADC1 Right, 1st or 48kHz only */ +#define EMU_SRC_DOCK_ADC1_RIGHT2 0x010d /* Audio Dock ADC1 Right, 2nd or 96kHz */ +#define EMU_SRC_DOCK_ADC1_RIGHT3 0x010e /* Audio Dock ADC1 Right, 3rd or 192kHz */ +#define EMU_SRC_DOCK_ADC1_RIGHT4 0x010f /* Audio Dock ADC1 Right, 4th or 192kHz */ +#define EMU_SRC_DOCK_ADC2_LEFT1 0x0110 /* Audio Dock ADC2 Left, 1st or 48kHz only */ +#define EMU_SRC_DOCK_ADC2_LEFT2 0x0111 /* Audio Dock ADC2 Left, 2nd or 96kHz */ +#define EMU_SRC_DOCK_ADC2_LEFT3 0x0112 /* Audio Dock ADC2 Left, 3rd or 192kHz */ +#define EMU_SRC_DOCK_ADC2_LEFT4 0x0113 /* Audio Dock ADC2 Left, 4th or 192kHz */ +#define EMU_SRC_DOCK_ADC2_RIGHT1 0x0114 /* Audio Dock ADC2 Right, 1st or 48kHz only */ +#define EMU_SRC_DOCK_ADC2_RIGHT2 0x0115 /* Audio Dock ADC2 Right, 2nd or 96kHz */ +#define EMU_SRC_DOCK_ADC2_RIGHT3 0x0116 /* Audio Dock ADC2 Right, 3rd or 192kHz */ +#define EMU_SRC_DOCK_ADC2_RIGHT4 0x0117 /* Audio Dock ADC2 Right, 4th or 192kHz */ +#define EMU_SRC_DOCK_ADC3_LEFT1 0x0118 /* Audio Dock ADC3 Left, 1st or 48kHz only */ +#define EMU_SRC_DOCK_ADC3_LEFT2 0x0119 /* Audio Dock ADC3 Left, 2nd or 96kHz */ +#define EMU_SRC_DOCK_ADC3_LEFT3 0x011a /* Audio Dock ADC3 Left, 3rd or 192kHz */ +#define EMU_SRC_DOCK_ADC3_LEFT4 0x011b /* Audio Dock ADC3 Left, 4th or 192kHz */ +#define EMU_SRC_DOCK_ADC3_RIGHT1 0x011c /* Audio Dock ADC3 Right, 1st or 48kHz only */ +#define EMU_SRC_DOCK_ADC3_RIGHT2 0x011d /* Audio Dock ADC3 Right, 2nd or 96kHz */ +#define EMU_SRC_DOCK_ADC3_RIGHT3 0x011e /* Audio Dock ADC3 Right, 3rd or 192kHz */ +#define EMU_SRC_DOCK_ADC3_RIGHT4 0x011f /* Audio Dock ADC3 Right, 4th or 192kHz */ +#define EMU_SRC_HAMOA_ADC_LEFT1 0x0200 /* Hamoa ADC Left, 1st or 48kHz only */ +#define EMU_SRC_HAMOA_ADC_LEFT2 0x0202 /* Hamoa ADC Left, 2nd or 96kHz */ +#define EMU_SRC_HAMOA_ADC_LEFT3 0x0204 /* Hamoa ADC Left, 3rd or 192kHz */ +#define EMU_SRC_HAMOA_ADC_LEFT4 0x0206 /* Hamoa ADC Left, 4th or 192kHz */ +#define EMU_SRC_HAMOA_ADC_RIGHT1 0x0201 /* Hamoa ADC Right, 1st or 48kHz only */ +#define EMU_SRC_HAMOA_ADC_RIGHT2 0x0203 /* Hamoa ADC Right, 2nd or 96kHz */ +#define EMU_SRC_HAMOA_ADC_RIGHT3 0x0205 /* Hamoa ADC Right, 3rd or 192kHz */ +#define EMU_SRC_HAMOA_ADC_RIGHT4 0x0207 /* Hamoa ADC Right, 4th or 192kHz */ +#define EMU_SRC_ALICE_EMU32A 0x0300 /* Alice2 EMU32a 16 outputs. +0 to +0xf */ +#define EMU_SRC_ALICE_EMU32B 0x0310 /* Alice2 EMU32b 16 outputs. +0 to +0xf */ +#define EMU_SRC_HANA_ADAT 0x0400 /* Hana ADAT 8 channel in +0 to +7 */ +#define EMU_SRC_HANA_SPDIF_LEFT1 0x0500 /* Hana SPDIF Left, 1st or 48kHz only */ +#define EMU_SRC_HANA_SPDIF_LEFT2 0x0502 /* Hana SPDIF Left, 2nd or 96kHz */ +#define EMU_SRC_HANA_SPDIF_RIGHT1 0x0501 /* Hana SPDIF Right, 1st or 48kHz only */ +#define EMU_SRC_HANA_SPDIF_RIGHT2 0x0503 /* Hana SPDIF Right, 2nd or 96kHz */ +/* 0x600 and 0x700 no used */ /* ------------------- STRUCTURES -------------------- */ @@ -1063,7 +1425,7 @@ struct snd_emu_chip_details { unsigned char spdif_bug; /* Has Spdif phasing bug */ unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */ unsigned char ecard; /* APS EEPROM */ - unsigned char emu1212m; /* EMU 1212m card */ + unsigned char emu1010; /* EMU 1010m card */ unsigned char spi_dac; /* SPI interface for DAC */ unsigned char i2c_adc; /* I2C interface for ADC */ unsigned char adc_1361t; /* Use Philips 1361T ADC */ @@ -1072,6 +1434,14 @@ struct snd_emu_chip_details { const char *id; /* for backward compatibility - can be NULL if not needed */ }; +struct snd_emu1010 { + unsigned int output_source[64]; + unsigned int input_source[64]; + unsigned int adc_pads; /* bit mask */ + unsigned int dac_pads; /* bit mask */ + unsigned int internal_clock; /* 44100 or 48000 */ +}; + struct snd_emu10k1 { int irq; @@ -1079,6 +1449,7 @@ struct snd_emu10k1 { unsigned int tos_link: 1, /* tos link detected */ rear_ac97: 1, /* rear channels are on AC'97 */ enable_ir: 1; + unsigned int support_tlv :1; /* Contains profile of card capabilities */ const struct snd_emu_chip_details *card_capabilities; unsigned int audigy; /* is Audigy? */ @@ -1104,6 +1475,8 @@ struct snd_emu10k1 { spinlock_t memblk_lock; unsigned int spdif_bits[3]; /* s/pdif out setup */ + unsigned int i2c_capture_source; + u8 i2c_capture_volume[4][2]; struct snd_emu10k1_fx8010 fx8010; /* FX8010 info */ int gpr_base; @@ -1132,6 +1505,7 @@ struct snd_emu10k1 { int p16v_device_offset; u32 p16v_capture_source; u32 p16v_capture_channel; + struct snd_emu1010 emu1010; struct snd_emu10k1_pcm_mixer pcm_mixer[32]; struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK]; struct snd_kcontrol *ctl_send_routing; @@ -1208,6 +1582,10 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn); void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data); int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data); +int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value); +int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value); +int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value); +int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src); unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc); void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb); void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb); @@ -1524,11 +1902,20 @@ struct snd_emu10k1_fx8010_control_gpr { unsigned int value[32]; /* initial values */ unsigned int min; /* minimum range */ unsigned int max; /* maximum range */ - union { - snd_kcontrol_tlv_rw_t *c; - unsigned int *p; - } tlv; unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ + const unsigned int *tlv; +}; + +/* old ABI without TLV support */ +struct snd_emu10k1_fx8010_control_old_gpr { + struct snd_ctl_elem_id id; + unsigned int vcount; + unsigned int count; + unsigned short gpr[32]; + unsigned int value[32]; + unsigned int min; + unsigned int max; + unsigned int translation; }; struct snd_emu10k1_fx8010_code { @@ -1579,6 +1966,8 @@ struct snd_emu10k1_fx8010_pcm_rec { unsigned int res2; /* reserved */ }; +#define SNDRV_EMU10K1_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + #define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info) #define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code) #define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code) @@ -1587,6 +1976,7 @@ struct snd_emu10k1_fx8010_pcm_rec { #define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram) #define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec) #define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec) +#define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int) #define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80) #define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81) #define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2f645dfd7f70..ee6bc2d06803 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -56,6 +56,8 @@ struct snd_pcm_hardware { size_t fifo_size; /* fifo size in bytes */ }; +struct snd_pcm_substream; + struct snd_pcm_ops { int (*open)(struct snd_pcm_substream *substream); int (*close)(struct snd_pcm_substream *substream); @@ -384,6 +386,7 @@ struct snd_pcm_substream { struct snd_info_entry *proc_sw_params_entry; struct snd_info_entry *proc_status_entry; struct snd_info_entry *proc_prealloc_entry; + struct snd_info_entry *proc_prealloc_max_entry; #endif /* misc flags */ unsigned int hw_opened: 1; @@ -427,6 +430,7 @@ struct snd_pcm { wait_queue_head_t open_wait; void *private_data; void (*private_free) (struct snd_pcm *pcm); + struct device *dev; /* actual hw device this belongs to */ #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) struct snd_pcm_oss oss; #endif diff --git a/include/sound/pt2258.h b/include/sound/pt2258.h new file mode 100644 index 000000000000..160f812faa42 --- /dev/null +++ b/include/sound/pt2258.h @@ -0,0 +1,37 @@ +/* + * ALSA Driver for the PT2258 volume controller. + * + * Copyright (c) 2006 Jochen Voss <voss@seehuhn.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __SOUND_PT2258_H +#define __SOUND_PT2258_H + +struct snd_pt2258 { + struct snd_card *card; + struct snd_i2c_bus *i2c_bus; + struct snd_i2c_device *i2c_dev; + + unsigned char volume[6]; + int mute; +}; + +extern int snd_pt2258_reset(struct snd_pt2258 *pt); +extern int snd_pt2258_build_controls(struct snd_pt2258 *pt); + +#endif /* __SOUND_PT2258_H */ diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h index caf6fe21514d..736eac71d053 100644 --- a/include/sound/sb16_csp.h +++ b/include/sound/sb16_csp.h @@ -114,9 +114,21 @@ struct snd_sb_csp_info { #ifdef __KERNEL__ #include "sb.h" #include "hwdep.h" +#include <linux/firmware.h> struct snd_sb_csp; +/* indices for the known CSP programs */ +enum { + CSP_PROGRAM_MULAW, + CSP_PROGRAM_ALAW, + CSP_PROGRAM_ADPCM_INIT, + CSP_PROGRAM_ADPCM_PLAYBACK, + CSP_PROGRAM_ADPCM_CAPTURE, + + CSP_PROGRAM_COUNT +}; + /* * CSP operators */ @@ -159,6 +171,8 @@ struct snd_sb_csp { struct snd_kcontrol *qsound_space; struct mutex access_mutex; /* locking */ + + const struct firmware *csp_programs[CSP_PROGRAM_COUNT]; }; int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep); diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h index 0b9e5de94ff1..9688d4be918e 100644 --- a/include/sound/snd_wavefront.h +++ b/include/sound/snd_wavefront.h @@ -85,6 +85,7 @@ struct _snd_wavefront { char hw_version[2]; /* major = [0], minor = [1] */ char israw; /* needs Motorola microcode */ char has_fx; /* has FX processor (Tropez+) */ + char fx_initialized; /* FX's register pages initialized */ char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */ char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */ char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */ @@ -94,6 +95,7 @@ struct _snd_wavefront { spinlock_t irq_lock; wait_queue_head_t interrupt_sleeper; snd_wavefront_midi_t midi; /* ICS2115 MIDI interface */ + struct snd_card *card; }; struct _snd_wavefront_card { diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h new file mode 100644 index 000000000000..2b1ae8edc43c --- /dev/null +++ b/include/sound/soc-dapm.h @@ -0,0 +1,286 @@ +/* + * linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management + * + * Author: Liam Girdwood + * Created: Aug 11th 2005 + * Copyright: Wolfson Microelectronics. PLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_SOC_DAPM_H +#define __LINUX_SND_SOC_DAPM_H + +#include <linux/device.h> +#include <linux/types.h> +#include <sound/control.h> +#include <sound/soc.h> + +/* widget has no PM register bit */ +#define SND_SOC_NOPM -1 + +/* + * SoC dynamic audio power managment + * + * We can have upto 4 power domains + * 1. Codec domain - VREF, VMID + * Usually controlled at codec probe/remove, although can be set + * at stream time if power is not needed for sidetone, etc. + * 2. Platform/Machine domain - physically connected inputs and outputs + * Is platform/machine and user action specific, is set in the machine + * driver and by userspace e.g when HP are inserted + * 3. Path domain - Internal codec path mixers + * Are automatically set when mixer and mux settings are + * changed by the user. + * 4. Stream domain - DAC's and ADC's. + * Enabled when stream playback/capture is started. + */ + +/* codec domain */ +#define SND_SOC_DAPM_VMID(wname) \ +{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0} + +/* platform domain */ +#define SND_SOC_DAPM_INPUT(wname) \ +{ .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0} +#define SND_SOC_DAPM_OUTPUT(wname) \ +{ .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0} +#define SND_SOC_DAPM_MIC(wname, wevent) \ +{ .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0, .event = wevent, \ + .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} +#define SND_SOC_DAPM_HP(wname, wevent) \ +{ .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0, .event = wevent, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} +#define SND_SOC_DAPM_SPK(wname, wevent) \ +{ .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0, .event = wevent, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} +#define SND_SOC_DAPM_LINE(wname, wevent) \ +{ .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0, .event = wevent, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} + +/* path domain */ +#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ + wcontrols, wncontrols) \ +{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} +#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ + wcontrols, wncontrols)\ +{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} +#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ +{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0} +#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ +{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} +#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ +{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} + +/* path domain with event - event handler must return 0 for success */ +#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ + wncontrols, wevent, wflags) \ +{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ + .event = wevent, .event_flags = wflags} +#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ + wncontrols, wevent, wflags) \ +{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ + .event = wevent, .event_flags = wflags} +#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \ +{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \ + .event = wevent, .event_flags = wflags} +#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ + wevent, wflags) \ +{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1 \ + .event = wevent, .event_flags = wflags} +#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ + wevent, wflags) \ +{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \ + .event = wevent, .event_flags = wflags} + +/* events that are pre and post DAPM */ +#define SND_SOC_DAPM_PRE(wname, wevent) \ +{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0, .event = wevent, \ + .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD} +#define SND_SOC_DAPM_POST(wname, wevent) \ +{ .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \ + .num_kcontrols = 0, .event = wevent, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} + +/* stream domain */ +#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ +{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ + .shift = wshift, .invert = winvert} +#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ +{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ + .shift = wshift, .invert = winvert} + +/* dapm kcontrol types */ +#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, \ + .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } +#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \ + power) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_soc_info_volsw, \ + .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ + .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\ + ((mask) << 16) | ((invert) << 24) } +#define SOC_DAPM_ENUM(xname, xenum) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_double, \ + .get = snd_soc_dapm_get_enum_double, \ + .put = snd_soc_dapm_put_enum_double, \ + .private_value = (unsigned long)&xenum } + +/* dapm stream operations */ +#define SND_SOC_DAPM_STREAM_NOP 0x0 +#define SND_SOC_DAPM_STREAM_START 0x1 +#define SND_SOC_DAPM_STREAM_STOP 0x2 +#define SND_SOC_DAPM_STREAM_SUSPEND 0x4 +#define SND_SOC_DAPM_STREAM_RESUME 0x8 +#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10 +#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20 + +/* dapm event types */ +#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ +#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ +#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ +#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ +#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ +#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ + +/* convenience event type detection */ +#define SND_SOC_DAPM_EVENT_ON(e) \ + (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)) +#define SND_SOC_DAPM_EVENT_OFF(e) \ + (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)) + +struct snd_soc_dapm_widget; +enum snd_soc_dapm_type; +struct snd_soc_dapm_path; +struct snd_soc_dapm_pin; + +/* dapm controls */ +int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_dapm_new_control(struct snd_soc_codec *codec, + const struct snd_soc_dapm_widget *widget); + +/* dapm path setup */ +int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, + const char *sink_name, const char *control_name, const char *src_name); +int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); +void snd_soc_dapm_free(struct snd_soc_device *socdev); + +/* dapm events */ +int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, + int event); + +/* dapm sys fs - used by the core */ +int snd_soc_dapm_sys_add(struct device *dev); + +/* dapm audio endpoint control */ +int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, + char *pin, int status); +int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec); + +/* dapm widget types */ +enum snd_soc_dapm_type { + snd_soc_dapm_input = 0, /* input pin */ + snd_soc_dapm_output, /* output pin */ + snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ + snd_soc_dapm_mixer, /* mixes several analog signals together */ + snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ + snd_soc_dapm_adc, /* analog to digital converter */ + snd_soc_dapm_dac, /* digital to analog converter */ + snd_soc_dapm_micbias, /* microphone bias (power) */ + snd_soc_dapm_mic, /* microphone */ + snd_soc_dapm_hp, /* headphones */ + snd_soc_dapm_spk, /* speaker */ + snd_soc_dapm_line, /* line input/output */ + snd_soc_dapm_switch, /* analog switch */ + snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */ + snd_soc_dapm_pre, /* machine specific pre widget - exec first */ + snd_soc_dapm_post, /* machine specific post widget - exec last */ +}; + +/* dapm audio path between two widgets */ +struct snd_soc_dapm_path { + char *name; + char *long_name; + + /* source (input) and sink (output) widgets */ + struct snd_soc_dapm_widget *source; + struct snd_soc_dapm_widget *sink; + struct snd_kcontrol *kcontrol; + + /* status */ + u32 connect:1; /* source and sink widgets are connected */ + u32 walked:1; /* path has been walked */ + + struct list_head list_source; + struct list_head list_sink; + struct list_head list; +}; + +/* dapm widget */ +struct snd_soc_dapm_widget { + enum snd_soc_dapm_type id; + char *name; /* widget name */ + char *sname; /* stream name */ + struct snd_soc_codec *codec; + struct list_head list; + + /* dapm control */ + short reg; /* negative reg = no direct dapm */ + unsigned char shift; /* bits to shift */ + unsigned int saved_value; /* widget saved value */ + unsigned int value; /* widget current value */ + unsigned char power:1; /* block power status */ + unsigned char invert:1; /* invert the power bit */ + unsigned char active:1; /* active stream on DAC, ADC's */ + unsigned char connected:1; /* connected codec pin */ + unsigned char new:1; /* cnew complete */ + unsigned char ext:1; /* has external widgets */ + unsigned char muted:1; /* muted for pop reduction */ + unsigned char suspend:1; /* was active before suspend */ + unsigned char pmdown:1; /* waiting for timeout */ + + /* external events */ + unsigned short event_flags; /* flags to specify event types */ + int (*event)(struct snd_soc_dapm_widget*, int); + + /* kcontrols that relate to this widget */ + int num_kcontrols; + const struct snd_kcontrol_new *kcontrols; + + /* widget input and outputs */ + struct list_head sources; + struct list_head sinks; +}; + +#endif diff --git a/include/sound/soc.h b/include/sound/soc.h new file mode 100644 index 000000000000..b1dc364b8f74 --- /dev/null +++ b/include/sound/soc.h @@ -0,0 +1,461 @@ +/* + * linux/sound/soc.h -- ALSA SoC Layer + * + * Author: Liam Girdwood + * Created: Aug 11th 2005 + * Copyright: Wolfson Microelectronics. PLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_SOC_H +#define __LINUX_SND_SOC_H + +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/workqueue.h> +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/control.h> +#include <sound/ac97_codec.h> + +#define SND_SOC_VERSION "0.13.0" + +/* + * Convenience kcontrol builders + */ +#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\ + ((shift) << 12) | ((mask) << 16) | ((invert) << 24)) +#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\ + ((invert) << 31)) +#define SOC_SINGLE(xname, reg, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = snd_soc_put_volsw, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } +#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ + .put = snd_soc_put_volsw, \ + .private_value = (reg) | ((shift_left) << 8) | \ + ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) } +#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_soc_info_volsw_2r, \ + .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ + .private_value = (reg_left) | ((shift) << 8) | \ + ((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) } +#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ +{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ + .mask = xmask, .texts = xtexts } +#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \ + SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts) +#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \ +{ .mask = xmask, .texts = xtexts } +#define SOC_ENUM(xname, xenum) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ + .info = snd_soc_info_enum_double, \ + .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ + .private_value = (unsigned long)&xenum } +#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\ + xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) } +#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_bool_ext, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = xdata } +#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_ext, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&xenum } + +/* + * Digital Audio Interface (DAI) types + */ +#define SND_SOC_DAI_AC97 0x1 +#define SND_SOC_DAI_I2S 0x2 +#define SND_SOC_DAI_PCM 0x4 + +/* + * DAI hardware audio formats + */ +#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ +#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */ +#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ +#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */ +#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */ +#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ + +#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J +#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J + +/* + * DAI Gating + */ +#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ +#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */ + +/* + * DAI hardware signal inversions + */ +#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ +#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ +#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ +#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ + +/* + * DAI hardware clock masters + * This is wrt the codec, the inverse is true for the interface + * i.e. if the codec is clk and frm master then the interface is + * clk and frame slave. + */ +#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ +#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ +#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ +#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ + +#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f +#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 +#define SND_SOC_DAIFMT_INV_MASK 0x0f00 +#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 + + +/* + * Master Clock Directions + */ +#define SND_SOC_CLOCK_IN 0 +#define SND_SOC_CLOCK_OUT 1 + +/* + * AC97 codec ID's bitmask + */ +#define SND_SOC_DAI_AC97_ID0 (1 << 0) +#define SND_SOC_DAI_AC97_ID1 (1 << 1) +#define SND_SOC_DAI_AC97_ID2 (1 << 2) +#define SND_SOC_DAI_AC97_ID3 (1 << 3) + +struct snd_soc_device; +struct snd_soc_pcm_stream; +struct snd_soc_ops; +struct snd_soc_dai_mode; +struct snd_soc_pcm_runtime; +struct snd_soc_codec_dai; +struct snd_soc_cpu_dai; +struct snd_soc_codec; +struct snd_soc_machine_config; +struct soc_enum; +struct snd_soc_ac97_ops; +struct snd_soc_clock_info; + +typedef int (*hw_write_t)(void *,const char* ,int); +typedef int (*hw_read_t)(void *,char* ,int); + +extern struct snd_ac97_bus_ops soc_ac97_ops; + +/* pcm <-> DAI connect */ +void snd_soc_free_pcms(struct snd_soc_device *socdev); +int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); +int snd_soc_register_card(struct snd_soc_device *socdev); + +/* set runtime hw params */ +int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, + const struct snd_pcm_hardware *hw); + +/* codec IO */ +#define snd_soc_read(codec, reg) codec->read(codec, reg) +#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value) + +/* codec register bit access */ +int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, + unsigned short mask, unsigned short value); +int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, + unsigned short mask, unsigned short value); + +int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, + struct snd_ac97_bus_ops *ops, int num); +void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); + +/* + *Controls + */ +struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, + void *data, char *long_name); +int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +/* SoC PCM stream information */ +struct snd_soc_pcm_stream { + char *stream_name; + u64 formats; /* SNDRV_PCM_FMTBIT_* */ + unsigned int rates; /* SNDRV_PCM_RATE_* */ + unsigned int rate_min; /* min rate */ + unsigned int rate_max; /* max rate */ + unsigned int channels_min; /* min channels */ + unsigned int channels_max; /* max channels */ + unsigned int active:1; /* stream is in use */ +}; + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); + int (*trigger)(struct snd_pcm_substream *, int); +}; + +/* ASoC codec DAI ops */ +struct snd_soc_codec_ops { + /* codec DAI clocking configuration */ + int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai, + int clk_id, unsigned int freq, int dir); + int (*set_pll)(struct snd_soc_codec_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai, + int div_id, int div); + + /* CPU DAI format configuration */ + int (*set_fmt)(struct snd_soc_codec_dai *codec_dai, + unsigned int fmt); + int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai, + unsigned int mask, int slots); + int (*set_tristate)(struct snd_soc_codec_dai *, int tristate); + + /* digital mute */ + int (*digital_mute)(struct snd_soc_codec_dai *, int mute); +}; + +/* ASoC cpu DAI ops */ +struct snd_soc_cpu_ops { + /* CPU DAI clocking configuration */ + int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai, + int clk_id, unsigned int freq, int dir); + int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai, + int div_id, int div); + int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + + /* CPU DAI format configuration */ + int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai, + unsigned int fmt); + int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai, + unsigned int mask, int slots); + int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate); +}; + +/* SoC Codec DAI */ +struct snd_soc_codec_dai { + char *name; + int id; + + /* DAI capabilities */ + struct snd_soc_pcm_stream playback; + struct snd_soc_pcm_stream capture; + + /* DAI runtime info */ + struct snd_soc_codec *codec; + unsigned int active; + unsigned char pop_wait:1; + + /* ops */ + struct snd_soc_ops ops; + struct snd_soc_codec_ops dai_ops; + + /* DAI private data */ + void *private_data; +}; + +/* SoC CPU DAI */ +struct snd_soc_cpu_dai { + + /* DAI description */ + char *name; + unsigned int id; + unsigned char type; + + /* DAI callbacks */ + int (*probe)(struct platform_device *pdev); + void (*remove)(struct platform_device *pdev); + int (*suspend)(struct platform_device *pdev, + struct snd_soc_cpu_dai *cpu_dai); + int (*resume)(struct platform_device *pdev, + struct snd_soc_cpu_dai *cpu_dai); + + /* ops */ + struct snd_soc_ops ops; + struct snd_soc_cpu_ops dai_ops; + + /* DAI capabilities */ + struct snd_soc_pcm_stream capture; + struct snd_soc_pcm_stream playback; + + /* DAI runtime info */ + struct snd_pcm_runtime *runtime; + unsigned char active:1; + void *dma_data; + + /* DAI private data */ + void *private_data; +}; + +/* SoC Audio Codec */ +struct snd_soc_codec { + char *name; + struct module *owner; + struct mutex mutex; + + /* callbacks */ + int (*dapm_event)(struct snd_soc_codec *codec, int event); + + /* runtime */ + struct snd_card *card; + struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ + unsigned int active; + unsigned int pcm_devs; + void *private_data; + + /* codec IO */ + void *control_data; /* codec control (i2c/3wire) data */ + unsigned int (*read)(struct snd_soc_codec *, unsigned int); + int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + hw_write_t hw_write; + hw_read_t hw_read; + void *reg_cache; + short reg_cache_size; + short reg_cache_step; + + /* dapm */ + struct list_head dapm_widgets; + struct list_head dapm_paths; + unsigned int dapm_state; + unsigned int suspend_dapm_state; + struct delayed_work delayed_work; + + /* codec DAI's */ + struct snd_soc_codec_dai *dai; + unsigned int num_dai; +}; + +/* codec device */ +struct snd_soc_codec_device { + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); +}; + +/* SoC platform interface */ +struct snd_soc_platform { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + int (*suspend)(struct platform_device *pdev, + struct snd_soc_cpu_dai *cpu_dai); + int (*resume)(struct platform_device *pdev, + struct snd_soc_cpu_dai *cpu_dai); + + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, + struct snd_pcm *); + void (*pcm_free)(struct snd_pcm *); + + /* platform stream ops */ + struct snd_pcm_ops *pcm_ops; +}; + +/* SoC machine DAI configuration, glues a codec and cpu DAI together */ +struct snd_soc_dai_link { + char *name; /* Codec name */ + char *stream_name; /* Stream name */ + + /* DAI */ + struct snd_soc_codec_dai *codec_dai; + struct snd_soc_cpu_dai *cpu_dai; + + /* machine stream operations */ + struct snd_soc_ops *ops; + + /* codec/machine specific init - e.g. add machine controls */ + int (*init)(struct snd_soc_codec *codec); +}; + +/* SoC machine */ +struct snd_soc_machine { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + + /* the pre and post PM functions are used to do any PM work before and + * after the codec and DAI's do any PM work. */ + int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); + int (*suspend_post)(struct platform_device *pdev, pm_message_t state); + int (*resume_pre)(struct platform_device *pdev); + int (*resume_post)(struct platform_device *pdev); + + /* CPU <--> Codec DAI links */ + struct snd_soc_dai_link *dai_link; + int num_links; +}; + +/* SoC Device - the audio subsystem */ +struct snd_soc_device { + struct device *dev; + struct snd_soc_machine *machine; + struct snd_soc_platform *platform; + struct snd_soc_codec *codec; + struct snd_soc_codec_device *codec_dev; + struct delayed_work delayed_work; + void *codec_data; +}; + +/* runtime channel data */ +struct snd_soc_pcm_runtime { + struct snd_soc_dai_link *dai; + struct snd_soc_device *socdev; +}; + +/* enumerated kcontrol */ +struct soc_enum { + unsigned short reg; + unsigned short reg2; + unsigned char shift_l; + unsigned char shift_r; + unsigned int mask; + const char **texts; + void *dapm; +}; + +#endif diff --git a/include/sound/typedefs.h b/include/sound/typedefs.h deleted file mode 100644 index f454b0206b93..000000000000 --- a/include/sound/typedefs.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Typedef's for backward compatibility (for out-of-kernel drivers) - * - * This file will be removed soon in future - */ - -/* core stuff */ -typedef struct snd_card snd_card_t; -typedef struct snd_device snd_device_t; -typedef struct snd_device_ops snd_device_ops_t; -typedef enum snd_card_type snd_card_type_t; -typedef struct snd_minor snd_minor_t; - -/* info */ -typedef struct snd_info_entry snd_info_entry_t; -typedef struct snd_info_buffer snd_info_buffer_t; - -/* control */ -typedef struct snd_ctl_file snd_ctl_file_t; -typedef struct snd_kcontrol snd_kcontrol_t; -typedef struct snd_kcontrol_new snd_kcontrol_new_t; -typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t; -typedef struct snd_kctl_event snd_kctl_event_t; -typedef struct snd_aes_iec958 snd_aes_iec958_t; -typedef struct snd_ctl_card_info snd_ctl_card_info_t; -typedef struct snd_ctl_elem_id snd_ctl_elem_id_t; -typedef struct snd_ctl_elem_list snd_ctl_elem_list_t; -typedef struct snd_ctl_elem_info snd_ctl_elem_info_t; -typedef struct snd_ctl_elem_value snd_ctl_elem_value_t; -typedef struct snd_ctl_event snd_ctl_event_t; -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) -typedef struct snd_mixer_oss snd_mixer_oss_t; -#endif - -/* timer */ -typedef struct snd_timer snd_timer_t; -typedef struct snd_timer_instance snd_timer_instance_t; -typedef struct snd_timer_id snd_timer_id_t; -typedef struct snd_timer_ginfo snd_timer_ginfo_t; -typedef struct snd_timer_gparams snd_timer_gparams_t; -typedef struct snd_timer_gstatus snd_timer_gstatus_t; -typedef struct snd_timer_select snd_timer_select_t; -typedef struct snd_timer_info snd_timer_info_t; -typedef struct snd_timer_params snd_timer_params_t; -typedef struct snd_timer_status snd_timer_status_t; -typedef struct snd_timer_read snd_timer_read_t; -typedef struct snd_timer_tread snd_timer_tread_t; - -/* PCM */ -typedef struct snd_pcm snd_pcm_t; -typedef struct snd_pcm_str snd_pcm_str_t; -typedef struct snd_pcm_substream snd_pcm_substream_t; -typedef struct snd_pcm_info snd_pcm_info_t; -typedef struct snd_pcm_hw_params snd_pcm_hw_params_t; -typedef struct snd_pcm_sw_params snd_pcm_sw_params_t; -typedef struct snd_pcm_channel_info snd_pcm_channel_info_t; -typedef struct snd_pcm_status snd_pcm_status_t; -typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t; -typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t; -typedef struct snd_mask snd_mask_t; -typedef struct snd_sg_buf snd_pcm_sgbuf_t; - -typedef struct snd_interval snd_interval_t; -typedef struct snd_xferi snd_xferi_t; -typedef struct snd_xfern snd_xfern_t; -typedef struct snd_xferv snd_xferv_t; - -typedef struct snd_pcm_file snd_pcm_file_t; -typedef struct snd_pcm_runtime snd_pcm_runtime_t; -typedef struct snd_pcm_hardware snd_pcm_hardware_t; -typedef struct snd_pcm_ops snd_pcm_ops_t; -typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t; -typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t; -typedef struct snd_ratnum ratnum_t; -typedef struct snd_ratden ratden_t; -typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t; -typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t; -typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t; -typedef struct snd_pcm_group snd_pcm_group_t; -typedef struct snd_pcm_notify snd_pcm_notify_t; - -/* rawmidi */ -typedef struct snd_rawmidi snd_rawmidi_t; -typedef struct snd_rawmidi_info snd_rawmidi_info_t; -typedef struct snd_rawmidi_params snd_rawmidi_params_t; -typedef struct snd_rawmidi_status snd_rawmidi_status_t; -typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t; -typedef struct snd_rawmidi_substream snd_rawmidi_substream_t; -typedef struct snd_rawmidi_str snd_rawmidi_str_t; -typedef struct snd_rawmidi_ops snd_rawmidi_ops_t; -typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t; -typedef struct snd_rawmidi_file snd_rawmidi_file_t; - -/* hwdep */ -typedef struct snd_hwdep snd_hwdep_t; -typedef struct snd_hwdep_info snd_hwdep_info_t; -typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t; -typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t; -typedef struct snd_hwdep_ops snd_hwdep_ops_t; - -/* sequencer */ -typedef struct snd_seq_port_info snd_seq_port_info_t; -typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t; -typedef struct snd_seq_event snd_seq_event_t; -typedef struct snd_seq_addr snd_seq_addr_t; -typedef struct snd_seq_ev_volume snd_seq_ev_volume_t; -typedef struct snd_seq_ev_loop snd_seq_ev_loop_t; -typedef struct snd_seq_remove_events snd_seq_remove_events_t; -typedef struct snd_seq_query_subs snd_seq_query_subs_t; -typedef struct snd_seq_system_info snd_seq_system_info_t; -typedef struct snd_seq_client_info snd_seq_client_info_t; -typedef struct snd_seq_queue_info snd_seq_queue_info_t; -typedef struct snd_seq_queue_status snd_seq_queue_status_t; -typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t; -typedef struct snd_seq_queue_owner snd_seq_queue_owner_t; -typedef struct snd_seq_queue_timer snd_seq_queue_timer_t; -typedef struct snd_seq_queue_client snd_seq_queue_client_t; -typedef struct snd_seq_client_pool snd_seq_client_pool_t; -typedef struct snd_seq_instr snd_seq_instr_t; -typedef struct snd_seq_instr_data snd_seq_instr_data_t; -typedef struct snd_seq_instr_header snd_seq_instr_header_t; - -typedef struct snd_seq_user_client user_client_t; -typedef struct snd_seq_kernel_client kernel_client_t; -typedef struct snd_seq_client client_t; -typedef struct snd_seq_queue queue_t; - -/* seq_device */ -typedef struct snd_seq_device snd_seq_device_t; -typedef struct snd_seq_dev_ops snd_seq_dev_ops_t; - -/* seq_midi */ -typedef struct snd_midi_event snd_midi_event_t; - -/* seq_midi_emul */ -typedef struct snd_midi_channel snd_midi_channel_t; -typedef struct snd_midi_channel_set snd_midi_channel_set_t; -typedef struct snd_midi_op snd_midi_op_t; - -/* seq_oss */ -typedef struct snd_seq_oss_arg snd_seq_oss_arg_t; -typedef struct snd_seq_oss_callback snd_seq_oss_callback_t; -typedef struct snd_seq_oss_reg snd_seq_oss_reg_t; - -/* virmidi */ -typedef struct snd_virmidi_dev snd_virmidi_dev_t; -typedef struct snd_virmidi snd_virmidi_t; - -/* seq_instr */ -typedef struct snd_seq_kcluster snd_seq_kcluster_t; -typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t; -typedef struct snd_seq_kinstr snd_seq_kinstr_t; -typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t; - -/* ac97 */ -typedef struct snd_ac97_bus ac97_bus_t; -typedef struct snd_ac97_bus_ops ac97_bus_ops_t; -typedef struct snd_ac97_template ac97_template_t; -typedef struct snd_ac97 ac97_t; - -/* opl3/4 */ -typedef struct snd_opl3 opl3_t; -typedef struct snd_opl4 opl4_t; - -/* mpu401 */ -typedef struct snd_mpu401 mpu401_t; - -/* i2c */ -typedef struct snd_i2c_device snd_i2c_device_t; -typedef struct snd_i2c_bus snd_i2c_bus_t; - -typedef struct snd_ak4531 ak4531_t; - diff --git a/include/sound/version.h b/include/sound/version.h index 20f7babad514..c39b3802cf18 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated by alsa/ksync script. */ -#define CONFIG_SND_VERSION "1.0.14rc1" -#define CONFIG_SND_DATE " (Tue Jan 09 09:56:17 2007 UTC)" +#define CONFIG_SND_VERSION "1.0.14rc2" +#define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)" diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h index 217394652090..4830651cc4cf 100644 --- a/include/sound/vx_core.h +++ b/include/sound/vx_core.h @@ -128,7 +128,7 @@ struct snd_vx_hardware { unsigned int num_ins; unsigned int num_outs; unsigned int output_level_max; - unsigned int *output_level_db_scale; + const unsigned int *output_level_db_scale; }; /* hwdep id string */ diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h index f3514ee96bd9..203d2b45b788 100644 --- a/include/sound/ymfpci.h +++ b/include/sound/ymfpci.h @@ -270,6 +270,7 @@ struct snd_ymfpci_pcm { struct snd_pcm_substream *substream; struct snd_ymfpci_voice *voices[2]; /* playback only */ unsigned int running: 1, + use_441_slot: 1, output_front: 1, output_rear: 1, swap_rear: 1; @@ -324,6 +325,7 @@ struct snd_ymfpci { u32 active_bank; struct snd_ymfpci_voice voices[64]; + int src441_used; struct snd_ac97_bus *ac97_bus; struct snd_ac97 *ac97; @@ -346,7 +348,7 @@ struct snd_ymfpci { int mode_dup4ch; int rear_opened; int spdif_opened; - struct { + struct snd_ymfpci_pcm_mixer { u16 left; u16 right; struct snd_kcontrol *ctl; @@ -357,6 +359,8 @@ struct snd_ymfpci { wait_queue_head_t interrupt_sleep; atomic_t interrupt_sleep_count; struct snd_info_entry *proc_entry; + const struct firmware *dsp_microcode; + const struct firmware *controller_microcode; #ifdef CONFIG_PM u32 *saved_regs; diff --git a/sound/Kconfig b/sound/Kconfig index 9d77300746c6..97532bbc2ccb 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -76,6 +76,8 @@ source "sound/sparc/Kconfig" source "sound/parisc/Kconfig" +source "sound/soc/Kconfig" + endmenu menu "Open Sound System" diff --git a/sound/Makefile b/sound/Makefile index 9aee54c4882d..b7c7fb7c24c8 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ -obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ +obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index 66de2c2f1554..7fa37e15f196 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c @@ -26,6 +26,7 @@ static int ac97_bus_match(struct device *dev, struct device_driver *drv) return 1; } +#ifdef CONFIG_PM static int ac97_bus_suspend(struct device *dev, pm_message_t state) { int ret = 0; @@ -45,12 +46,15 @@ static int ac97_bus_resume(struct device *dev) return ret; } +#endif /* CONFIG_PM */ struct bus_type ac97_bus_type = { .name = "ac97", .match = ac97_bus_match, +#ifdef CONFIG_PM .suspend = ac97_bus_suspend, .resume = ac97_bus_resume, +#endif /* CONFIG_PM */ }; static int __init ac97_bus_init(void) diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h index 378ef1e9879b..541b908f3cdf 100644 --- a/sound/aoa/aoa.h +++ b/sound/aoa/aoa.h @@ -99,7 +99,7 @@ struct aoa_fabric { * that are not assigned yet are passed to the fabric * again for reconsideration. */ extern int -aoa_fabric_register(struct aoa_fabric *fabric); +aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev); /* it is vital to call this when the fabric exits! * When calling, the remove_codec will be called diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c index 0b7650788f1f..b00fc4842c93 100644 --- a/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c @@ -825,7 +825,16 @@ static int onyx_resume(struct codec_info_item *cii) int err = -ENXIO; mutex_lock(&onyx->mutex); - /* take codec out of suspend */ + + /* reset codec */ + onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); + msleep(1); + onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); + msleep(1); + onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); + msleep(1); + + /* take codec out of suspend (if it still is after reset) */ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) goto out_unlock; onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV)); diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c index b42fdea77ed0..17fe689ed287 100644 --- a/sound/aoa/core/snd-aoa-alsa.c +++ b/sound/aoa/core/snd-aoa-alsa.c @@ -14,7 +14,7 @@ MODULE_PARM_DESC(index, "index for AOA sound card."); static struct aoa_card *aoa_card; -int aoa_alsa_init(char *name, struct module *mod) +int aoa_alsa_init(char *name, struct module *mod, struct device *dev) { struct snd_card *alsa_card; int err; @@ -28,6 +28,7 @@ int aoa_alsa_init(char *name, struct module *mod) return -ENOMEM; aoa_card = alsa_card->private_data; aoa_card->alsa_card = alsa_card; + alsa_card->dev = dev; strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver)); strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname)); strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname)); @@ -59,7 +60,7 @@ void aoa_alsa_cleanup(void) } int aoa_snd_device_new(snd_device_type_t type, - void * device_data, struct snd_device_ops * ops) + void * device_data, struct snd_device_ops * ops) { struct snd_card *card = aoa_get_card(); int err; diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h index 660d2f1793bb..9669e4489cab 100644 --- a/sound/aoa/core/snd-aoa-alsa.h +++ b/sound/aoa/core/snd-aoa-alsa.h @@ -10,7 +10,7 @@ #define __SND_AOA_ALSA_H #include "../aoa.h" -extern int aoa_alsa_init(char *name, struct module *mod); +extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev); extern void aoa_alsa_cleanup(void); #endif /* __SND_AOA_ALSA_H */ diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c index ecd2d8263f2d..19fdae400687 100644 --- a/sound/aoa/core/snd-aoa-core.c +++ b/sound/aoa/core/snd-aoa-core.c @@ -82,7 +82,7 @@ void aoa_codec_unregister(struct aoa_codec *codec) } EXPORT_SYMBOL_GPL(aoa_codec_unregister); -int aoa_fabric_register(struct aoa_fabric *new_fabric) +int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev) { struct aoa_codec *c; int err; @@ -98,7 +98,7 @@ int aoa_fabric_register(struct aoa_fabric *new_fabric) if (!new_fabric) return -EINVAL; - err = aoa_alsa_init(new_fabric->name, new_fabric->owner); + err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev); if (err) return err; diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 172eb95476c0..1b94ba6dd279 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -1014,7 +1014,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) ldev->gpio.methods->init(&ldev->gpio); - err = aoa_fabric_register(&layout_fabric); + err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev); if (err && err != -EALREADY) { printk(KERN_INFO "snd-aoa-fabric-layout: can't use," " another fabric is active!\n"); @@ -1034,9 +1034,9 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) list_del(&ldev->list); layouts_list_items--; outnodev: - if (sound) of_node_put(sound); + of_node_put(sound); layout_device = NULL; - if (ldev) kfree(ldev); + kfree(ldev); return -ENODEV; } @@ -1077,8 +1077,6 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta { struct layout_dev *ldev = sdev->ofdev.dev.driver_data; - printk("aoa_fabric_layout_suspend()\n"); - if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_off(&ldev->gpio); @@ -1089,8 +1087,6 @@ static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) { struct layout_dev *ldev = sdev->ofdev.dev.driver_data; - printk("aoa_fabric_layout_resume()\n"); - if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_restore(&ldev->gpio); @@ -1107,6 +1103,9 @@ static struct soundbus_driver aoa_soundbus_driver = { .suspend = aoa_fabric_layout_suspend, .resume = aoa_fabric_layout_resume, #endif + .driver = { + .owner = THIS_MODULE, + } }; static int __init aoa_fabric_layout_init(void) diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index e593a1333fe3..e36f6aa448d4 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -41,8 +41,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, struct dbdma_command_mem *r, int numcmds) { - /* one more for rounding */ - r->size = (numcmds+1) * sizeof(struct dbdma_cmd); + /* one more for rounding, one for branch back, one for stop command */ + r->size = (numcmds + 3) * sizeof(struct dbdma_cmd); /* We use the PCI APIs for now until the generic one gets fixed * enough or until we get some macio-specific versions */ @@ -377,11 +377,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) if (i2sdev->sound.pcm) { /* Suspend PCM streams */ snd_pcm_suspend_all(i2sdev->sound.pcm); - /* Probably useless as we handle - * power transitions ourselves */ - snd_power_change_state(i2sdev->sound.pcm->card, - SNDRV_CTL_POWER_D3hot); } + /* Notify codecs */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { err = 0; @@ -390,7 +387,11 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) if (err) ret = err; } + + /* wait until streams are stopped */ + i2sbus_wait_for_stop_both(i2sdev); } + return ret; } @@ -402,6 +403,9 @@ static int i2sbus_resume(struct macio_dev* dev) int err, ret = 0; list_for_each_entry(i2sdev, &control->list, item) { + /* reset i2s bus format etc. */ + i2sbus_pcm_prepare_both(i2sdev); + /* Notify codecs so they can re-initialize */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { err = 0; @@ -410,12 +414,6 @@ static int i2sbus_resume(struct macio_dev* dev) if (err) ret = err; } - /* Notify Alsa */ - if (i2sdev->sound.pcm) { - /* Same comment as above, probably useless */ - snd_power_change_state(i2sdev->sound.pcm->card, - SNDRV_CTL_POWER_D0); - } } return ret; diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index 5eff30b10201..c6b42f9bdbc9 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c @@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) } /* bus dependent stuff */ hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME; + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_JOINT_DUPLEX; CHECK_RATE(5512); CHECK_RATE(8000); @@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) return err; } +static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev, + struct pcm_info *pi) +{ + unsigned long flags; + struct completion done; + long timeout; + + spin_lock_irqsave(&i2sdev->low_lock, flags); + if (pi->dbdma_ring.stopping) { + init_completion(&done); + pi->stop_completion = &done; + spin_unlock_irqrestore(&i2sdev->low_lock, flags); + timeout = wait_for_completion_timeout(&done, HZ); + spin_lock_irqsave(&i2sdev->low_lock, flags); + pi->stop_completion = NULL; + if (timeout == 0) { + /* timeout expired, stop dbdma forcefully */ + printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n"); + /* make sure RUN, PAUSE and S0 bits are cleared */ + out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + pi->dbdma_ring.stopping = 0; + timeout = 10; + while (in_le32(&pi->dbdma->status) & ACTIVE) { + if (--timeout <= 0) + break; + udelay(1); + } + } + } + spin_unlock_irqrestore(&i2sdev->low_lock, flags); +} + +#ifdef CONFIG_PM +void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev) +{ + struct pcm_info *pi; + + get_pcm_info(i2sdev, 0, &pi, NULL); + i2sbus_wait_for_stop(i2sdev, pi); + get_pcm_info(i2sdev, 1, &pi, NULL); + i2sbus_wait_for_stop(i2sdev, pi); +} +#endif + static int i2sbus_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } -static int i2sbus_hw_free(struct snd_pcm_substream *substream) +static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in) { + struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); + struct pcm_info *pi; + + get_pcm_info(i2sdev, in, &pi, NULL); + if (pi->dbdma_ring.stopping) + i2sbus_wait_for_stop(i2sdev, pi); snd_pcm_lib_free_pages(substream); return 0; } +static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream) +{ + return i2sbus_hw_free(substream, 0); +} + +static int i2sbus_record_hw_free(struct snd_pcm_substream *substream) +{ + return i2sbus_hw_free(substream, 1); +} + static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) { /* whee. Hard work now. The user has selected a bitrate @@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) * I2S controller appropriately. */ struct snd_pcm_runtime *runtime; struct dbdma_cmd *command; - int i, periodsize; + int i, periodsize, nperiods; dma_addr_t offset; struct bus_info bi; struct codec_info_item *cii; @@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) struct pcm_info *pi, *other; int cnt; int result = 0; + unsigned int cmd, stopaddr; mutex_lock(&i2sdev->lock); @@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) result = -EBUSY; goto out_unlock; } + if (pi->dbdma_ring.stopping) + i2sbus_wait_for_stop(i2sdev, pi); + + if (!pi->substream || !pi->substream->runtime) { + result = -EINVAL; + goto out_unlock; + } runtime = pi->substream->runtime; pi->active = 1; @@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) i2sdev->rate = runtime->rate; periodsize = snd_pcm_lib_period_bytes(pi->substream); + nperiods = pi->substream->runtime->periods; pi->current_period = 0; /* generate dbdma command ring first */ command = pi->dbdma_ring.cmds; + memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd)); + + /* commands to DMA to/from the ring */ + /* + * For input, we need to do a graceful stop; if we abort + * the DMA, we end up with leftover bytes that corrupt + * the next recording. To do this we set the S0 status + * bit and wait for the DMA controller to stop. Each + * command has a branch condition to + * make it branch to a stop command if S0 is set. + * On input we also need to wait for the S7 bit to be + * set before turning off the DMA controller. + * In fact we do the graceful stop for output as well. + */ offset = runtime->dma_addr; - for (i = 0; i < pi->substream->runtime->periods; - i++, command++, offset += periodsize) { - memset(command, 0, sizeof(struct dbdma_cmd)); - command->command = - cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS); + cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS; + stopaddr = pi->dbdma_ring.bus_cmd_start + + (nperiods + 1) * sizeof(struct dbdma_cmd); + for (i = 0; i < nperiods; i++, command++, offset += periodsize) { + command->command = cpu_to_le16(cmd); + command->cmd_dep = cpu_to_le32(stopaddr); command->phy_addr = cpu_to_le32(offset); command->req_count = cpu_to_le16(periodsize); - command->xfer_status = cpu_to_le16(0); } - /* last one branches back to first */ - command--; - command->command |= cpu_to_le16(BR_ALWAYS); + + /* branch back to beginning of ring */ + command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS); command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); + command++; + + /* set stop command */ + command->command = cpu_to_le16(DBDMA_STOP); /* ok, let's set the serial format and stuff */ switch (runtime->format) { @@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) return result; } -static struct dbdma_cmd STOP_CMD = { - .command = __constant_cpu_to_le16(DBDMA_STOP), -}; +#ifdef CONFIG_PM +void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev) +{ + i2sbus_pcm_prepare(i2sdev, 0); + i2sbus_pcm_prepare(i2sdev, 1); +} +#endif static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) { struct codec_info_item *cii; struct pcm_info *pi; - int timeout; - struct dbdma_cmd tmp; int result = 0; unsigned long flags; @@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) cii->codec->start(cii, pi->substream); pi->dbdma_ring.running = 1; - /* reset dma engine */ - out_le32(&pi->dbdma->control, - 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); - timeout = 100; - while (in_le32(&pi->dbdma->status) & RUN && timeout--) - udelay(1); - if (timeout <= 0) { - printk(KERN_ERR - "i2sbus: error waiting for dma reset\n"); - result = -ENXIO; - goto out_unlock; + if (pi->dbdma_ring.stopping) { + /* Clear the S0 bit, then see if we stopped yet */ + out_le32(&pi->dbdma->control, 1 << 16); + if (in_le32(&pi->dbdma->status) & ACTIVE) { + /* possible race here? */ + udelay(10); + if (in_le32(&pi->dbdma->status) & ACTIVE) { + pi->dbdma_ring.stopping = 0; + goto out_unlock; /* keep running */ + } + } } + /* make sure RUN, PAUSE and S0 bits are cleared */ + out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + + /* set branch condition select register */ + out_le32(&pi->dbdma->br_sel, (1 << 16) | 1); + /* write dma command buffer address to the dbdma chip */ out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); - /* post PCI write */ - mb(); - (void)in_le32(&pi->dbdma->status); - - /* change first command to STOP */ - tmp = *pi->dbdma_ring.cmds; - *pi->dbdma_ring.cmds = STOP_CMD; - - /* set running state, remember that the first command is STOP */ - out_le32(&pi->dbdma->control, RUN | (RUN << 16)); - timeout = 100; - /* wait for STOP to be executed */ - while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--) - udelay(1); - if (timeout <= 0) { - printk(KERN_ERR "i2sbus: error waiting for dma stop\n"); - result = -ENXIO; - goto out_unlock; - } - /* again, write dma command buffer address to the dbdma chip, - * this time of the first real command */ - *pi->dbdma_ring.cmds = tmp; - out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); - /* post write */ - mb(); - (void)in_le32(&pi->dbdma->status); - - /* reset dma engine again */ - out_le32(&pi->dbdma->control, - 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); - timeout = 100; - while (in_le32(&pi->dbdma->status) & RUN && timeout--) - udelay(1); - if (timeout <= 0) { - printk(KERN_ERR - "i2sbus: error waiting for dma reset\n"); - result = -ENXIO; - goto out_unlock; - } - /* wake up the chip with the next descriptor */ - out_le32(&pi->dbdma->control, - (RUN | WAKE) | ((RUN | WAKE) << 16)); - /* get the frame count */ + /* initialize the frame count and current period */ + pi->current_period = 0; pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); + /* set the DMA controller running */ + out_le32(&pi->dbdma->control, (RUN << 16) | RUN); + /* off you go! */ break; + case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (!pi->dbdma_ring.running) { result = -EALREADY; goto out_unlock; } + pi->dbdma_ring.running = 0; - /* turn off all relevant bits */ - out_le32(&pi->dbdma->control, - (RUN | WAKE | FLUSH | PAUSE) << 16); - { - /* FIXME: move to own function */ - int timeout = 5000; - while ((in_le32(&pi->dbdma->status) & RUN) - && --timeout > 0) - udelay(1); - if (!timeout) - printk(KERN_ERR - "i2sbus: timed out turning " - "off dbdma engine!\n"); - } + /* Set the S0 bit to make the DMA branch to the stop cmd */ + out_le32(&pi->dbdma->control, (1 << 16) | 1); + pi->dbdma_ring.stopping = 1; - pi->dbdma_ring.running = 0; list_for_each_entry(cii, &i2sdev->sound.codec_list, list) if (cii->codec->stop) cii->codec->stop(cii, pi->substream); @@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) fc = in_le32(&i2sdev->intfregs->frame_count); fc = fc - pi->frame_count; - return (bytes_to_frames(pi->substream->runtime, - pi->current_period * - snd_pcm_lib_period_bytes(pi->substream)) - + fc) % pi->substream->runtime->buffer_size; + if (fc >= pi->substream->runtime->buffer_size) + fc %= pi->substream->runtime->buffer_size; + return fc; } static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) { struct pcm_info *pi; - u32 fc; - u32 delta; + u32 fc, nframes; + u32 status; + int timeout, i; + int dma_stopped = 0; + struct snd_pcm_runtime *runtime; spin_lock(&i2sdev->low_lock); get_pcm_info(i2sdev, in, &pi, NULL); - - if (!pi->dbdma_ring.running) { - /* there was still an interrupt pending - * while we stopped. or maybe another - * processor (not the one that was stopping - * the DMA engine) was spinning above - * waiting for the lock. */ + if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping) goto out_unlock; - } - fc = in_le32(&i2sdev->intfregs->frame_count); - /* a counter overflow does not change the calculation. */ - delta = fc - pi->frame_count; - - /* update current_period */ - while (delta >= pi->substream->runtime->period_size) { - pi->current_period++; - delta = delta - pi->substream->runtime->period_size; - } - - if (unlikely(delta)) { - /* Some interrupt came late, so check the dbdma. - * This special case exists to syncronize the frame_count with - * the dbdma transfer, but is hit every once in a while. */ - int period; - - period = (in_le32(&pi->dbdma->cmdptr) - - pi->dbdma_ring.bus_cmd_start) - / sizeof(struct dbdma_cmd); - pi->current_period = pi->current_period - % pi->substream->runtime->periods; - - while (pi->current_period != period) { - pi->current_period++; - pi->current_period %= pi->substream->runtime->periods; - /* Set delta to zero, as the frame_count value is too - * high (otherwise the code path will not be executed). - * This corrects the fact that the frame_count is too - * low at the beginning due to buffering. */ - delta = 0; + i = pi->current_period; + runtime = pi->substream->runtime; + while (pi->dbdma_ring.cmds[i].xfer_status) { + if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT) + /* + * BT is the branch taken bit. If it took a branch + * it is because we set the S0 bit to make it + * branch to the stop command. + */ + dma_stopped = 1; + pi->dbdma_ring.cmds[i].xfer_status = 0; + + if (++i >= runtime->periods) { + i = 0; + pi->frame_count += runtime->buffer_size; } + pi->current_period = i; + + /* + * Check the frame count. The DMA tends to get a bit + * ahead of the frame counter, which confuses the core. + */ + fc = in_le32(&i2sdev->intfregs->frame_count); + nframes = i * runtime->period_size; + if (fc < pi->frame_count + nframes) + pi->frame_count = fc - nframes; } - pi->frame_count = fc - delta; - pi->current_period %= pi->substream->runtime->periods; + if (dma_stopped) { + timeout = 1000; + for (;;) { + status = in_le32(&pi->dbdma->status); + if (!(status & ACTIVE) && (!in || (status & 0x80))) + break; + if (--timeout <= 0) { + printk(KERN_ERR "i2sbus: timed out " + "waiting for DMA to stop!\n"); + break; + } + udelay(1); + } + + /* Turn off DMA controller, clear S0 bit */ + out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + + pi->dbdma_ring.stopping = 0; + if (pi->stop_completion) + complete(pi->stop_completion); + } + if (!pi->dbdma_ring.running) + goto out_unlock; spin_unlock(&i2sdev->low_lock); /* may call _trigger again, hence needs to be unlocked */ snd_pcm_period_elapsed(pi->substream); return; + out_unlock: spin_unlock(&i2sdev->low_lock); } @@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = { .close = i2sbus_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = i2sbus_hw_params, - .hw_free = i2sbus_hw_free, + .hw_free = i2sbus_playback_hw_free, .prepare = i2sbus_playback_prepare, .trigger = i2sbus_playback_trigger, .pointer = i2sbus_playback_pointer, @@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = { .close = i2sbus_record_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = i2sbus_hw_params, - .hw_free = i2sbus_hw_free, + .hw_free = i2sbus_record_hw_free, .prepare = i2sbus_record_prepare, .trigger = i2sbus_record_trigger, .pointer = i2sbus_record_pointer, @@ -812,7 +872,6 @@ static void i2sbus_private_free(struct snd_pcm *pcm) module_put(THIS_MODULE); } -/* FIXME: this function needs an error handling strategy with labels */ int i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, struct codec_info *ci, void *data) @@ -880,41 +939,31 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, if (!cii->sdev) { printk(KERN_DEBUG "i2sbus: failed to get soundbus dev reference\n"); - kfree(cii); - return -ENODEV; + err = -ENODEV; + goto out_free_cii; } if (!try_module_get(THIS_MODULE)) { printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); - soundbus_dev_put(dev); - kfree(cii); - return -EBUSY; + err = -EBUSY; + goto out_put_sdev; } if (!try_module_get(ci->owner)) { printk(KERN_DEBUG "i2sbus: failed to get module reference to codec owner!\n"); - module_put(THIS_MODULE); - soundbus_dev_put(dev); - kfree(cii); - return -EBUSY; + err = -EBUSY; + goto out_put_this_module; } if (!dev->pcm) { - err = snd_pcm_new(card, - dev->pcmname, - dev->pcmid, - 0, - 0, + err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0, &dev->pcm); if (err) { printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); - kfree(cii); - module_put(ci->owner); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + goto out_put_ci_module; } + dev->pcm->dev = &dev->ofdev.dev; } /* ALSA yet again sucks. @@ -926,20 +975,12 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, /* eh? */ printk(KERN_ERR "Can't attach same bus to different cards!\n"); - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return -EINVAL; - } - if ((err = - snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) { - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + err = -EINVAL; + goto out_put_ci_module; } + err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1); + if (err) + goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &i2sbus_playback_ops); i2sdev->out.created = 1; @@ -949,20 +990,11 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, if (dev->pcm->card != card) { printk(KERN_ERR "Can't attach same bus to different cards!\n"); - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return -EINVAL; - } - if ((err = - snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) { - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + goto out_put_ci_module; } + err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1); + if (err) + goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &i2sbus_record_ops); i2sdev->in.created = 1; @@ -977,11 +1009,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, err = snd_device_register(card, dev->pcm); if (err) { printk(KERN_ERR "i2sbus: error registering new pcm\n"); - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + goto out_put_ci_module; } /* no errors any more, so let's add this to our list */ list_add(&cii->list, &dev->codec_list); @@ -996,6 +1024,15 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, 64 * 1024, 64 * 1024); return 0; + out_put_ci_module: + module_put(ci->owner); + out_put_this_module: + module_put(THIS_MODULE); + out_put_sdev: + soundbus_dev_put(dev); + out_free_cii: + kfree(cii); + return err; } void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index ec20ee615d7f..ff29654782c9 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h @@ -10,6 +10,7 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/mutex.h> +#include <linux/completion.h> #include <sound/pcm.h> @@ -34,6 +35,7 @@ struct dbdma_command_mem { void *space; int size; u32 running:1; + u32 stopping:1; }; struct pcm_info { @@ -45,6 +47,7 @@ struct pcm_info { u32 frame_count; struct dbdma_command_mem dbdma_ring; volatile struct dbdma_regs __iomem *dbdma; + struct completion *stop_completion; }; enum { @@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid); extern irqreturn_t i2sbus_rx_intr(int irq, void *devid); +extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev); +extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev); + /* control specific functions */ extern int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c); diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h index 06295190606c..9175ff9ded01 100644 --- a/sound/arm/aaci.h +++ b/sound/arm/aaci.h @@ -228,7 +228,7 @@ struct aaci { /* AC'97 */ struct mutex ac97_sem; - ac97_bus_t *ac97_bus; + struct snd_ac97_bus *ac97_bus; u32 maincr; spinlock_t lock; diff --git a/sound/core/control.c b/sound/core/control.c index 0c7bcd62e5b2..42bcf2794b28 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -108,7 +108,6 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) static int snd_ctl_release(struct inode *inode, struct file *file) { unsigned long flags; - struct list_head *list; struct snd_card *card; struct snd_ctl_file *ctl; struct snd_kcontrol *control; @@ -122,12 +121,10 @@ static int snd_ctl_release(struct inode *inode, struct file *file) list_del(&ctl->list); write_unlock_irqrestore(&card->ctl_files_rwlock, flags); down_write(&card->controls_rwsem); - list_for_each(list, &card->controls) { - control = snd_kcontrol(list); + list_for_each_entry(control, &card->controls, list) for (idx = 0; idx < control->count; idx++) if (control->vd[idx].owner == ctl) control->vd[idx].owner = NULL; - } up_write(&card->controls_rwsem); snd_ctl_empty_read_queue(ctl); kfree(ctl); @@ -140,7 +137,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, struct snd_ctl_elem_id *id) { unsigned long flags; - struct list_head *flist; struct snd_ctl_file *ctl; struct snd_kctl_event *ev; @@ -149,14 +145,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) card->mixer_oss_change_count++; #endif - list_for_each(flist, &card->ctl_files) { - struct list_head *elist; - ctl = snd_ctl_file(flist); + list_for_each_entry(ctl, &card->ctl_files, list) { if (!ctl->subscribed) continue; spin_lock_irqsave(&ctl->read_lock, flags); - list_for_each(elist, &ctl->events) { - ev = snd_kctl_event(elist); + list_for_each_entry(ev, &ctl->events, list) { if (ev->id.numid == id->numid) { ev->mask |= mask; goto _found; @@ -190,7 +183,8 @@ EXPORT_SYMBOL(snd_ctl_notify); * * Returns the pointer of the new instance, or NULL on failure. */ -struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access) +static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, + unsigned int access) { struct snd_kcontrol *kctl; unsigned int idx; @@ -208,8 +202,6 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce return kctl; } -EXPORT_SYMBOL(snd_ctl_new); - /** * snd_ctl_new1 - create a control instance from the template * @ncontrol: the initialization record @@ -277,11 +269,9 @@ EXPORT_SYMBOL(snd_ctl_free_one); static unsigned int snd_ctl_hole_check(struct snd_card *card, unsigned int count) { - struct list_head *list; struct snd_kcontrol *kctl; - list_for_each(list, &card->controls) { - kctl = snd_kcontrol(list); + list_for_each_entry(kctl, &card->controls, list) { if ((kctl->id.numid <= card->last_numid && kctl->id.numid + kctl->count > card->last_numid) || (kctl->id.numid <= card->last_numid + count - 1 && @@ -498,12 +488,10 @@ EXPORT_SYMBOL(snd_ctl_rename_id); */ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) { - struct list_head *list; struct snd_kcontrol *kctl; snd_assert(card != NULL && numid != 0, return NULL); - list_for_each(list, &card->controls) { - kctl = snd_kcontrol(list); + list_for_each_entry(kctl, &card->controls, list) { if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) return kctl; } @@ -527,14 +515,12 @@ EXPORT_SYMBOL(snd_ctl_find_numid); struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, struct snd_ctl_elem_id *id) { - struct list_head *list; struct snd_kcontrol *kctl; snd_assert(card != NULL && id != NULL, return NULL); if (id->numid != 0) return snd_ctl_find_numid(card, id->numid); - list_for_each(list, &card->controls) { - kctl = snd_kcontrol(list); + list_for_each_entry(kctl, &card->controls, list) { if (kctl->id.iface != id->iface) continue; if (kctl->id.device != id->device) @@ -1182,7 +1168,6 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg { struct snd_ctl_file *ctl; struct snd_card *card; - struct list_head *list; struct snd_kctl_ioctl *p; void __user *argp = (void __user *)arg; int __user *ip = argp; @@ -1232,8 +1217,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg #endif } down_read(&snd_ioctl_rwsem); - list_for_each(list, &snd_control_ioctls) { - p = list_entry(list, struct snd_kctl_ioctl, list); + list_for_each_entry(p, &snd_control_ioctls, list) { err = p->fioctl(card, ctl, cmd, arg); if (err != -ENOIOCTLCMD) { up_read(&snd_ioctl_rwsem); @@ -1357,13 +1341,11 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl_compat); static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists) { - struct list_head *list; struct snd_kctl_ioctl *p; snd_assert(fcn != NULL, return -EINVAL); down_write(&snd_ioctl_rwsem); - list_for_each(list, lists) { - p = list_entry(list, struct snd_kctl_ioctl, list); + list_for_each_entry(p, lists, list) { if (p->fioctl == fcn) { list_del(&p->list); up_write(&snd_ioctl_rwsem); @@ -1453,7 +1435,6 @@ static int snd_ctl_dev_register(struct snd_device *device) static int snd_ctl_dev_disconnect(struct snd_device *device) { struct snd_card *card = device->device_data; - struct list_head *flist; struct snd_ctl_file *ctl; int err, cardnum; @@ -1462,8 +1443,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); down_read(&card->controls_rwsem); - list_for_each(flist, &card->ctl_files) { - ctl = snd_ctl_file(flist); + list_for_each_entry(ctl, &card->ctl_files, list) { wake_up(&ctl->change_sleep); kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); } diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index ab48962c48ce..9311ca397bbc 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -392,7 +392,7 @@ enum { static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_ctl_file *ctl; - struct list_head *list; + struct snd_kctl_ioctl *p; void __user *argp = compat_ptr(arg); int err; @@ -427,8 +427,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns } down_read(&snd_ioctl_rwsem); - list_for_each(list, &snd_control_compat_ioctls) { - struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, list); + list_for_each_entry(p, &snd_control_compat_ioctls, list) { if (p->fioctl) { err = p->fioctl(ctl->card, ctl, cmd, arg); if (err != -ENOIOCTLCMD) { diff --git a/sound/core/device.c b/sound/core/device.c index ccb25816ac9e..5858b02b0b1d 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -79,13 +79,11 @@ EXPORT_SYMBOL(snd_device_new); */ int snd_device_free(struct snd_card *card, void *device_data) { - struct list_head *list; struct snd_device *dev; snd_assert(card != NULL, return -ENXIO); snd_assert(device_data != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->device_data != device_data) continue; /* unlink */ @@ -124,13 +122,11 @@ EXPORT_SYMBOL(snd_device_free); */ int snd_device_disconnect(struct snd_card *card, void *device_data) { - struct list_head *list; struct snd_device *dev; snd_assert(card != NULL, return -ENXIO); snd_assert(device_data != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->device_data != device_data) continue; if (dev->state == SNDRV_DEV_REGISTERED && @@ -161,14 +157,12 @@ int snd_device_disconnect(struct snd_card *card, void *device_data) */ int snd_device_register(struct snd_card *card, void *device_data) { - struct list_head *list; struct snd_device *dev; int err; snd_assert(card != NULL, return -ENXIO); snd_assert(device_data != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->device_data != device_data) continue; if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { @@ -192,13 +186,11 @@ EXPORT_SYMBOL(snd_device_register); */ int snd_device_register_all(struct snd_card *card) { - struct list_head *list; struct snd_device *dev; int err; snd_assert(card != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { if ((err = dev->ops->dev_register(dev)) < 0) return err; @@ -215,12 +207,10 @@ int snd_device_register_all(struct snd_card *card) int snd_device_disconnect_all(struct snd_card *card) { struct snd_device *dev; - struct list_head *list; int err = 0; snd_assert(card != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (snd_device_disconnect(card, dev->device_data) < 0) err = -ENXIO; } @@ -234,7 +224,6 @@ int snd_device_disconnect_all(struct snd_card *card) int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) { struct snd_device *dev; - struct list_head *list; int err; unsigned int range_low, range_high; @@ -242,8 +231,7 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE; range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; __again: - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->type >= range_low && dev->type <= range_high) { if ((err = snd_device_free(card, dev->device_data)) < 0) return err; diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 46b47689362c..39c03f3dfbfa 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -47,14 +47,11 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device); static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) { - struct list_head *p; struct snd_hwdep *hwdep; - list_for_each(p, &snd_hwdep_devices) { - hwdep = list_entry(p, struct snd_hwdep, list); + list_for_each_entry(hwdep, &snd_hwdep_devices, list) if (hwdep->card == card && hwdep->device == device) return hwdep; - } return NULL; } @@ -159,15 +156,16 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) int err = -ENXIO; struct snd_hwdep *hw = file->private_data; struct module *mod = hw->card->module; + mutex_lock(&hw->open_mutex); - if (hw->ops.release) { + if (hw->ops.release) err = hw->ops.release(hw, file); - wake_up(&hw->open_wait); - } if (hw->used > 0) hw->used--; - snd_card_file_remove(hw->card, file); mutex_unlock(&hw->open_mutex); + wake_up(&hw->open_wait); + + snd_card_file_remove(hw->card, file); module_put(mod); return err; } @@ -468,15 +466,12 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) static void snd_hwdep_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct list_head *p; struct snd_hwdep *hwdep; mutex_lock(®ister_mutex); - list_for_each(p, &snd_hwdep_devices) { - hwdep = list_entry(p, struct snd_hwdep, list); + list_for_each_entry(hwdep, &snd_hwdep_devices, list) snd_iprintf(buffer, "%02i-%02i: %s\n", hwdep->card->number, hwdep->device, hwdep->name); - } mutex_unlock(®ister_mutex); } diff --git a/sound/core/init.c b/sound/core/init.c index a4cc6b155ae9..db6103733742 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -114,22 +114,28 @@ struct snd_card *snd_card_new(int idx, const char *xid, if (idx < 0) { int idx2; for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) + /* idx == -1 == 0xffff means: take any free slot */ if (~snd_cards_lock & idx & 1<<idx2) { idx = idx2; if (idx >= snd_ecards_limit) snd_ecards_limit = idx + 1; break; } - } else if (idx < snd_ecards_limit) { - if (snd_cards_lock & (1 << idx)) - err = -ENODEV; /* invalid */ - } else if (idx < SNDRV_CARDS) - snd_ecards_limit = idx + 1; /* increase the limit */ - else - err = -ENODEV; + } else { + if (idx < snd_ecards_limit) { + if (snd_cards_lock & (1 << idx)) + err = -EBUSY; /* invalid */ + } else { + if (idx < SNDRV_CARDS) + snd_ecards_limit = idx + 1; /* increase the limit */ + else + err = -ENODEV; + } + } if (idx < 0 || err < 0) { mutex_unlock(&snd_card_mutex); - snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); + snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", + idx, snd_ecards_limit - 1, err); goto __error; } snd_cards_lock |= 1 << idx; /* lock it */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index bc0bd0910a62..f057430db0d0 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -406,19 +406,17 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) */ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) { - struct list_head *p; struct snd_mem_list *mem; snd_assert(dmab, return 0); mutex_lock(&list_mutex); - list_for_each(p, &mem_list_head) { - mem = list_entry(p, struct snd_mem_list, list); + list_for_each_entry(mem, &mem_list_head, list) { if (mem->id == id && (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { struct device *dev = dmab->dev.dev; - list_del(p); + list_del(&mem->list); *dmab = mem->buffer; if (dmab->dev.dev == NULL) dmab->dev.dev = dev; @@ -488,7 +486,6 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, { int len = 0; long pages = snd_allocated_pages >> (PAGE_SHIFT-12); - struct list_head *p; struct snd_mem_list *mem; int devno; static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; @@ -498,8 +495,7 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, "pages : %li bytes (%li pages per %likB)\n", pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); devno = 0; - list_for_each(p, &mem_list_head) { - mem = list_entry(p, struct snd_mem_list, list); + list_for_each_entry(mem, &mem_list_head, list) { devno++; len += snprintf(page + len, count - len, "buffer %d : ID %08x : type %s\n", diff --git a/sound/core/misc.c b/sound/core/misc.c index 03fc711f4127..6db86a7c9704 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -78,3 +78,31 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) EXPORT_SYMBOL(snd_verbose_printd); #endif + +#ifdef CONFIG_PCI +#include <linux/pci.h> +/** + * snd_pci_quirk_lookup - look up a PCI SSID quirk list + * @pci: pci_dev handle + * @list: quirk list, terminated by a null entry + * + * Look through the given quirk list and finds a matching entry + * with the same PCI SSID. When subdevice is 0, all subdevice + * values may match. + * + * Returns the matched entry pointer, or NULL if nothing matched. + */ +const struct snd_pci_quirk * +snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) +{ + const struct snd_pci_quirk *q; + + for (q = list; q->subvendor; q++) + if (q->subvendor == pci->subsystem_vendor && + (!q->subdevice || q->subdevice == pci->subsystem_device)) + return q; + return NULL; +} + +EXPORT_SYMBOL(snd_pci_quirk_lookup); +#endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e0189885516..2743414fc8fa 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -45,11 +45,9 @@ static int snd_pcm_dev_disconnect(struct snd_device *device); static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) { - struct list_head *p; struct snd_pcm *pcm; - list_for_each(p, &snd_pcm_devices) { - pcm = list_entry(p, struct snd_pcm, list); + list_for_each_entry(pcm, &snd_pcm_devices, list) { if (pcm->card == card && pcm->device == device) return pcm; } @@ -782,7 +780,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct snd_pcm_runtime *runtime; struct snd_ctl_file *kctl; struct snd_card *card; - struct list_head *list; int prefer_subdevice = -1; size_t size; @@ -795,8 +792,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, card = pcm->card; down_read(&card->controls_rwsem); - list_for_each(list, &card->ctl_files) { - kctl = snd_ctl_file(list); + list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == current->pid) { prefer_subdevice = kctl->prefer_pcm_subdevice; if (prefer_subdevice != -1) @@ -941,9 +937,10 @@ static int snd_pcm_dev_register(struct snd_device *device) { int cidx, err; struct snd_pcm_substream *substream; - struct list_head *list; + struct snd_pcm_notify *notify; char str[16]; struct snd_pcm *pcm = device->device_data; + struct device *dev; snd_assert(pcm != NULL && device != NULL, return -ENXIO); mutex_lock(®ister_mutex); @@ -966,11 +963,18 @@ static int snd_pcm_dev_register(struct snd_device *device) devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; break; } - if ((err = snd_register_device(devtype, pcm->card, - pcm->device, - &snd_pcm_f_ops[cidx], - pcm, str)) < 0) - { + /* device pointer to use, pcm->dev takes precedence if + * it is assigned, otherwise fall back to card's device + * if possible */ + dev = pcm->dev; + if (!dev) + dev = snd_card_get_device_link(pcm->card); + /* register pcm */ + err = snd_register_device_for_dev(devtype, pcm->card, + pcm->device, + &snd_pcm_f_ops[cidx], + pcm, str, dev); + if (err < 0) { list_del(&pcm->list); mutex_unlock(®ister_mutex); return err; @@ -980,11 +984,10 @@ static int snd_pcm_dev_register(struct snd_device *device) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) snd_pcm_timer_init(substream); } - list_for_each(list, &snd_pcm_notify_list) { - struct snd_pcm_notify *notify; - notify = list_entry(list, struct snd_pcm_notify, list); + + list_for_each_entry(notify, &snd_pcm_notify_list, list) notify->n_register(pcm); - } + mutex_unlock(®ister_mutex); return 0; } @@ -1027,7 +1030,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) { - struct list_head *p; + struct snd_pcm *pcm; snd_assert(notify != NULL && notify->n_register != NULL && @@ -1036,13 +1039,12 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) mutex_lock(®ister_mutex); if (nfree) { list_del(¬ify->list); - list_for_each(p, &snd_pcm_devices) - notify->n_unregister(list_entry(p, - struct snd_pcm, list)); + list_for_each_entry(pcm, &snd_pcm_devices, list) + notify->n_unregister(pcm); } else { list_add_tail(¬ify->list, &snd_pcm_notify_list); - list_for_each(p, &snd_pcm_devices) - notify->n_register(list_entry(p, struct snd_pcm, list)); + list_for_each_entry(pcm, &snd_pcm_devices, list) + notify->n_register(pcm); } mutex_unlock(®ister_mutex); return 0; @@ -1058,12 +1060,10 @@ EXPORT_SYMBOL(snd_pcm_notify); static void snd_pcm_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct list_head *p; struct snd_pcm *pcm; mutex_lock(®ister_mutex); - list_for_each(p, &snd_pcm_devices) { - pcm = list_entry(p, struct snd_pcm, list); + list_for_each_entry(pcm, &snd_pcm_devices, list) { snd_iprintf(buffer, "%02i-%02i: %s : %s", pcm->card->number, pcm->device, pcm->id, pcm->name); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b336797be4fc..9fefcaa2c324 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -781,6 +781,11 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int * { unsigned int k; int changed = 0; + + if (!count) { + i->empty = 1; + return -EINVAL; + } for (k = 0; k < count; k++) { if (mask && !(mask & (1 << k))) continue; diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index be030cb4d373..95b1b2f0b1e2 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -101,6 +101,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) { snd_pcm_lib_preallocate_dma_free(substream); #ifdef CONFIG_SND_VERBOSE_PROCFS + snd_info_free_entry(substream->proc_prealloc_max_entry); + substream->proc_prealloc_max_entry = NULL; snd_info_free_entry(substream->proc_prealloc_entry); substream->proc_prealloc_entry = NULL; #endif @@ -142,6 +144,18 @@ static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry, } /* + * read callback for prealloc_max proc file + * + * prints the maximum allowed size in kB. + */ +static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_pcm_substream *substream = entry->private_data; + snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024); +} + +/* * write callback for prealloc proc file * * accepts the preallocation size in kB. @@ -203,6 +217,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) } } substream->proc_prealloc_entry = entry; + if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) { + entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read; + entry->private_data = substream; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + substream->proc_prealloc_max_entry = entry; } #else /* !CONFIG_SND_VERBOSE_PROCFS */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0f055bfcbdac..7e6ceec738d5 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -61,14 +61,11 @@ static DEFINE_MUTEX(register_mutex); static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) { - struct list_head *p; struct snd_rawmidi *rawmidi; - list_for_each(p, &snd_rawmidi_devices) { - rawmidi = list_entry(p, struct snd_rawmidi, list); + list_for_each_entry(rawmidi, &snd_rawmidi_devices, list) if (rawmidi->card == card && rawmidi->device == device) return rawmidi; - } return NULL; } @@ -389,7 +386,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) struct snd_rawmidi *rmidi; struct snd_rawmidi_file *rawmidi_file; wait_queue_t wait; - struct list_head *list; struct snd_ctl_file *kctl; if (maj == snd_major) { @@ -426,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) while (1) { subdevice = -1; down_read(&card->controls_rwsem); - list_for_each(list, &card->ctl_files) { - kctl = snd_ctl_file(list); + list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == current->pid) { subdevice = kctl->prefer_rawmidi_subdevice; if (subdevice != -1) @@ -575,7 +570,6 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info struct snd_rawmidi *rmidi; struct snd_rawmidi_str *pstr; struct snd_rawmidi_substream *substream; - struct list_head *list; mutex_lock(®ister_mutex); rmidi = snd_rawmidi_search(card, info->device); @@ -589,8 +583,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info return -ENOENT; if (info->subdevice >= pstr->substream_count) return -ENXIO; - list_for_each(list, &pstr->substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, &pstr->substreams, list) { if ((unsigned int)substream->number == info->subdevice) return snd_rawmidi_info(substream, info); } @@ -1313,14 +1306,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; - struct list_head *list; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); mutex_lock(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { - list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, + list) { snd_iprintf(buffer, "Output %d\n" " Tx bytes : %lu\n", @@ -1339,8 +1332,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, } } if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) { - list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, + list) { snd_iprintf(buffer, "Input %d\n" " Rx bytes : %lu\n", @@ -1625,13 +1619,10 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, struct snd_rawmidi_ops *ops) { - struct list_head *list; struct snd_rawmidi_substream *substream; - list_for_each(list, &rmidi->streams[stream].substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) substream->ops = ops; - } } /* diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 532a660df51d..bb9dd9fa8e51 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -659,7 +659,6 @@ static int deliver_to_subscribers(struct snd_seq_client *client, int err = 0, num_ev = 0; struct snd_seq_event event_saved; struct snd_seq_client_port *src_port; - struct list_head *p; struct snd_seq_port_subs_info *grp; src_port = snd_seq_port_use_ptr(client, event->source.port); @@ -674,8 +673,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client, read_lock(&grp->list_lock); else down_read(&grp->list_mutex); - list_for_each(p, &grp->list_head) { - subs = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(subs, &grp->list_head, src_list) { event->dest = subs->info.dest; if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) /* convert time according to flag with subscription */ @@ -709,15 +707,14 @@ static int port_broadcast_event(struct snd_seq_client *client, { int num_ev = 0, err = 0; struct snd_seq_client *dest_client; - struct list_head *p; + struct snd_seq_client_port *port; dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST); if (dest_client == NULL) return 0; /* no matching destination */ read_lock(&dest_client->ports_lock); - list_for_each(p, &dest_client->ports_list_head) { - struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list); + list_for_each_entry(port, &dest_client->ports_list_head, list) { event->dest.port = port->addr.port; /* pass NULL as source client to avoid error bounce */ err = snd_seq_deliver_single_event(NULL, event, @@ -2473,11 +2470,10 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer, static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, struct snd_seq_client *client) { - struct list_head *l; + struct snd_seq_client_port *p; mutex_lock(&client->ports_mutex); - list_for_each(l, &client->ports_list_head) { - struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); + list_for_each_entry(p, &client->ports_list_head, list) { snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n", p->addr.port, p->name, FLAG_PERM_RD(p->capability), diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index b79d011813c0..37852cdace76 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -106,11 +106,10 @@ static void remove_drivers(void); static void snd_seq_device_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct list_head *head; + struct ops_list *ops; mutex_lock(&ops_mutex); - list_for_each(head, &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); + list_for_each_entry(ops, &opslist, list) { snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", ops->id, ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), @@ -143,7 +142,7 @@ void snd_seq_autoload_unlock(void) void snd_seq_device_load_drivers(void) { #ifdef CONFIG_KMOD - struct list_head *head; + struct ops_list *ops; /* Calling request_module during module_init() * may cause blocking. @@ -155,8 +154,7 @@ void snd_seq_device_load_drivers(void) return; mutex_lock(&ops_mutex); - list_for_each(head, &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); + list_for_each_entry(ops, &opslist, list) { if (! (ops->driver & DRIVER_LOADED) && ! (ops->driver & DRIVER_REQUESTED)) { ops->used++; @@ -314,8 +312,8 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize) { - struct list_head *head; struct ops_list *ops; + struct snd_seq_device *dev; if (id == NULL || entry == NULL || entry->init_device == NULL || entry->free_device == NULL) @@ -341,8 +339,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, ops->argsize = argsize; /* initialize existing devices if necessary */ - list_for_each(head, &ops->dev_list) { - struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list); + list_for_each_entry(dev, &ops->dev_list, list) { init_device(dev, ops); } mutex_unlock(&ops->reg_mutex); @@ -394,8 +391,8 @@ static struct ops_list * create_driver(char *id) */ int snd_seq_device_unregister_driver(char *id) { - struct list_head *head; struct ops_list *ops; + struct snd_seq_device *dev; ops = find_driver(id, 0); if (ops == NULL) @@ -411,8 +408,7 @@ int snd_seq_device_unregister_driver(char *id) /* close and release all devices associated with this driver */ mutex_lock(&ops->reg_mutex); ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ - list_for_each(head, &ops->dev_list) { - struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list); + list_for_each_entry(dev, &ops->dev_list, list) { free_device(dev, ops); } @@ -512,11 +508,10 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops) */ static struct ops_list * find_driver(char *id, int create_if_empty) { - struct list_head *head; + struct ops_list *ops; mutex_lock(&ops_mutex); - list_for_each(head, &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); + list_for_each_entry(ops, &opslist, list) { if (strcmp(ops->id, id) == 0) { ops->used++; mutex_unlock(&ops_mutex); diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 8c64b58ff77b..eefd1cf872b4 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -59,14 +59,12 @@ much elements are in array. struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, int num) { - struct list_head *p; struct snd_seq_client_port *port; if (client == NULL) return NULL; read_lock(&client->ports_lock); - list_for_each(p, &client->ports_list_head) { - port = list_entry(p, struct snd_seq_client_port, list); + list_for_each_entry(port, &client->ports_list_head, list) { if (port->addr.port == num) { if (port->closing) break; /* deleting now */ @@ -85,14 +83,12 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl struct snd_seq_port_info *pinfo) { int num; - struct list_head *p; struct snd_seq_client_port *port, *found; num = pinfo->addr.port; found = NULL; read_lock(&client->ports_lock); - list_for_each(p, &client->ports_list_head) { - port = list_entry(p, struct snd_seq_client_port, list); + list_for_each_entry(port, &client->ports_list_head, list) { if (port->addr.port < num) continue; if (port->addr.port == num) { @@ -131,8 +127,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port) { unsigned long flags; - struct snd_seq_client_port *new_port; - struct list_head *l; + struct snd_seq_client_port *new_port, *p; int num = -1; /* sanity check */ @@ -161,15 +156,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, num = port >= 0 ? port : 0; mutex_lock(&client->ports_mutex); write_lock_irqsave(&client->ports_lock, flags); - list_for_each(l, &client->ports_list_head) { - struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); + list_for_each_entry(p, &client->ports_list_head, list) { if (p->addr.port > num) break; if (port < 0) /* auto-probe mode */ num = p->addr.port + 1; } /* insert the new port */ - list_add_tail(&new_port->list, l); + list_add_tail(&new_port->list, &p->list); client->num_ports++; new_port->addr.port = num; /* store the port number in the port */ write_unlock_irqrestore(&client->ports_lock, flags); @@ -251,9 +245,9 @@ static void clear_subscriber_list(struct snd_seq_client *client, list_del(&subs->dest_list); else list_del(&subs->src_list); + up_write(&agrp->list_mutex); unsubscribe_port(c, aport, agrp, &subs->info, 1); kfree(subs); - up_write(&agrp->list_mutex); snd_seq_port_unlock(aport); snd_seq_client_unlock(c); } @@ -287,16 +281,14 @@ static int port_delete(struct snd_seq_client *client, int snd_seq_delete_port(struct snd_seq_client *client, int port) { unsigned long flags; - struct list_head *l; - struct snd_seq_client_port *found = NULL; + struct snd_seq_client_port *found = NULL, *p; mutex_lock(&client->ports_mutex); write_lock_irqsave(&client->ports_lock, flags); - list_for_each(l, &client->ports_list_head) { - struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); + list_for_each_entry(p, &client->ports_list_head, list) { if (p->addr.port == port) { /* ok found. delete from the list at first */ - list_del(l); + list_del(&p->list); client->num_ports--; found = p; break; @@ -314,7 +306,8 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port) int snd_seq_delete_all_ports(struct snd_seq_client *client) { unsigned long flags; - struct list_head deleted_list, *p, *n; + struct list_head deleted_list; + struct snd_seq_client_port *port, *tmp; /* move the port list to deleted_list, and * clear the port list in the client data. @@ -331,9 +324,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client) write_unlock_irqrestore(&client->ports_lock, flags); /* remove each port in deleted_list */ - list_for_each_safe(p, n, &deleted_list) { - struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list); - list_del(p); + list_for_each_entry_safe(port, tmp, &deleted_list, list) { + list_del(&port->list); snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port); port_delete(client, port); } @@ -500,8 +492,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector, { struct snd_seq_port_subs_info *src = &src_port->c_src; struct snd_seq_port_subs_info *dest = &dest_port->c_dest; - struct snd_seq_subscribers *subs; - struct list_head *p; + struct snd_seq_subscribers *subs, *s; int err, src_called = 0; unsigned long flags; int exclusive; @@ -525,13 +516,11 @@ int snd_seq_port_connect(struct snd_seq_client *connector, if (src->exclusive || dest->exclusive) goto __error; /* check whether already exists */ - list_for_each(p, &src->list_head) { - struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(s, &src->list_head, src_list) { if (match_subs_info(info, &s->info)) goto __error; } - list_for_each(p, &dest->list_head) { - struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, dest_list); + list_for_each_entry(s, &dest->list_head, dest_list) { if (match_subs_info(info, &s->info)) goto __error; } @@ -582,7 +571,6 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_port_subs_info *src = &src_port->c_src; struct snd_seq_port_subs_info *dest = &dest_port->c_dest; struct snd_seq_subscribers *subs; - struct list_head *p; int err = -ENOENT; unsigned long flags; @@ -590,8 +578,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); /* look for the connection */ - list_for_each(p, &src->list_head) { - subs = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(subs, &src->list_head, src_list) { if (match_subs_info(info, &subs->info)) { write_lock_irqsave(&src->list_lock, flags); // write_lock(&dest->list_lock); // no lock yet @@ -620,12 +607,10 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, struct snd_seq_addr *dest_addr) { - struct list_head *p; struct snd_seq_subscribers *s, *found = NULL; down_read(&src_grp->list_mutex); - list_for_each(p, &src_grp->list_head) { - s = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(s, &src_grp->list_head, src_list) { if (addr_match(dest_addr, &s->info.dest)) { found = s; break; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 0cfa06c6b81f..972f93405364 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -81,13 +81,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, struct snd_seq_event *ev) { struct snd_virmidi *vmidi; - struct list_head *list; unsigned char msg[4]; int len; read_lock(&rdev->filelist_lock); - list_for_each(list, &rdev->filelist) { - vmidi = list_entry(list, struct snd_virmidi, list); + list_for_each_entry(vmidi, &rdev->filelist, list) { if (!vmidi->trigger) continue; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { diff --git a/sound/core/sound.c b/sound/core/sound.c index 82a61c67cf3a..4084de064127 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -219,26 +219,27 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) #endif /** - * snd_register_device - Register the ALSA device file for the card + * snd_register_device_for_dev - Register the ALSA device file for the card * @type: the device type, SNDRV_DEVICE_TYPE_XXX * @card: the card instance * @dev: the device index * @f_ops: the file operations * @private_data: user pointer for f_ops->open() * @name: the device file name + * @device: the &struct device to link this new device to * * Registers an ALSA device file for the given card. * The operators have to be set in reg parameter. * - * Retrurns zero if successful, or a negative error code on failure. + * Returns zero if successful, or a negative error code on failure. */ -int snd_register_device(int type, struct snd_card *card, int dev, - const struct file_operations *f_ops, void *private_data, - const char *name) +int snd_register_device_for_dev(int type, struct snd_card *card, int dev, + const struct file_operations *f_ops, + void *private_data, + const char *name, struct device *device) { int minor; struct snd_minor *preg; - struct device *device = snd_card_get_device_link(card); snd_assert(name, return -EINVAL); preg = kmalloc(sizeof *preg, GFP_KERNEL); @@ -272,7 +273,7 @@ int snd_register_device(int type, struct snd_card *card, int dev, return 0; } -EXPORT_SYMBOL(snd_register_device); +EXPORT_SYMBOL(snd_register_device_for_dev); /* find the matching minor record * return the index of snd_minor, or -1 if not found diff --git a/sound/core/timer.c b/sound/core/timer.c index 10a79aed33f8..3e0638351069 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -35,9 +35,6 @@ #include <sound/minors.h> #include <sound/initval.h> #include <linux/kmod.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> -#endif #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE) #define DEFAULT_TIMER_LIMIT 3 @@ -130,11 +127,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner, static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) { struct snd_timer *timer = NULL; - struct list_head *p; - - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { if (timer->tmr_class != tid->dev_class) continue; if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD || @@ -184,13 +178,10 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) { struct snd_timer *timer; struct snd_timer_instance *master; - struct list_head *p, *q; /* FIXME: it's really dumb to look up all entries.. */ - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); - list_for_each(q, &timer->open_list_head) { - master = list_entry(q, struct snd_timer_instance, open_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { + list_for_each_entry(master, &timer->open_list_head, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { list_del(&slave->open_list); @@ -214,16 +205,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) */ static void snd_timer_check_master(struct snd_timer_instance *master) { - struct snd_timer_instance *slave; - struct list_head *p, *n; + struct snd_timer_instance *slave, *tmp; /* check all pending slaves */ - list_for_each_safe(p, n, &snd_timer_slave_list) { - slave = list_entry(p, struct snd_timer_instance, open_list); + list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { - list_del(p); - list_add_tail(p, &master->slave_list_head); + list_move_tail(&slave->open_list, &master->slave_list_head); spin_lock_irq(&slave_active_lock); slave->master = master; slave->timer = master->timer; @@ -317,8 +305,7 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int snd_timer_close(struct snd_timer_instance *timeri) { struct snd_timer *timer = NULL; - struct list_head *p, *n; - struct snd_timer_instance *slave; + struct snd_timer_instance *slave, *tmp; snd_assert(timeri != NULL, return -ENXIO); @@ -353,12 +340,11 @@ int snd_timer_close(struct snd_timer_instance *timeri) timer->hw.close) timer->hw.close(timer); /* remove slave links */ - list_for_each_safe(p, n, &timeri->slave_list_head) { - slave = list_entry(p, struct snd_timer_instance, open_list); + list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, + open_list) { spin_lock_irq(&slave_active_lock); _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); - list_del(p); - list_add_tail(p, &snd_timer_slave_list); + list_move_tail(&slave->open_list, &snd_timer_slave_list); slave->master = NULL; slave->timer = NULL; spin_unlock_irq(&slave_active_lock); @@ -394,7 +380,6 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ts; - struct list_head *n; struct timespec tstamp; getnstimeofday(&tstamp); @@ -413,11 +398,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) return; spin_lock_irqsave(&timer->lock, flags); - list_for_each(n, &ti->slave_active_head) { - ts = list_entry(n, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) ts->ccallback(ti, event + 100, &tstamp, resolution); - } spin_unlock_irqrestore(&timer->lock, flags); } @@ -593,10 +576,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l { struct snd_timer_instance *ti; unsigned long ticks = ~0UL; - struct list_head *p; - list_for_each(p, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->flags & SNDRV_TIMER_IFLG_START) { ti->flags &= ~SNDRV_TIMER_IFLG_START; ti->flags |= SNDRV_TIMER_IFLG_RUNNING; @@ -661,9 +642,9 @@ static void snd_timer_tasklet(unsigned long arg) */ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) { - struct snd_timer_instance *ti, *ts; + struct snd_timer_instance *ti, *ts, *tmp; unsigned long resolution, ticks; - struct list_head *p, *q, *n, *ack_list_head; + struct list_head *p, *ack_list_head; unsigned long flags; int use_tasklet = 0; @@ -679,12 +660,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) resolution = timer->hw.resolution; /* loop for all active instances - * Here we cannot use list_for_each because the active_list of a + * Here we cannot use list_for_each_entry because the active_list of a * processed instance is relinked to done_list_head before the callback * is called. */ - list_for_each_safe(p, n, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry_safe(ti, tmp, &timer->active_list_head, + active_list) { if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) continue; ti->pticks += ticks_left; @@ -700,7 +681,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) - list_del(p); + list_del(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) @@ -709,8 +690,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) ack_list_head = &timer->sack_list_head; if (list_empty(&ti->ack_list)) list_add_tail(&ti->ack_list, ack_list_head); - list_for_each(q, &ti->slave_active_head) { - ts = list_entry(q, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) { ts->pticks = ti->pticks; ts->resolution = resolution; if (list_empty(&ts->ack_list)) @@ -844,7 +824,6 @@ static int snd_timer_dev_register(struct snd_device *dev) { struct snd_timer *timer = dev->device_data; struct snd_timer *timer1; - struct list_head *p; snd_assert(timer != NULL && timer->hw.start != NULL && timer->hw.stop != NULL, return -ENXIO); @@ -853,8 +832,7 @@ static int snd_timer_dev_register(struct snd_device *dev) return -EINVAL; mutex_lock(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer1 = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer1, &snd_timer_list, device_list) { if (timer1->tmr_class > timer->tmr_class) break; if (timer1->tmr_class < timer->tmr_class) @@ -877,7 +855,7 @@ static int snd_timer_dev_register(struct snd_device *dev) mutex_unlock(®ister_mutex); return -EBUSY; } - list_add_tail(&timer->device_list, p); + list_add_tail(&timer->device_list, &timer1->device_list); mutex_unlock(®ister_mutex); return 0; } @@ -896,7 +874,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ti, *ts; - struct list_head *p, *n; if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) return; @@ -911,15 +888,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam else resolution = timer->hw.resolution; } - list_for_each(p, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->ccallback) ti->ccallback(ti, event, tstamp, resolution); - list_for_each(n, &ti->slave_active_head) { - ts = list_entry(n, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) ts->ccallback(ts, event, tstamp, resolution); - } } spin_unlock_irqrestore(&timer->lock, flags); } @@ -1057,11 +1031,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, { struct snd_timer *timer; struct snd_timer_instance *ti; - struct list_head *p, *q; mutex_lock(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: snd_iprintf(buffer, "G%i: ", timer->tmr_device); @@ -1088,14 +1060,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) snd_iprintf(buffer, " SLAVE"); snd_iprintf(buffer, "\n"); - list_for_each(q, &timer->open_list_head) { - ti = list_entry(q, struct snd_timer_instance, open_list); + list_for_each_entry(ti, &timer->open_list_head, open_list) snd_iprintf(buffer, " Client %s : %s\n", ti->owner ? ti->owner : "unknown", ti->flags & (SNDRV_TIMER_IFLG_START | SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped"); - } } mutex_unlock(®ister_mutex); } diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 40ebd2f44056..83529b08d019 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -109,4 +109,15 @@ config SND_MPU401 To compile this driver as a module, choose M here: the module will be called snd-mpu401. +config SND_PORTMAN2X4 + tristate "Portman 2x4 driver" + depends on SND && PARPORT + select SND_RAWMIDI + help + Say Y here to include support for Midiman Portman 2x4 parallel + port MIDI device. + + To compile this driver as a module, choose M here: the module + will be called snd-portman2x4. + endmenu diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index c9bad6d67e73..04112642611a 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile @@ -6,6 +6,7 @@ snd-dummy-objs := dummy.o snd-mtpav-objs := mtpav.o snd-mts64-objs := mts64.o +snd-portman2x4-objs := portman2x4.o snd-serial-u16550-objs := serial-u16550.o snd-virmidi-objs := virmidi.o @@ -15,5 +16,6 @@ obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o obj-$(CONFIG_SND_MTS64) += snd-mts64.o +obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 42001efa9f3e..8339bad969ba 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -501,7 +501,7 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, return change; } -static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); #define DUMMY_CAPSRC(xname, xindex, addr) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c new file mode 100644 index 000000000000..6c48772aaefd --- /dev/null +++ b/sound/drivers/portman2x4.c @@ -0,0 +1,876 @@ +/* + * Driver for Midiman Portman2x4 parallel port midi interface + * + * Copyright (c) by Levent Guendogdu <levon@feature-it.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * ChangeLog + * Jan 24 2007 Matthias Koenig <mkoenig@suse.de> + * - cleanup and rewrite + * Sep 30 2004 Tobias Gehrig <tobias@gehrig.tk> + * - source code cleanup + * Sep 03 2004 Tobias Gehrig <tobias@gehrig.tk> + * - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES, + * MODULE_PARM_SYNTAX and changed MODULE_DEVICES to + * MODULE_SUPPORTED_DEVICE) + * Mar 24 2004 Tobias Gehrig <tobias@gehrig.tk> + * - added 2.6 kernel support + * Mar 18 2004 Tobias Gehrig <tobias@gehrig.tk> + * - added parport_unregister_driver to the startup routine if the driver fails to detect a portman + * - added support for all 4 output ports in portman_putmidi + * Mar 17 2004 Tobias Gehrig <tobias@gehrig.tk> + * - added checks for opened input device in interrupt handler + * Feb 20 2004 Tobias Gehrig <tobias@gehrig.tk> + * - ported from alsa 0.5 to 1.0 + */ + +#include <sound/driver.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/parport.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/rawmidi.h> +#include <sound/control.h> + +#define CARD_NAME "Portman 2x4" +#define DRIVER_NAME "portman" +#define PLATFORM_DRIVER "snd_portman2x4" + +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; + +static struct platform_device *platform_devices[SNDRV_CARDS]; +static int device_count; + +module_param_array(index, int, NULL, S_IRUGO); +MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); +module_param_array(id, charp, NULL, S_IRUGO); +MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); +module_param_array(enable, bool, NULL, S_IRUGO); +MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); + +MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig"); +MODULE_DESCRIPTION("Midiman Portman2x4"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}"); + +/********************************************************************* + * Chip specific + *********************************************************************/ +#define PORTMAN_NUM_INPUT_PORTS 2 +#define PORTMAN_NUM_OUTPUT_PORTS 4 + +struct portman { + spinlock_t reg_lock; + struct snd_card *card; + struct snd_rawmidi *rmidi; + struct pardevice *pardev; + int pardev_claimed; + + int open_count; + int mode[PORTMAN_NUM_INPUT_PORTS]; + struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS]; +}; + +static int portman_free(struct portman *pm) +{ + kfree(pm); + return 0; +} + +static int __devinit portman_create(struct snd_card *card, + struct pardevice *pardev, + struct portman **rchip) +{ + struct portman *pm; + + *rchip = NULL; + + pm = kzalloc(sizeof(struct portman), GFP_KERNEL); + if (pm == NULL) + return -ENOMEM; + + /* Init chip specific data */ + spin_lock_init(&pm->reg_lock); + pm->card = card; + pm->pardev = pardev; + + *rchip = pm; + + return 0; +} + +/********************************************************************* + * HW related constants + *********************************************************************/ + +/* Standard PC parallel port status register equates. */ +#define PP_STAT_BSY 0x80 /* Busy status. Inverted. */ +#define PP_STAT_ACK 0x40 /* Acknowledge. Non-Inverted. */ +#define PP_STAT_POUT 0x20 /* Paper Out. Non-Inverted. */ +#define PP_STAT_SEL 0x10 /* Select. Non-Inverted. */ +#define PP_STAT_ERR 0x08 /* Error. Non-Inverted. */ + +/* Standard PC parallel port command register equates. */ +#define PP_CMD_IEN 0x10 /* IRQ Enable. Non-Inverted. */ +#define PP_CMD_SELI 0x08 /* Select Input. Inverted. */ +#define PP_CMD_INIT 0x04 /* Init Printer. Non-Inverted. */ +#define PP_CMD_FEED 0x02 /* Auto Feed. Inverted. */ +#define PP_CMD_STB 0x01 /* Strobe. Inverted. */ + +/* Parallel Port Command Register as implemented by PCP2x4. */ +#define INT_EN PP_CMD_IEN /* Interrupt enable. */ +#define STROBE PP_CMD_STB /* Command strobe. */ + +/* The parallel port command register field (b1..b3) selects the + * various "registers" within the PC/P 2x4. These are the internal + * address of these "registers" that must be written to the parallel + * port command register. + */ +#define RXDATA0 (0 << 1) /* PCP RxData channel 0. */ +#define RXDATA1 (1 << 1) /* PCP RxData channel 1. */ +#define GEN_CTL (2 << 1) /* PCP General Control Register. */ +#define SYNC_CTL (3 << 1) /* PCP Sync Control Register. */ +#define TXDATA0 (4 << 1) /* PCP TxData channel 0. */ +#define TXDATA1 (5 << 1) /* PCP TxData channel 1. */ +#define TXDATA2 (6 << 1) /* PCP TxData channel 2. */ +#define TXDATA3 (7 << 1) /* PCP TxData channel 3. */ + +/* Parallel Port Status Register as implemented by PCP2x4. */ +#define ESTB PP_STAT_POUT /* Echoed strobe. */ +#define INT_REQ PP_STAT_ACK /* Input data int request. */ +#define BUSY PP_STAT_ERR /* Interface Busy. */ + +/* Parallel Port Status Register BUSY and SELECT lines are multiplexed + * between several functions. Depending on which 2x4 "register" is + * currently selected (b1..b3), the BUSY and SELECT lines are + * assigned as follows: + * + * SELECT LINE: A3 A2 A1 + * -------- + */ +#define RXAVAIL PP_STAT_SEL /* Rx Available, channel 0. 0 0 0 */ +// RXAVAIL1 PP_STAT_SEL /* Rx Available, channel 1. 0 0 1 */ +#define SYNC_STAT PP_STAT_SEL /* Reserved - Sync Status. 0 1 0 */ +// /* Reserved. 0 1 1 */ +#define TXEMPTY PP_STAT_SEL /* Tx Empty, channel 0. 1 0 0 */ +// TXEMPTY1 PP_STAT_SEL /* Tx Empty, channel 1. 1 0 1 */ +// TXEMPTY2 PP_STAT_SEL /* Tx Empty, channel 2. 1 1 0 */ +// TXEMPTY3 PP_STAT_SEL /* Tx Empty, channel 3. 1 1 1 */ + +/* BUSY LINE: A3 A2 A1 + * -------- + */ +#define RXDATA PP_STAT_BSY /* Rx Input Data, channel 0. 0 0 0 */ +// RXDATA1 PP_STAT_BSY /* Rx Input Data, channel 1. 0 0 1 */ +#define SYNC_DATA PP_STAT_BSY /* Reserved - Sync Data. 0 1 0 */ + /* Reserved. 0 1 1 */ +#define DATA_ECHO PP_STAT_BSY /* Parallel Port Data Echo. 1 0 0 */ +#define A0_ECHO PP_STAT_BSY /* Address 0 Echo. 1 0 1 */ +#define A1_ECHO PP_STAT_BSY /* Address 1 Echo. 1 1 0 */ +#define A2_ECHO PP_STAT_BSY /* Address 2 Echo. 1 1 1 */ + +#define PORTMAN2X4_MODE_INPUT_TRIGGERED 0x01 + +/********************************************************************* + * Hardware specific functions + *********************************************************************/ +static inline void portman_write_command(struct portman *pm, u8 value) +{ + parport_write_control(pm->pardev->port, value); +} + +static inline u8 portman_read_command(struct portman *pm) +{ + return parport_read_control(pm->pardev->port); +} + +static inline u8 portman_read_status(struct portman *pm) +{ + return parport_read_status(pm->pardev->port); +} + +static inline u8 portman_read_data(struct portman *pm) +{ + return parport_read_data(pm->pardev->port); +} + +static inline void portman_write_data(struct portman *pm, u8 value) +{ + parport_write_data(pm->pardev->port, value); +} + +static void portman_write_midi(struct portman *pm, + int port, u8 mididata) +{ + int command = ((port + 4) << 1); + + /* Get entering data byte and port number in BL and BH respectively. + * Set up Tx Channel address field for use with PP Cmd Register. + * Store address field in BH register. + * Inputs: AH = Output port number (0..3). + * AL = Data byte. + * command = TXDATA0 | INT_EN; + * Align port num with address field (b1...b3), + * set address for TXDatax, Strobe=0 + */ + command |= INT_EN; + + /* Disable interrupts so that the process is not interrupted, then + * write the address associated with the current Tx channel to the + * PP Command Reg. Do not set the Strobe signal yet. + */ + + do { + portman_write_command(pm, command); + + /* While the address lines settle, write parallel output data to + * PP Data Reg. This has no effect until Strobe signal is asserted. + */ + + portman_write_data(pm, mididata); + + /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP + * Status Register), then go write data. Else go back and wait. + */ + } while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY); + + /* TxEmpty is set. Maintain PC/P destination address and assert + * Strobe through the PP Command Reg. This will Strobe data into + * the PC/P transmitter and set the PC/P BUSY signal. + */ + + portman_write_command(pm, command | STROBE); + + /* Wait for strobe line to settle and echo back through hardware. + * Once it has echoed back, assume that the address and data lines + * have settled! + */ + + while ((portman_read_status(pm) & ESTB) == 0) + cpu_relax(); + + /* Release strobe and immediately re-allow interrupts. */ + portman_write_command(pm, command); + + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); + + /* PC/P BUSY is now set. We must wait until BUSY resets itself. + * We'll reenable ints while we're waiting. + */ + + while ((portman_read_status(pm) & BUSY) == BUSY) + cpu_relax(); + + /* Data sent. */ +} + + +/* + * Read MIDI byte from port + * Attempt to read input byte from specified hardware input port (0..). + * Return -1 if no data + */ +static int portman_read_midi(struct portman *pm, int port) +{ + unsigned char midi_data = 0; + unsigned char cmdout; /* Saved address+IE bit. */ + + /* Make sure clocking edge is down before starting... */ + portman_write_data(pm, 0); /* Make sure edge is down. */ + + /* Set destination address to PCP. */ + cmdout = (port << 1) | INT_EN; /* Address + IE + No Strobe. */ + portman_write_command(pm, cmdout); + + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); /* Wait for strobe echo. */ + + /* After the address lines settle, check multiplexed RxAvail signal. + * If data is available, read it. + */ + if ((portman_read_status(pm) & RXAVAIL) == 0) + return -1; /* No data. */ + + /* Set the Strobe signal to enable the Rx clocking circuitry. */ + portman_write_command(pm, cmdout | STROBE); /* Write address+IE+Strobe. */ + + while ((portman_read_status(pm) & ESTB) == 0) + cpu_relax(); /* Wait for strobe echo. */ + + /* The first data bit (msb) is already sitting on the input line. */ + midi_data = (portman_read_status(pm) & 128); + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 6. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 1) & 64; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 5. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 2) & 32; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 4. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 3) & 16; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 3. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 4) & 8; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 2. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 5) & 4; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 1. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 6) & 2; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 0. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 7) & 1; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + portman_write_data(pm, 0); /* Return data clock low. */ + + + /* De-assert Strobe and return data. */ + portman_write_command(pm, cmdout); /* Output saved address+IE. */ + + /* Wait for strobe echo. */ + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); + + return (midi_data & 255); /* Shift back and return value. */ +} + +/* + * Checks if any input data on the given channel is available + * Checks RxAvail + */ +static int portman_data_avail(struct portman *pm, int channel) +{ + int command = INT_EN; + switch (channel) { + case 0: + command |= RXDATA0; + break; + case 1: + command |= RXDATA1; + break; + } + /* Write hardware (assumme STROBE=0) */ + portman_write_command(pm, command); + /* Check multiplexed RxAvail signal */ + if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL) + return 1; /* Data available */ + + /* No Data available */ + return 0; +} + + +/* + * Flushes any input + */ +static void portman_flush_input(struct portman *pm, unsigned char port) +{ + /* Local variable for counting things */ + unsigned int i = 0; + unsigned char command = 0; + + switch (port) { + case 0: + command = RXDATA0; + break; + case 1: + command = RXDATA1; + break; + default: + snd_printk(KERN_WARNING + "portman_flush_input() Won't flush port %i\n", + port); + return; + } + + /* Set address for specified channel in port and allow to settle. */ + portman_write_command(pm, command); + + /* Assert the Strobe and wait for echo back. */ + portman_write_command(pm, command | STROBE); + + /* Wait for ESTB */ + while ((portman_read_status(pm) & ESTB) == 0) + cpu_relax(); + + /* Output clock cycles to the Rx circuitry. */ + portman_write_data(pm, 0); + + /* Flush 250 bits... */ + for (i = 0; i < 250; i++) { + portman_write_data(pm, 1); + portman_write_data(pm, 0); + } + + /* Deassert the Strobe signal of the port and wait for it to settle. */ + portman_write_command(pm, command | INT_EN); + + /* Wait for settling */ + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); +} + +static int portman_probe(struct parport *p) +{ + /* Initialize the parallel port data register. Will set Rx clocks + * low in case we happen to be addressing the Rx ports at this time. + */ + /* 1 */ + parport_write_data(p, 0); + + /* Initialize the parallel port command register, thus initializing + * hardware handshake lines to midi box: + * + * Strobe = 0 + * Interrupt Enable = 0 + */ + /* 2 */ + parport_write_control(p, 0); + + /* Check if Portman PC/P 2x4 is out there. */ + /* 3 */ + parport_write_control(p, RXDATA0); /* Write Strobe=0 to command reg. */ + + /* Check for ESTB to be clear */ + /* 4 */ + if ((parport_read_status(p) & ESTB) == ESTB) + return 1; /* CODE 1 - Strobe Failure. */ + + /* Set for RXDATA0 where no damage will be done. */ + /* 5 */ + parport_write_control(p, RXDATA0 + STROBE); /* Write Strobe=1 to command reg. */ + + /* 6 */ + if ((parport_read_status(p) & ESTB) != ESTB) + return 1; /* CODE 1 - Strobe Failure. */ + + /* 7 */ + parport_write_control(p, 0); /* Reset Strobe=0. */ + + /* Check if Tx circuitry is functioning properly. If initialized + * unit TxEmpty is false, send out char and see if if goes true. + */ + /* 8 */ + parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */ + + /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP + * Status Register), then go write data. Else go back and wait. + */ + /* 9 */ + if ((parport_read_status(p) & TXEMPTY) == 0) + return 2; + + /* Return OK status. */ + return 0; +} + +static int portman_device_init(struct portman *pm) +{ + portman_flush_input(pm, 0); + portman_flush_input(pm, 1); + + return 0; +} + +/********************************************************************* + * Rawmidi + *********************************************************************/ +static int snd_portman_midi_open(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static int snd_portman_midi_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct portman *pm = substream->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&pm->reg_lock, flags); + if (up) + pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED; + else + pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED; + spin_unlock_irqrestore(&pm->reg_lock, flags); +} + +static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct portman *pm = substream->rmidi->private_data; + unsigned long flags; + unsigned char byte; + + spin_lock_irqsave(&pm->reg_lock, flags); + if (up) { + while ((snd_rawmidi_transmit(substream, &byte, 1) == 1)) + portman_write_midi(pm, substream->number, byte); + } + spin_unlock_irqrestore(&pm->reg_lock, flags); +} + +static struct snd_rawmidi_ops snd_portman_midi_output = { + .open = snd_portman_midi_open, + .close = snd_portman_midi_close, + .trigger = snd_portman_midi_output_trigger, +}; + +static struct snd_rawmidi_ops snd_portman_midi_input = { + .open = snd_portman_midi_open, + .close = snd_portman_midi_close, + .trigger = snd_portman_midi_input_trigger, +}; + +/* Create and initialize the rawmidi component */ +static int __devinit snd_portman_rawmidi_create(struct snd_card *card) +{ + struct portman *pm = card->private_data; + struct snd_rawmidi *rmidi; + struct snd_rawmidi_substream *substream; + int err; + + err = snd_rawmidi_new(card, CARD_NAME, 0, + PORTMAN_NUM_OUTPUT_PORTS, + PORTMAN_NUM_INPUT_PORTS, + &rmidi); + if (err < 0) + return err; + + rmidi->private_data = pm; + strcpy(rmidi->name, CARD_NAME); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + + pm->rmidi = rmidi; + + /* register rawmidi ops */ + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_portman_midi_output); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_portman_midi_input); + + /* name substreams */ + /* output */ + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, + list) { + sprintf(substream->name, + "Portman2x4 %d", substream->number+1); + } + /* input */ + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, + list) { + pm->midi_input[substream->number] = substream; + sprintf(substream->name, + "Portman2x4 %d", substream->number+1); + } + + return err; +} + +/********************************************************************* + * parport stuff + *********************************************************************/ +static void snd_portman_interrupt(int irq, void *userdata) +{ + unsigned char midivalue = 0; + struct portman *pm = ((struct snd_card*)userdata)->private_data; + + spin_lock(&pm->reg_lock); + + /* While any input data is waiting */ + while ((portman_read_status(pm) & INT_REQ) == INT_REQ) { + /* If data available on channel 0, + read it and stuff it into the queue. */ + if (portman_data_avail(pm, 0)) { + /* Read Midi */ + midivalue = portman_read_midi(pm, 0); + /* put midi into queue... */ + if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED) + snd_rawmidi_receive(pm->midi_input[0], + &midivalue, 1); + + } + /* If data available on channel 1, + read it and stuff it into the queue. */ + if (portman_data_avail(pm, 1)) { + /* Read Midi */ + midivalue = portman_read_midi(pm, 1); + /* put midi into queue... */ + if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED) + snd_rawmidi_receive(pm->midi_input[1], + &midivalue, 1); + } + + } + + spin_unlock(&pm->reg_lock); +} + +static int __devinit snd_portman_probe_port(struct parport *p) +{ + struct pardevice *pardev; + int res; + + pardev = parport_register_device(p, DRIVER_NAME, + NULL, NULL, NULL, + 0, NULL); + if (!pardev) + return -EIO; + + if (parport_claim(pardev)) { + parport_unregister_device(pardev); + return -EIO; + } + + res = portman_probe(p); + + parport_release(pardev); + parport_unregister_device(pardev); + + return res; +} + +static void __devinit snd_portman_attach(struct parport *p) +{ + struct platform_device *device; + + device = platform_device_alloc(PLATFORM_DRIVER, device_count); + if (!device) + return; + + /* Temporary assignment to forward the parport */ + platform_set_drvdata(device, p); + + if (platform_device_register(device) < 0) { + platform_device_put(device); + return; + } + + /* Since we dont get the return value of probe + * We need to check if device probing succeeded or not */ + if (!platform_get_drvdata(device)) { + platform_device_unregister(device); + return; + } + + /* register device in global table */ + platform_devices[device_count] = device; + device_count++; +} + +static void snd_portman_detach(struct parport *p) +{ + /* nothing to do here */ +} + +static struct parport_driver portman_parport_driver = { + .name = "portman2x4", + .attach = snd_portman_attach, + .detach = snd_portman_detach +}; + +/********************************************************************* + * platform stuff + *********************************************************************/ +static void snd_portman_card_private_free(struct snd_card *card) +{ + struct portman *pm = card->private_data; + struct pardevice *pardev = pm->pardev; + + if (pardev) { + if (pm->pardev_claimed) + parport_release(pardev); + parport_unregister_device(pardev); + } + + portman_free(pm); +} + +static int __devinit snd_portman_probe(struct platform_device *pdev) +{ + struct pardevice *pardev; + struct parport *p; + int dev = pdev->id; + struct snd_card *card = NULL; + struct portman *pm = NULL; + int err; + + p = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) + return -ENOENT; + + if ((err = snd_portman_probe_port(p)) < 0) + return err; + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (card == NULL) { + snd_printd("Cannot create card\n"); + return -ENOMEM; + } + strcpy(card->driver, DRIVER_NAME); + strcpy(card->shortname, CARD_NAME); + sprintf(card->longname, "%s at 0x%lx, irq %i", + card->shortname, p->base, p->irq); + + pardev = parport_register_device(p, /* port */ + DRIVER_NAME, /* name */ + NULL, /* preempt */ + NULL, /* wakeup */ + snd_portman_interrupt, /* ISR */ + PARPORT_DEV_EXCL, /* flags */ + (void *)card); /* private */ + if (pardev == NULL) { + snd_printd("Cannot register pardevice\n"); + err = -EIO; + goto __err; + } + + if ((err = portman_create(card, pardev, &pm)) < 0) { + snd_printd("Cannot create main component\n"); + parport_unregister_device(pardev); + goto __err; + } + card->private_data = pm; + card->private_free = snd_portman_card_private_free; + + if ((err = snd_portman_rawmidi_create(card)) < 0) { + snd_printd("Creating Rawmidi component failed\n"); + goto __err; + } + + /* claim parport */ + if (parport_claim(pardev)) { + snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base); + err = -EIO; + goto __err; + } + pm->pardev_claimed = 1; + + /* init device */ + if ((err = portman_device_init(pm)) < 0) + goto __err; + + platform_set_drvdata(pdev, card); + + /* At this point card will be usable */ + if ((err = snd_card_register(card)) < 0) { + snd_printd("Cannot register card\n"); + goto __err; + } + + snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base); + return 0; + +__err: + snd_card_free(card); + return err; +} + +static int snd_portman_remove(struct platform_device *pdev) +{ + struct snd_card *card = platform_get_drvdata(pdev); + + if (card) + snd_card_free(card); + + return 0; +} + + +static struct platform_driver snd_portman_driver = { + .probe = snd_portman_probe, + .remove = snd_portman_remove, + .driver = { + .name = PLATFORM_DRIVER + } +}; + +/********************************************************************* + * module init stuff + *********************************************************************/ +static void snd_portman_unregister_all(void) +{ + int i; + + for (i = 0; i < SNDRV_CARDS; ++i) { + if (platform_devices[i]) { + platform_device_unregister(platform_devices[i]); + platform_devices[i] = NULL; + } + } + platform_driver_unregister(&snd_portman_driver); + parport_unregister_driver(&portman_parport_driver); +} + +static int __init snd_portman_module_init(void) +{ + int err; + + if ((err = platform_driver_register(&snd_portman_driver)) < 0) + return err; + + if (parport_register_driver(&portman_parport_driver) != 0) { + platform_driver_unregister(&snd_portman_driver); + return -EIO; + } + + if (device_count == 0) { + snd_portman_unregister_all(); + return -ENODEV; + } + + return 0; +} + +static void __exit snd_portman_module_exit(void) +{ + snd_portman_unregister_all(); +} + +module_init(snd_portman_module_init); +module_exit(snd_portman_module_exit); diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 74028b2219c2..3a86a5820726 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -117,13 +117,13 @@ MODULE_PARM_DESC(adaptor, "Type of adaptor."); #define SERIAL_MODE_INPUT_TRIGGERED (1 << 2) #define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3) -typedef struct _snd_uart16550 { +struct snd_uart16550 { struct snd_card *card; struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS]; struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS]; - int filemode; //open status of file + int filemode; /* open status of file */ spinlock_t open_lock; @@ -140,39 +140,39 @@ typedef struct _snd_uart16550 { unsigned char old_divisor_msb; unsigned char old_line_ctrl_reg; - // parameter for using of write loop - short int fifo_limit; //used in uart16550 - short int fifo_count; //used in uart16550 + /* parameter for using of write loop */ + short int fifo_limit; /* used in uart16550 */ + short int fifo_count; /* used in uart16550 */ - // type of adaptor + /* type of adaptor */ int adaptor; - // inputs + /* inputs */ int prev_in; unsigned char rstatus; - // outputs + /* outputs */ int prev_out; unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS]; - // write buffer and its writing/reading position + /* write buffer and its writing/reading position */ unsigned char tx_buff[TX_BUFF_SIZE]; int buff_in_count; int buff_in; int buff_out; int drop_on_full; - // wait timer + /* wait timer */ unsigned int timer_running:1; struct timer_list buffer_timer; -} snd_uart16550_t; +}; static struct platform_device *devices[SNDRV_CARDS]; -static inline void snd_uart16550_add_timer(snd_uart16550_t *uart) +static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart) { - if (! uart->timer_running) { + if (!uart->timer_running) { /* timer 38600bps * 10bit * 16byte */ uart->buffer_timer.expires = jiffies + (HZ+255)/256; uart->timer_running = 1; @@ -180,7 +180,7 @@ static inline void snd_uart16550_add_timer(snd_uart16550_t *uart) } } -static inline void snd_uart16550_del_timer(snd_uart16550_t *uart) +static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart) { if (uart->timer_running) { del_timer(&uart->buffer_timer); @@ -189,10 +189,10 @@ static inline void snd_uart16550_del_timer(snd_uart16550_t *uart) } /* This macro is only used in snd_uart16550_io_loop */ -static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart) +static inline void snd_uart16550_buffer_output(struct snd_uart16550 *uart) { unsigned short buff_out = uart->buff_out; - if( uart->buff_in_count > 0 ) { + if (uart->buff_in_count > 0) { outb(uart->tx_buff[buff_out], uart->base + UART_TX); uart->fifo_count++; buff_out++; @@ -206,7 +206,7 @@ static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart) * We don't want to interrupt this, * as we're already handling an interrupt */ -static void snd_uart16550_io_loop(snd_uart16550_t * uart) +static void snd_uart16550_io_loop(struct snd_uart16550 * uart) { unsigned char c, status; int substream; @@ -220,9 +220,8 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) c = inb(uart->base + UART_RX); /* keep track of last status byte */ - if (c & 0x80) { + if (c & 0x80) uart->rstatus = c; - } /* handle stream switch */ if (uart->adaptor == SNDRV_SERIAL_GENERIC) { @@ -230,14 +229,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) if (c <= SNDRV_SERIAL_MAX_INS && c > 0) substream = c - 1; if (c != 0xf5) - uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */ - } - else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) { - snd_rawmidi_receive(uart->midi_input[substream], &c, 1); - } - } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) { + /* prevent future bytes from being + interpreted as streams */ + uart->rstatus = 0; + } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) + && uart->midi_input[substream]) + snd_rawmidi_receive(uart->midi_input[substream], + &c, 1); + } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && + uart->midi_input[substream]) snd_rawmidi_receive(uart->midi_input[substream], &c, 1); - } if (status & UART_LSR_OE) snd_printk("%s: Overrun on device at 0x%lx\n", @@ -250,21 +251,20 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) /* no need of check SERIAL_MODE_OUTPUT_OPEN because if not, buffer is never filled. */ /* Check write status */ - if (status & UART_LSR_THRE) { + if (status & UART_LSR_THRE) uart->fifo_count = 0; - } if (uart->adaptor == SNDRV_SERIAL_MS124W_SA || uart->adaptor == SNDRV_SERIAL_GENERIC) { /* Can't use FIFO, must send only when CTS is true */ status = inb(uart->base + UART_MSR); - while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) && - (uart->buff_in_count > 0) ) { + while (uart->fifo_count == 0 && (status & UART_MSR_CTS) && + uart->buff_in_count > 0) { snd_uart16550_buffer_output(uart); - status = inb( uart->base + UART_MSR ); + status = inb(uart->base + UART_MSR); } } else { /* Write loop */ - while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ + while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ && uart->buff_in_count > 0) /* Do we want to? */ snd_uart16550_buffer_output(uart); } @@ -294,15 +294,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) */ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) { - snd_uart16550_t *uart; + struct snd_uart16550 *uart; - uart = (snd_uart16550_t *) dev_id; + uart = dev_id; spin_lock(&uart->open_lock); if (uart->filemode == SERIAL_MODE_NOT_OPENED) { spin_unlock(&uart->open_lock); return IRQ_NONE; } - inb(uart->base + UART_IIR); /* indicate to the UART that the interrupt has been serviced */ + /* indicate to the UART that the interrupt has been serviced */ + inb(uart->base + UART_IIR); snd_uart16550_io_loop(uart); spin_unlock(&uart->open_lock); return IRQ_HANDLED; @@ -312,9 +313,9 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) static void snd_uart16550_buffer_timer(unsigned long data) { unsigned long flags; - snd_uart16550_t *uart; + struct snd_uart16550 *uart; - uart = (snd_uart16550_t *)data; + uart = (struct snd_uart16550 *)data; spin_lock_irqsave(&uart->open_lock, flags); snd_uart16550_del_timer(uart); snd_uart16550_io_loop(uart); @@ -326,7 +327,7 @@ static void snd_uart16550_buffer_timer(unsigned long data) * return 0 if found * return negative error if not found */ -static int __init snd_uart16550_detect(snd_uart16550_t *uart) +static int __init snd_uart16550_detect(struct snd_uart16550 *uart) { unsigned long io_base = uart->base; int ok; @@ -343,7 +344,8 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart) return -EBUSY; } - ok = 1; /* uart detected unless one of the following tests should fail */ + /* uart detected unless one of the following tests should fail */ + ok = 1; /* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */ outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */ c = inb(io_base + UART_IER); @@ -368,7 +370,7 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart) return ok; } -static void snd_uart16550_do_open(snd_uart16550_t * uart) +static void snd_uart16550_do_open(struct snd_uart16550 * uart) { char byte; @@ -460,7 +462,7 @@ static void snd_uart16550_do_open(snd_uart16550_t * uart) inb(uart->base + UART_RX); /* Clear any pre-existing receive interrupt */ } -static void snd_uart16550_do_close(snd_uart16550_t * uart) +static void snd_uart16550_do_close(struct snd_uart16550 * uart) { if (uart->irq < 0) snd_uart16550_del_timer(uart); @@ -514,7 +516,7 @@ static void snd_uart16550_do_close(snd_uart16550_t * uart) static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (uart->filemode == SERIAL_MODE_NOT_OPENED) @@ -528,7 +530,7 @@ static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); uart->filemode &= ~SERIAL_MODE_INPUT_OPEN; @@ -539,24 +541,24 @@ static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) return 0; } -static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, + int up) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); - if (up) { + if (up) uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED; - } else { + else uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED; - } spin_unlock_irqrestore(&uart->open_lock, flags); } static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (uart->filemode == SERIAL_MODE_NOT_OPENED) @@ -570,7 +572,7 @@ static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN; @@ -581,18 +583,20 @@ static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) return 0; }; -static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num ) +static inline int snd_uart16550_buffer_can_write(struct snd_uart16550 *uart, + int Num) { - if( uart->buff_in_count + Num < TX_BUFF_SIZE ) + if (uart->buff_in_count + Num < TX_BUFF_SIZE) return 1; else return 0; } -static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) +static inline int snd_uart16550_write_buffer(struct snd_uart16550 *uart, + unsigned char byte) { unsigned short buff_in = uart->buff_in; - if( uart->buff_in_count < TX_BUFF_SIZE ) { + if (uart->buff_in_count < TX_BUFF_SIZE) { uart->tx_buff[buff_in] = byte; buff_in++; buff_in &= TX_BUFF_MASK; @@ -605,12 +609,14 @@ static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned cha return 0; } -static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte) +static int snd_uart16550_output_byte(struct snd_uart16550 *uart, + struct snd_rawmidi_substream *substream, + unsigned char midi_byte) { - if (uart->buff_in_count == 0 /* Buffer empty? */ + if (uart->buff_in_count == 0 /* Buffer empty? */ && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA && uart->adaptor != SNDRV_SERIAL_GENERIC) || - (uart->fifo_count == 0 /* FIFO empty? */ + (uart->fifo_count == 0 /* FIFO empty? */ && (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */ /* Tx Buffer Empty - try to write immediately */ @@ -623,12 +629,13 @@ static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_s uart->fifo_count++; outb(midi_byte, uart->base + UART_TX); } else { - /* Cannot write (buffer empty) - put char in buffer */ + /* Cannot write (buffer empty) - + * put char in buffer */ snd_uart16550_write_buffer(uart, midi_byte); } } } else { - if( !snd_uart16550_write_buffer(uart, midi_byte) ) { + if (!snd_uart16550_write_buffer(uart, midi_byte)) { snd_printk("%s: Buffer overrun on device at 0x%lx\n", uart->rmidi->name, uart->base); return 0; @@ -642,9 +649,9 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) { unsigned long flags; unsigned char midi_byte, addr_byte; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; char first; - static unsigned long lasttime=0; + static unsigned long lasttime = 0; /* Interupts are disabled during the updating of the tx_buff, * since it is 'bad' to have two processes updating the same @@ -653,7 +660,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) spin_lock_irqsave(&uart->open_lock, flags); - if (uart->irq < 0) //polling + if (uart->irq < 0) /* polling */ snd_uart16550_io_loop(uart); if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) { @@ -671,7 +678,8 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) /* select any combination of the four ports */ addr_byte = (substream->number << 4) | 0x08; /* ...except none */ - if (addr_byte == 0x08) addr_byte = 0xf8; + if (addr_byte == 0x08) + addr_byte = 0xf8; #endif snd_uart16550_output_byte(uart, substream, addr_byte); /* send midi byte */ @@ -679,31 +687,42 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) } } else { first = 0; - while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) { - /* Also send F5 after 3 seconds with no data to handle device disconnect */ - if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || - uart->adaptor == SNDRV_SERIAL_GENERIC) && - (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) { - - if( snd_uart16550_buffer_can_write( uart, 3 ) ) { + while (snd_rawmidi_transmit_peek(substream, &midi_byte, 1) == 1) { + /* Also send F5 after 3 seconds with no data + * to handle device disconnect */ + if (first == 0 && + (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || + uart->adaptor == SNDRV_SERIAL_GENERIC) && + (uart->prev_out != substream->number || + jiffies-lasttime > 3*HZ)) { + + if (snd_uart16550_buffer_can_write(uart, 3)) { /* Roland Soundcanvas part selection */ - /* If this substream of the data is different previous - substream in this uart, send the change part event */ + /* If this substream of the data is + * different previous substream + * in this uart, send the change part + * event + */ uart->prev_out = substream->number; /* change part */ - snd_uart16550_output_byte(uart, substream, 0xf5); + snd_uart16550_output_byte(uart, substream, + 0xf5); /* data */ - snd_uart16550_output_byte(uart, substream, uart->prev_out + 1); - /* If midi_byte is a data byte, send the previous status byte */ - if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)) + snd_uart16550_output_byte(uart, substream, + uart->prev_out + 1); + /* If midi_byte is a data byte, + * send the previous status byte */ + if (midi_byte < 0x80 && + uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS) snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); - } else if( !uart->drop_on_full ) + } else if (!uart->drop_on_full) break; } /* send midi byte */ - if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full ) + if (!snd_uart16550_output_byte(uart, substream, midi_byte) && + !uart->drop_on_full ) break; if (midi_byte >= 0x80 && midi_byte < 0xf0) @@ -717,17 +736,17 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) spin_unlock_irqrestore(&uart->open_lock, flags); } -static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, + int up) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); - if (up) { + if (up) uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED; - } else { + else uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED; - } spin_unlock_irqrestore(&uart->open_lock, flags); if (up) snd_uart16550_output_write(substream); @@ -747,10 +766,10 @@ static struct snd_rawmidi_ops snd_uart16550_input = .trigger = snd_uart16550_input_trigger, }; -static int snd_uart16550_free(snd_uart16550_t *uart) +static int snd_uart16550_free(struct snd_uart16550 *uart) { if (uart->irq >= 0) - free_irq(uart->irq, (void *)uart); + free_irq(uart->irq, uart); release_and_free_resource(uart->res_base); kfree(uart); return 0; @@ -758,7 +777,7 @@ static int snd_uart16550_free(snd_uart16550_t *uart) static int snd_uart16550_dev_free(struct snd_device *device) { - snd_uart16550_t *uart = device->device_data; + struct snd_uart16550 *uart = device->device_data; return snd_uart16550_free(uart); } @@ -769,12 +788,12 @@ static int __init snd_uart16550_create(struct snd_card *card, unsigned int base, int adaptor, int droponfull, - snd_uart16550_t **ruart) + struct snd_uart16550 **ruart) { static struct snd_device_ops ops = { .dev_free = snd_uart16550_dev_free, }; - snd_uart16550_t *uart; + struct snd_uart16550 *uart; int err; @@ -795,7 +814,7 @@ static int __init snd_uart16550_create(struct snd_card *card, if (irq >= 0 && irq != SNDRV_AUTO_IRQ) { if (request_irq(irq, snd_uart16550_interrupt, - IRQF_DISABLED, "Serial MIDI", (void *) uart)) { + IRQF_DISABLED, "Serial MIDI", uart)) { snd_printk("irq %d busy. Using Polling.\n", irq); } else { uart->irq = irq; @@ -843,23 +862,28 @@ static int __init snd_uart16550_create(struct snd_card *card, static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream) { - struct list_head *list; + struct snd_rawmidi_substream *substream; - list_for_each(list, &stream->substreams) { - struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, &stream->substreams, list) { sprintf(substream->name, "Serial MIDI %d", substream->number + 1); } } -static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi) +static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, + int outs, int ins, + struct snd_rawmidi **rmidi) { struct snd_rawmidi *rrawmidi; int err; - if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0) + err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, + outs, ins, &rrawmidi); + if (err < 0) return err; - snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input); - snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output); + snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_uart16550_input); + snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_uart16550_output); strcpy(rrawmidi->name, "Serial MIDI"); snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); @@ -875,7 +899,7 @@ static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int out static int __init snd_serial_probe(struct platform_device *devptr) { struct snd_card *card; - snd_uart16550_t *uart; + struct snd_uart16550 *uart; int err; int dev = devptr->id; @@ -929,7 +953,8 @@ static int __init snd_serial_probe(struct platform_device *devptr) &uart)) < 0) goto _err; - if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0) + err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi); + if (err < 0) goto _err; sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d", diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 1613ed844ac6..f63152a6a223 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -716,7 +716,7 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return 0; } -static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); static struct snd_kcontrol_new vx_control_audio_gain = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile index 816a2e7c88ca..45902d48c89c 100644 --- a/sound/i2c/Makefile +++ b/sound/i2c/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_SND) += other/ # Toplevel Module Dependency obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o +obj-$(CONFIG_SND_ICE1724) += snd-i2c.o diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 2fe023ef00a7..77a8a7c75dd9 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -6,11 +6,11 @@ snd-ak4114-objs := ak4114.o snd-ak4117-objs := ak4117.o snd-ak4xxx-adda-objs := ak4xxx-adda.o +snd-pt2258-objs := pt2258.o snd-tea575x-tuner-objs := tea575x-tuner.o # Module Dependency obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o -obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o -obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o +obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index d2f2c5078e65..adbfd5884d06 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -42,8 +42,8 @@ static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char va ak4114->write(ak4114->private_data, reg, val); if (reg <= AK4114_REG_INT1_MASK) ak4114->regmap[reg] = val; - else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4) - ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val; + else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) + ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val; } static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg) @@ -66,10 +66,8 @@ static void snd_ak4114_free(struct ak4114 *chip) { chip->init = 1; /* don't schedule new work */ mb(); - if (chip->workqueue != NULL) { - flush_workqueue(chip->workqueue); - destroy_workqueue(chip->workqueue); - } + cancel_delayed_work(&chip->work); + flush_scheduled_work(); kfree(chip); } @@ -82,7 +80,7 @@ static int snd_ak4114_dev_free(struct snd_device *device) int snd_ak4114_create(struct snd_card *card, ak4114_read_t *read, ak4114_write_t *write, - unsigned char pgm[7], unsigned char txcsb[5], + const unsigned char pgm[7], const unsigned char txcsb[5], void *private_data, struct ak4114 **r_ak4114) { struct ak4114 *chip; @@ -100,18 +98,13 @@ int snd_ak4114_create(struct snd_card *card, chip->read = read; chip->write = write; chip->private_data = private_data; + INIT_DELAYED_WORK(&chip->work, ak4114_stats); for (reg = 0; reg < 7; reg++) chip->regmap[reg] = pgm[reg]; for (reg = 0; reg < 5; reg++) chip->txcsb[reg] = txcsb[reg]; - chip->workqueue = create_workqueue("snd-ak4114"); - if (chip->workqueue == NULL) { - kfree(chip); - return -ENOMEM; - } - snd_ak4114_reinit(chip); chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); @@ -134,7 +127,8 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char if (reg <= AK4114_REG_INT1_MASK) reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) - reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val); + reg_write(chip, reg, + (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val); } void snd_ak4114_reinit(struct ak4114 *chip) @@ -143,7 +137,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) chip->init = 1; mb(); - flush_workqueue(chip->workqueue); + flush_scheduled_work(); /* bring the chip to reset state and powerdown state */ reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN)); udelay(200); @@ -158,8 +152,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); /* bring up statistics / event queing */ chip->init = 0; - INIT_DELAYED_WORK(&chip->work, ak4114_stats); - queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); + schedule_delayed_work(&chip->work, HZ / 10); } static unsigned int external_rate(unsigned char rcs1) @@ -568,7 +561,7 @@ static void ak4114_stats(struct work_struct *work) if (chip->init) return; snd_ak4114_check_rate_and_errors(chip, 0); - queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); + schedule_delayed_work(&chip->work, HZ / 10); } EXPORT_SYMBOL(snd_ak4114_create); diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 4e45952dd95a..c022f29da2f7 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -74,7 +74,7 @@ static int snd_ak4117_dev_free(struct snd_device *device) } int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, - unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) + const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) { struct ak4117 *chip; int err = 0; diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 5da49e2eb350..8805110017a7 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset); * Used for AK4524 input/ouput attenuation, AK4528, and * AK5365 input attenuation */ -static unsigned char vol_cvt_datt[128] = { +static const unsigned char vol_cvt_datt[128] = { 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, @@ -162,17 +162,17 @@ static unsigned char vol_cvt_datt[128] = { /* * dB tables */ -static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); -static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); -static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); -static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); +static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); /* * initialize all the ak4xxx chips */ void snd_akm4xxx_init(struct snd_akm4xxx *ak) { - static unsigned char inits_ak4524[] = { + static const unsigned char inits_ak4524[] = { 0x00, 0x07, /* 0: all power up */ 0x01, 0x00, /* 1: ADC/DAC reset */ 0x02, 0x60, /* 2: 24bit I2S */ @@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x07, 0x00, /* 7: DAC right muted */ 0xff, 0xff }; - static unsigned char inits_ak4528[] = { + static const unsigned char inits_ak4528[] = { 0x00, 0x07, /* 0: all power up */ 0x01, 0x00, /* 1: ADC/DAC reset */ 0x02, 0x60, /* 2: 24bit I2S */ @@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x05, 0x00, /* 5: ADC right muted */ 0xff, 0xff }; - static unsigned char inits_ak4529[] = { + static const unsigned char inits_ak4529[] = { 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ @@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x08, 0x55, /* 8: deemphasis all off */ 0xff, 0xff }; - static unsigned char inits_ak4355[] = { + static const unsigned char inits_ak4355[] = { 0x01, 0x02, /* 1: reset and soft-mute */ 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, * disable DZF, sharp roll-off, RSTN#=0 */ @@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x01, 0x01, /* 1: un-reset, unmute */ 0xff, 0xff }; - static unsigned char inits_ak4358[] = { + static const unsigned char inits_ak4358[] = { 0x01, 0x02, /* 1: reset and soft-mute */ 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, * disable DZF, sharp roll-off, RSTN#=0 */ @@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x01, 0x01, /* 1: un-reset, unmute */ 0xff, 0xff }; - static unsigned char inits_ak4381[] = { + static const unsigned char inits_ak4381[] = { 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ 0x01, 0x02, /* 1: de-emphasis off, normal speed, * sharp roll-off, DZF off */ @@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) }; int chip, num_chips; - unsigned char *ptr, reg, data, *inits; + const unsigned char *ptr, *inits; + unsigned char reg, data; memset(ak->images, 0, sizeof(ak->images)); memset(ak->volumes, 0, sizeof(ak->volumes)); @@ -513,6 +514,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, return change; } +#define AK5365_NUM_INPUTS 5 + +static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int mixer_ch = AK_GET_SHIFT(kcontrol->private_value); + const char **input_names; + int num_names, idx; + + input_names = ak->adc_info[mixer_ch].input_names; + + num_names = 0; + while (num_names < AK5365_NUM_INPUTS && input_names[num_names]) + ++num_names; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = num_names; + idx = uinfo->value.enumerated.item; + if (idx >= num_names) + return -EINVAL; + strncpy(uinfo->value.enumerated.name, input_names[idx], + sizeof(uinfo->value.enumerated.name)); + return 0; +} + +static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char val; + + val = snd_akm4xxx_get(ak, chip, addr) & mask; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char oval, val; + + oval = snd_akm4xxx_get(ak, chip, addr); + val = oval & ~mask; + val |= ucontrol->value.enumerated.item[0] & mask; + if (val != oval) { + snd_akm4xxx_write(ak, chip, addr, val); + return 1; + } + return 0; +} + /* * build AK4xxx controls */ @@ -647,9 +708,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak) if (ak->type == SND_AK5365 && (idx % 2) == 0) { if (! ak->adc_info || - ! ak->adc_info[mixer_ch].switch_name) + ! ak->adc_info[mixer_ch].switch_name) { knew.name = "Capture Switch"; - else + knew.index = mixer_ch + ak->idx_offset * 2; + } else knew.name = ak->adc_info[mixer_ch].switch_name; knew.info = ak4xxx_switch_info; knew.get = ak4xxx_switch_get; @@ -662,6 +724,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak) err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); if (err < 0) return err; + + memset(&knew, 0, sizeof(knew)); + knew.name = ak->adc_info[mixer_ch].selector_name; + if (!knew.name) { + knew.name = "Capture Channel"; + knew.index = mixer_ch + ak->idx_offset * 2; + } + + knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + knew.info = ak4xxx_capture_source_info; + knew.get = ak4xxx_capture_source_get; + knew.put = ak4xxx_capture_source_put; + knew.access = 0; + /* input selector control: reg. 1, bits 0-2. + * mis-use 'shift' to pass mixer_ch */ + knew.private_value + = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07); + err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); + if (err < 0) + return err; } idx += num_stereo; diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c new file mode 100644 index 000000000000..e91cc3b44de5 --- /dev/null +++ b/sound/i2c/other/pt2258.c @@ -0,0 +1,233 @@ +/* + * ALSA Driver for the PT2258 volume controller. + * + * Copyright (c) 2006 Jochen Voss <voss@seehuhn.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/tlv.h> +#include <sound/i2c.h> +#include <sound/pt2258.h> + +MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>"); +MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)"); +MODULE_LICENSE("GPL"); + +#define PT2258_CMD_RESET 0xc0 +#define PT2258_CMD_UNMUTE 0xf8 +#define PT2258_CMD_MUTE 0xf9 + +static const unsigned char pt2258_channel_code[12] = { + 0x80, 0x90, /* channel 1: -10dB, -1dB */ + 0x40, 0x50, /* channel 2: -10dB, -1dB */ + 0x00, 0x10, /* channel 3: -10dB, -1dB */ + 0x20, 0x30, /* channel 4: -10dB, -1dB */ + 0x60, 0x70, /* channel 5: -10dB, -1dB */ + 0xa0, 0xb0 /* channel 6: -10dB, -1dB */ +}; + +int snd_pt2258_reset(struct snd_pt2258 *pt) +{ + unsigned char bytes[2]; + int i; + + /* reset chip */ + bytes[0] = PT2258_CMD_RESET; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + /* mute all channels */ + pt->mute = 1; + bytes[0] = PT2258_CMD_MUTE; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + /* set all channels to 0dB */ + for (i = 0; i < 6; ++i) + pt->volume[i] = 0; + bytes[0] = 0xd0; + bytes[1] = 0xe0; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + return 0; + + __error: + snd_i2c_unlock(pt->i2c_bus); + snd_printk(KERN_ERR "PT2258 reset failed\n"); + return -EIO; +} + +static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 79; + return 0; +} + +static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + int base = kcontrol->private_value; + + /* chip does not support register reads */ + ucontrol->value.integer.value[0] = 79 - pt->volume[base]; + ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1]; + return 0; +} + +static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + int base = kcontrol->private_value; + unsigned char bytes[2]; + int val0, val1; + + val0 = 79 - ucontrol->value.integer.value[0]; + val1 = 79 - ucontrol->value.integer.value[1]; + if (val0 == pt->volume[base] && val1 == pt->volume[base + 1]) + return 0; + + pt->volume[base] = val0; + bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10); + bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10); + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + pt->volume[base + 1] = val1; + bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10); + bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10); + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + return 1; + + __error: + snd_i2c_unlock(pt->i2c_bus); + snd_printk(KERN_ERR "PT2258 access failed\n"); + return -EIO; +} + +static int pt2258_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int pt2258_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + + ucontrol->value.integer.value[0] = !pt->mute; + return 0; +} + +static int pt2258_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + unsigned char bytes[2]; + int val; + + val = !ucontrol->value.integer.value[0]; + if (pt->mute == val) + return 0; + + pt->mute = val; + bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + return 1; + + __error: + snd_i2c_unlock(pt->i2c_bus); + snd_printk(KERN_ERR "PT2258 access failed 2\n"); + return -EIO; +} + +static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0); + +int snd_pt2258_build_controls(struct snd_pt2258 *pt) +{ + struct snd_kcontrol_new knew; + char *names[3] = { + "Mic Loopback Playback Volume", + "Line Loopback Playback Volume", + "CD Loopback Playback Volume" + }; + int i, err; + + for (i = 0; i < 3; ++i) { + memset(&knew, 0, sizeof(knew)); + knew.name = names[i]; + knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + knew.count = 1; + knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ; + knew.private_value = 2 * i; + knew.info = pt2258_stereo_volume_info; + knew.get = pt2258_stereo_volume_get; + knew.put = pt2258_stereo_volume_put; + knew.tlv.p = pt2258_db_scale; + + err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt)); + if (err < 0) + return err; + } + + memset(&knew, 0, sizeof(knew)); + knew.name = "Loopback Switch"; + knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + knew.info = pt2258_switch_info; + knew.get = pt2258_switch_get; + knew.put = pt2258_switch_put; + knew.access = 0; + err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt)); + if (err < 0) + return err; + + return 0; +} + +EXPORT_SYMBOL(snd_pt2258_reset); +EXPORT_SYMBOL(snd_pt2258_build_controls); diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 57371f1a441f..4e3a9729f569 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -358,6 +358,7 @@ config SND_SBAWE config SND_SB16_CSP bool "Sound Blaster 16/AWE CSP support" depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) + select FW_LOADER help Say Y here to include support for the CSP core. This special coprocessor can do variable tasks like various compression and @@ -390,6 +391,7 @@ config SND_SSCAPE config SND_WAVEFRONT tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" depends on SND + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_CS4231_LIB diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index b524e0d9ee44..ec9209cd5177 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -906,11 +906,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 666b3bcc19f0..8094282c2ae1 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -1223,9 +1223,9 @@ int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); -static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); static struct ad1848_mix_elem snd_ad1848_controls[] = { AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index b680fddf0d74..8ced5e81b9a7 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -294,10 +294,10 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) gus->mix_cntrl_reg |= 4; /* enable MIC */ } dma1 = gus->gf1.dma1; - dma1 = dma1 < 0 ? -dma1 : dma1; + dma1 = abs(dma1); dma1 = dmas[dma1 & 7]; dma2 = gus->gf1.dma2; - dma2 = dma2 < 0 ? -dma2 : dma2; + dma2 = abs(dma2); dma2 = dmas[dma2 & 7]; dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3); @@ -306,7 +306,7 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) return -EINVAL; } irq = gus->gf1.irq; - irq = irq < 0 ? -irq : irq; + irq = abs(irq); irq = irqs[irq & 0x0f]; if (irq == 0) { snd_printk(KERN_ERR "Error! IRQ isn't defined.\n"); diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 419b4ebbf00e..1e30713d2cad 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -486,8 +486,8 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); static struct snd_kcontrol_new snd_opl3sa2_controls[] = { OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index fcd638090a9e..3d9d7e0107ca 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -161,10 +161,13 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep) */ static void snd_sb_csp_free(struct snd_hwdep *hwdep) { + int i; struct snd_sb_csp *p = hwdep->private_data; if (p) { if (p->running & SNDRV_SB_CSP_ST_RUNNING) snd_sb_csp_stop(p); + for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i) + release_firmware(p->csp_programs[i]); kfree(p); } } @@ -687,8 +690,50 @@ static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __use return err; } +#define FIRMWARE_IN_THE_KERNEL + +#ifdef FIRMWARE_IN_THE_KERNEL #include "sb16_csp_codecs.h" +static const struct firmware snd_sb_csp_static_programs[] = { + { .data = mulaw_main, .size = sizeof mulaw_main }, + { .data = alaw_main, .size = sizeof alaw_main }, + { .data = ima_adpcm_init, .size = sizeof ima_adpcm_init }, + { .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback }, + { .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture }, +}; +#endif + +static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags) +{ + static const char *const names[] = { + "sb16/mulaw_main.csp", + "sb16/alaw_main.csp", + "sb16/ima_adpcm_init.csp", + "sb16/ima_adpcm_playback.csp", + "sb16/ima_adpcm_capture.csp", + }; + const struct firmware *program; + int err; + + BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT); + program = p->csp_programs[index]; + if (!program) { + err = request_firmware(&program, names[index], + p->chip->card->dev); + if (err >= 0) + p->csp_programs[index] = program; + else { +#ifdef FIRMWARE_IN_THE_KERNEL + program = &snd_sb_csp_static_programs[index]; +#else + return err; +#endif + } + } + return snd_sb_csp_load(p, program->data, program->size, flags); +} + /* * autoload hardware codec if necessary * return 0 if CSP is loaded and ready to run (p->running != 0) @@ -708,27 +753,27 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec } else { switch (pcm_sfmt) { case SNDRV_PCM_FORMAT_MU_LAW: - err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0); + err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0); p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW; p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; break; case SNDRV_PCM_FORMAT_A_LAW: - err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0); + err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0); p->acc_format = SNDRV_PCM_FMTBIT_A_LAW; p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; break; case SNDRV_PCM_FORMAT_IMA_ADPCM: - err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init), - SNDRV_SB_CSP_LOAD_INITBLOCK); + err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT, + SNDRV_SB_CSP_LOAD_INITBLOCK); if (err) break; if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) { - err = snd_sb_csp_load(p, &ima_adpcm_playback[0], - sizeof(ima_adpcm_playback), 0); + err = snd_sb_csp_firmware_load + (p, CSP_PROGRAM_ADPCM_PLAYBACK, 0); p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE; } else { - err = snd_sb_csp_load(p, &ima_adpcm_capture[0], - sizeof(ima_adpcm_capture), 0); + err = snd_sb_csp_firmware_load + (p, CSP_PROGRAM_ADPCM_CAPTURE, 0); p->mode = SNDRV_SB_CSP_MODE_DSP_READ; } p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM; diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 85db535aea9b..e2fdd5fd39d0 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -402,6 +402,7 @@ static struct snd_card *snd_wavefront_card_new(int dev) init_waitqueue_head(&acard->wavefront.interrupt_sleeper); spin_lock_init(&acard->wavefront.midi.open); spin_lock_init(&acard->wavefront.midi.virtual); + acard->wavefront.card = card; card->private_free = snd_wavefront_free; return card; diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index 4f0846feb73f..15331ed88194 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/time.h> #include <linux/wait.h> +#include <linux/firmware.h> #include <sound/core.h> #include <sound/snd_wavefront.h> #include <sound/initval.h> @@ -32,325 +33,17 @@ #define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */ #define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */ -/* weird stuff, derived from port I/O tracing with dosemu */ - -static unsigned char page_zero[] __devinitdata = { -0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, -0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00, -0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19, -0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01, -0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00, -0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02, -0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, -0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00, -0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02, -0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40, -0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02, -0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, -0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00, -0x1d, 0x02, 0xdf -}; - -static unsigned char page_one[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, -0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00, -0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, -0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00, -0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7, -0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, -0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0, -0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00, -0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0, -0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, -0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, -0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, -0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02, -0x60, 0x00, 0x1b -}; - -static unsigned char page_two[] __devinitdata = { -0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4, -0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07, -0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46, -0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46, -0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, -0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05, -0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05, -0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44 -}; - -static unsigned char page_three[] __devinitdata = { -0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06, -0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, -0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, -0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40, -0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, -0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00, -0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40 -}; - -static unsigned char page_four[] __devinitdata = { -0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, -0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00, -0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, -0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, -0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22, -0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01 -}; - -static unsigned char page_six[] __devinitdata = { -0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, -0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e, -0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00, -0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00, -0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24, -0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00, -0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00, -0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a, -0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00, -0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d, -0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50, -0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00, -0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17, -0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66, -0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c, -0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00, -0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c, -0x80, 0x00, 0x7e, 0x80, 0x80 -}; - -static unsigned char page_seven[] __devinitdata = { -0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, -0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, -0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, -0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f, -0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38, -0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06, -0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b, -0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06, -0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, -0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14, -0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93, -0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x02, 0x00 -}; - -static unsigned char page_zero_v2[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char page_one_v2[] __devinitdata = { -0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char page_two_v2[] __devinitdata = { -0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; -static unsigned char page_three_v2[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; -static unsigned char page_four_v2[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; +#define WAIT_IDLE 0xff -static unsigned char page_seven_v2[] __devinitdata = { -0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; +#define FIRMWARE_IN_THE_KERNEL -static unsigned char mod_v2[] __devinitdata = { -0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02, -0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05, -0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0, -0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20, -0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, -0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff, -0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16, -0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, -0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31, -0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, -0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, -0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00, -0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, -0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, -0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72, -0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0, -0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, -0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, -0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0, -0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, -0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, -0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00, -0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, -0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00, -0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02, -0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, -0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01, -0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01 -}; -static unsigned char coefficients[] __devinitdata = { -0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03, -0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, -0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01, -0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00, -0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00, -0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47, -0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07, -0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00, -0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01, -0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, -0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07, -0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, -0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02, -0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44, -0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, -0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40, -0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a, -0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56, -0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07, -0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda, -0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05, -0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79, -0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07, -0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52, -0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03, -0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a, -0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06, -0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3, -0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20, -0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c, -0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06, -0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48, -0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02, -0xba -}; -static unsigned char coefficients2[] __devinitdata = { -0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f, -0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d, -0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07, -0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, -0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00 -}; -static unsigned char coefficients3[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00, -0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc, -0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01, -0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99, -0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02, -0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f, -0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03, -0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c, -0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03, -0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51, -0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04, -0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e, -0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05, -0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14, -0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06, -0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1, -0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07, -0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7, -0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08, -0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3, -0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09, -0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99, -0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a, -0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66, -0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a, -0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c, -0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b, -0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28, -0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c, -0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e, -0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d, -0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb, -0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e, -0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1, -0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f, -0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae, -0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff +#ifdef FIRMWARE_IN_THE_KERNEL +#include "yss225.c" +static const struct firmware yss225_registers_firmware = { + .data = (u8 *)yss225_registers, + .size = sizeof yss225_registers }; +#endif static int wavefront_fx_idle (snd_wavefront_t *dev) @@ -555,465 +248,56 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file, of the port I/O done, using the Yamaha faxback document as a guide to add more logic to the code. Its really pretty weird. - There was an alternative approach of just dumping the whole I/O + This is the approach of just dumping the whole I/O sequence as a series of port/value pairs and a simple loop - that output it. However, I hope that eventually I'll get more - control over what this code does, and so I tried to stick with - a somewhat "algorithmic" approach. + that outputs it. */ - int __devinit snd_wavefront_fx_start (snd_wavefront_t *dev) - { - unsigned int i, j; + unsigned int i; + int err; + const struct firmware *firmware; - /* Set all bits for all channels on the MOD unit to zero */ - /* XXX But why do this twice ? */ + if (dev->fx_initialized) + return 0; - for (j = 0; j < 2; j++) { - for (i = 0x10; i <= 0xff; i++) { - - if (!wavefront_fx_idle (dev)) { - return (-1); + err = request_firmware(&firmware, "yamaha/yss225_registers.bin", + dev->card->dev); + if (err < 0) { +#ifdef FIRMWARE_IN_THE_KERNEL + firmware = &yss225_registers_firmware; +#else + err = -1; + goto out; +#endif + } + + for (i = 0; i + 1 < firmware->size; i += 2) { + if (firmware->data[i] >= 8 && firmware->data[i] < 16) { + outb(firmware->data[i + 1], + dev->base + firmware->data[i]); + } else if (firmware->data[i] == WAIT_IDLE) { + if (!wavefront_fx_idle(dev)) { + err = -1; + goto out; } - - outb (i, dev->fx_mod_addr); - outb (0x0, dev->fx_mod_data); - } - } - - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x02, dev->fx_op); /* mute on */ - - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x44, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x42, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x43, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x7c, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x7e, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x46, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x49, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x47, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x4a, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - - /* either because of stupidity by TB's programmers, or because it - actually does something, rezero the MOD page. - */ - for (i = 0x10; i <= 0xff; i++) { - - if (!wavefront_fx_idle (dev)) { - return (-1); + } else { + snd_printk(KERN_ERR "invalid address" + " in register data\n"); + err = -1; + goto out; } - - outb (i, dev->fx_mod_addr); - outb (0x0, dev->fx_mod_data); - } - /* load page zero */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x00, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_zero); i += 2) { - outb (page_zero[i], dev->fx_dsp_msb); - outb (page_zero[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - /* Now load page one */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x01, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_one); i += 2) { - outb (page_one[i], dev->fx_dsp_msb); - outb (page_one[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x02, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_two); i++) { - outb (page_two[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x03, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_three); i++) { - outb (page_three[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x04, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_four); i++) { - outb (page_four[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - /* Load memory area (page six) */ - - outb (FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x06, dev->fx_dsp_page); - - for (i = 0; i < sizeof (page_six); i += 3) { - outb (page_six[i], dev->fx_dsp_addr); - outb (page_six[i+1], dev->fx_dsp_msb); - outb (page_six[i+2], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x07, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_seven); i += 2) { - outb (page_seven[i], dev->fx_dsp_msb); - outb (page_seven[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - /* Now setup the MOD area. We do this algorithmically in order to - save a little data space. It could be done in the same fashion - as the "pages". - */ - - for (i = 0x00; i <= 0x0f; i++) { - outb (0x01, dev->fx_mod_addr); - outb (i, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x02, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0xb0; i <= 0xbf; i++) { - outb (i, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); } - for (i = 0xf0; i <= 0xff; i++) { - outb (i, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x10; i <= 0x1d; i++) { - outb (i, dev->fx_mod_addr); - outb (0xff, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x1e, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x1f; i <= 0x2d; i++) { - outb (i, dev->fx_mod_addr); - outb (0xff, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x2e, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x2f; i <= 0x3e; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x3f, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x40; i <= 0x4d; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x4e, dev->fx_mod_addr); - outb (0x0e, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x4f, dev->fx_mod_addr); - outb (0x0e, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - - for (i = 0x50; i <= 0x6b; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x6c, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (0x6d, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (0x6e, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (0x6f, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x70; i <= 0x7f; i++) { - outb (i, dev->fx_mod_addr); - outb (0xc0, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x80; i <= 0xaf; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0xc0; i <= 0xdd; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0xde, dev->fx_mod_addr); - outb (0x10, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0xdf, dev->fx_mod_addr); - outb (0x10, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0xe0; i <= 0xef; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x00; i <= 0x0f; i++) { - outb (0x01, dev->fx_mod_addr); - outb (i, dev->fx_mod_data); - outb (0x02, dev->fx_mod_addr); - outb (0x01, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x02, dev->fx_op); /* mute on */ - - /* Now set the coefficients and so forth for the programs above */ - - for (i = 0; i < sizeof (coefficients); i += 4) { - outb (coefficients[i], dev->fx_dsp_page); - outb (coefficients[i+1], dev->fx_dsp_addr); - outb (coefficients[i+2], dev->fx_dsp_msb); - outb (coefficients[i+3], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - /* Some settings (?) that are too small to bundle into loops */ - - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x1e, dev->fx_mod_addr); - outb (0x14, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0xde, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0xdf, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - - /* some more coefficients */ - - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x06, dev->fx_dsp_page); - outb (0x78, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x40, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x03, dev->fx_dsp_addr); - outb (0x0f, dev->fx_dsp_msb); - outb (0xff, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x0b, dev->fx_dsp_addr); - outb (0x0f, dev->fx_dsp_msb); - outb (0xff, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x02, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x0a, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x46, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x49, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - - /* Now, for some strange reason, lets reload every page - and all the coefficients over again. I have *NO* idea - why this is done. I do know that no sound is produced - is this phase is omitted. - */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x00, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_zero_v2); i += 2) { - outb (page_zero_v2[i], dev->fx_dsp_msb); - outb (page_zero_v2[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x01, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_one_v2); i += 2) { - outb (page_one_v2[i], dev->fx_dsp_msb); - outb (page_one_v2[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - if (!wavefront_fx_idle (dev)) return (-1); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x02, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_two_v2); i++) { - outb (page_two_v2[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x03, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_three_v2); i++) { - outb (page_three_v2[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x04, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_four_v2); i++) { - outb (page_four_v2[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x06, dev->fx_dsp_page); - - /* Page six v.2 is algorithmic */ - - for (i = 0x10; i <= 0x3e; i += 2) { - outb (i, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x07, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_seven_v2); i += 2) { - outb (page_seven_v2[i], dev->fx_dsp_msb); - outb (page_seven_v2[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x00; i < sizeof(mod_v2); i += 2) { - outb (mod_v2[i], dev->fx_mod_addr); - outb (mod_v2[i+1], dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } + dev->fx_initialized = 1; + err = 0; - for (i = 0; i < sizeof (coefficients2); i += 4) { - outb (coefficients2[i], dev->fx_dsp_page); - outb (coefficients2[i+1], dev->fx_dsp_addr); - outb (coefficients2[i+2], dev->fx_dsp_msb); - outb (coefficients2[i+3], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0; i < sizeof (coefficients3); i += 2) { - int x; - - outb (0x07, dev->fx_dsp_page); - x = (i % 4) ? 0x4e : 0x4c; - outb (x, dev->fx_dsp_addr); - outb (coefficients3[i], dev->fx_dsp_msb); - outb (coefficients3[i+1], dev->fx_dsp_lsb); - } - - outb (0x00, dev->fx_op); /* mute off */ - if (!wavefront_fx_idle (dev)) return (-1); - - return (0); +out: +#ifdef FIRMWARE_IN_THE_KERNEL + if (firmware != &yss225_registers_firmware) +#endif + release_firmware(firmware); + return err; } diff --git a/sound/isa/wavefront/yss225.c b/sound/isa/wavefront/yss225.c new file mode 100644 index 000000000000..9f6be3ff8ecf --- /dev/null +++ b/sound/isa/wavefront/yss225.c @@ -0,0 +1,2739 @@ +/* + * Copyright (c) 1998-2002 by Paul Davis <pbd@op.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 + */ + +/* weird stuff, derived from port I/O tracing with dosemu */ + +static const struct { + unsigned char addr; + unsigned char data; +} yss225_registers[] __devinitdata = { +/* Set all bits for all channels on the MOD unit to zero */ +{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, + +/* XXX But why do this twice? */ +{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, + +/* mute on */ +{ WAIT_IDLE }, { 0x8, 0x02 }, + +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, + +/* either because of stupidity by TB's programmers, or because it + actually does something, rezero the MOD page. */ +{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, + +/* load page zero */ +{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x00 }, + +{ 0xd, 0x01 }, { 0xc, 0x7c }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1e }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x11 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x32 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x14 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xd1 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xf2 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xf4 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x15 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x50 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x71 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x92 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xb3 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xd4 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x70 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x11 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1d }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xdf }, { WAIT_IDLE }, + +/* Now load page one */ +{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x00 }, + +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1f }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xd8 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xd7 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xf7 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1c }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x3c }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x3f }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xdf }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x5d }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x7d }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x9e }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xbe }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x00 }, + +{ 0xc, 0xc4 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x25 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x06 }, { WAIT_IDLE }, +{ 0xc, 0xc4 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x25 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x04 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x04 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x00 }, + +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x47 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x06 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x70 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x00 }, + +{ 0xc, 0x63 }, { WAIT_IDLE }, +{ 0xc, 0x03 }, { WAIT_IDLE }, +{ 0xc, 0x26 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x2c }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x24 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x2e }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x21 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, + +/* Load memory area (page six) */ +{ 0x9, 0x01 }, { 0xb, 0x06 }, + +{ 0xa, 0x00 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x04 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x06 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x08 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x0c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x0e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x42 }, { 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x21 }, { WAIT_IDLE }, +{ 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x23 }, { WAIT_IDLE }, +{ 0xa, 0x4a }, { 0xd, 0x23 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x8f }, { WAIT_IDLE }, +{ 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x77 }, { WAIT_IDLE }, +{ 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE }, +{ 0xa, 0x52 }, { 0xd, 0x1c }, { 0xc, 0x92 }, { WAIT_IDLE }, +{ 0xa, 0x54 }, { 0xd, 0x1c }, { 0xc, 0x52 }, { WAIT_IDLE }, +{ 0xa, 0x56 }, { 0xd, 0x07 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc6 }, { WAIT_IDLE }, +{ 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x06 }, { WAIT_IDLE }, +{ 0xa, 0x5e }, { 0xd, 0x17 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xa, 0x62 }, { 0xd, 0x29 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x41 }, { WAIT_IDLE }, +{ 0xa, 0x66 }, { 0xd, 0x39 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE }, +{ 0xa, 0x6a }, { 0xd, 0x49 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE }, +{ 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd2 }, { WAIT_IDLE }, +{ 0xa, 0x70 }, { 0xd, 0x16 }, { 0xc, 0x0c }, { WAIT_IDLE }, +{ 0xa, 0x72 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x74 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xa, 0x76 }, { 0xd, 0x0f }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xa, 0x7a }, { 0xd, 0x13 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x7c }, { 0xd, 0x80 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x7e }, { 0xd, 0x80 }, { 0xc, 0x80 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x00 }, + +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xe9 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x1a }, { 0xc, 0x75 }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE }, +{ 0xd, 0x0b }, { 0xc, 0x16 }, { WAIT_IDLE }, +{ 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0xc8 }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE }, +{ 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x8f }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x7b }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x52 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +/* Now setup the MOD area. */ +{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x08 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x09 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0a }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0b }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0c }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0d }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0e }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0f }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb8 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb9 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xba }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbb }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbc }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbd }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbe }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbf }, { 0xf, 0x20 }, { WAIT_IDLE }, + +{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf8 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf9 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfa }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfb }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfc }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfd }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfe }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xff }, { 0xf, 0x20 }, { WAIT_IDLE }, + +{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x18 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x19 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1a }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1b }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1c }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1d }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1e }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x1f }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x28 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x29 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2a }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2b }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2c }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2d }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x2f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x38 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x39 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3f }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x48 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x49 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4e }, { 0xf, 0x0e }, { WAIT_IDLE }, +{ 0xe, 0x4f }, { 0xf, 0x0e }, { WAIT_IDLE }, +{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x58 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x59 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x68 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x69 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6c }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x6d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6e }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x6f }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x78 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x79 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7a }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7b }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7c }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7d }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7e }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7f }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x88 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x89 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x98 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x99 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xaa }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xab }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xac }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xad }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xae }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xaf }, { 0xf, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xca }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcb }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcc }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcd }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xce }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcf }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xda }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xdb }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xdc }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xdd }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xde }, { 0xf, 0x10 }, { WAIT_IDLE }, +{ 0xe, 0xdf }, { 0xf, 0x10 }, { WAIT_IDLE }, +{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xea }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xeb }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xec }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xed }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xee }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xef }, { 0xf, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0x01 }, { 0xf, 0x00 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x08 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x09 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0a }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0b }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0c }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0d }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0e }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0f }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, + +/* mute on */ +{ 0x8, 0x02 }, + +/* Now set the coefficients and so forth for the programs above */ +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x4b }, { 0xd, 0x03 }, { 0xc, 0x11 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x4d }, { 0xd, 0x01 }, { 0xc, 0x32 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x47 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x4a }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x00 }, { 0xd, 0x01 }, { 0xc, 0x1c }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x42 }, { 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x43 }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x51 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x50 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4f }, { 0xd, 0x03 }, { 0xc, 0x81 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x53 }, { 0xd, 0x1a }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x54 }, { 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x55 }, { 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x56 }, { 0xd, 0x0b }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x57 }, { 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x58 }, { 0xd, 0x0d }, { 0xc, 0xc9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x59 }, { 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x73 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x74 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x75 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x76 }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x77 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x78 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x79 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7a }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5e }, { 0xd, 0x03 }, { 0xc, 0x68 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5c }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5d }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x62 }, { 0xd, 0x03 }, { 0xc, 0x52 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x60 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x61 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x66 }, { 0xd, 0x03 }, { 0xc, 0x2e }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x64 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x65 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x6a }, { 0xd, 0x02 }, { 0xc, 0xf6 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x68 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x69 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x24 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd3 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x70 }, { 0xd, 0x15 }, { 0xc, 0xcb }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x52 }, { 0xd, 0x20 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x54 }, { 0xd, 0x20 }, { 0xc, 0x54 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x4a }, { 0xd, 0x27 }, { 0xc, 0x1d }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc8 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x90 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xdb }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x78 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x42 }, { 0xd, 0x02 }, { 0xc, 0xba }, { WAIT_IDLE }, + +/* Some settings (?) */ +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x14 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x20 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x20 }, + +/* some more coefficients */ +{ WAIT_IDLE }, { 0xb, 0x06 }, { 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x40 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x03 }, { 0xd, 0x0f }, { 0xc, 0xff }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0b }, { 0xd, 0x0f }, { 0xc, 0xff }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, + +/* Now, for some strange reason, lets reload every page + and all the coefficients over again. I have *NO* idea + why this is done. I do know that no sound is produced + is this phase is omitted. */ +{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x10 }, + +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x10 }, + +{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ WAIT_IDLE }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x10 }, + +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x10 }, + +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x10 }, + +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, + +/* Page six v.2 */ +{ 0x9, 0x01 }, { 0xb, 0x06 }, + +{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x10 }, + +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, + +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x45 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x48 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7b }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7d }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xff }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xff }, + +/* mute off */ +{ 0x8, 0x00 }, { WAIT_IDLE } +}; diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 8a6b1803c763..1bcfb3aac18d 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -236,7 +236,7 @@ config SND_CS5535AUDIO config SND_DARLA20 tristate "(Echoaudio) Darla20" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Darla. @@ -247,7 +247,7 @@ config SND_DARLA20 config SND_GINA20 tristate "(Echoaudio) Gina20" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Gina. @@ -258,7 +258,7 @@ config SND_GINA20 config SND_LAYLA20 tristate "(Echoaudio) Layla20" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -270,7 +270,7 @@ config SND_LAYLA20 config SND_DARLA24 tristate "(Echoaudio) Darla24" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Darla24. @@ -281,7 +281,7 @@ config SND_DARLA24 config SND_GINA24 tristate "(Echoaudio) Gina24" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Gina24. @@ -292,7 +292,7 @@ config SND_GINA24 config SND_LAYLA24 tristate "(Echoaudio) Layla24" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -304,7 +304,7 @@ config SND_LAYLA24 config SND_MONA tristate "(Echoaudio) Mona" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -316,7 +316,7 @@ config SND_MONA config SND_MIA tristate "(Echoaudio) Mia" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -328,7 +328,7 @@ config SND_MIA config SND_ECHO3G tristate "(Echoaudio) 3G cards" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -340,7 +340,7 @@ config SND_ECHO3G config SND_INDIGO tristate "(Echoaudio) Indigo" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Indigo. @@ -351,7 +351,7 @@ config SND_INDIGO config SND_INDIGOIO tristate "(Echoaudio) Indigo IO" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Indigo IO. @@ -362,7 +362,7 @@ config SND_INDIGOIO config SND_INDIGODJ tristate "(Echoaudio) Indigo DJ" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Indigo DJ. @@ -373,6 +373,7 @@ config SND_INDIGODJ config SND_EMU10K1 tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" depends on SND + select FW_LOADER select SND_HWDEP select SND_RAWMIDI select SND_AC97_CODEC @@ -575,6 +576,7 @@ config SND_INTEL8X0M config SND_KORG1212 tristate "Korg 1212 IO" depends on SND + select FW_LOADER select SND_PCM help Say Y here to include support for Korg 1212IO soundcards. @@ -585,6 +587,7 @@ config SND_KORG1212 config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" depends on SND + select FW_LOADER select SND_AC97_CODEC help Say Y here to include support for soundcards based on ESS Maestro 3 @@ -629,7 +632,7 @@ config SND_PCXHR config SND_RIPTIDE tristate "Conexant Riptide" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC @@ -734,6 +737,7 @@ config SND_VX222 config SND_YMFPCI tristate "Yamaha YMF724/740/744/754" depends on SND + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index d2994cb4c8c9..74ed81081478 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -111,7 +111,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL }, { 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL }, { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, -{ 0x41445378, 0xffffffff, "AD1986", patch_ad1985, NULL }, +{ 0x41445378, 0xffffffff, "AD1986", patch_ad1986, NULL }, { 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL }, { 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL }, { 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */ @@ -194,6 +194,13 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { static void update_power_regs(struct snd_ac97 *ac97); +#ifdef CONFIG_SND_AC97_POWER_SAVE +#define ac97_is_power_save_mode(ac97) \ + ((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save) +#else +#define ac97_is_power_save_mode(ac97) 0 +#endif + /* * I/O routines @@ -982,8 +989,8 @@ static int snd_ac97_free(struct snd_ac97 *ac97) { if (ac97) { #ifdef CONFIG_SND_AC97_POWER_SAVE - if (ac97->power_workq) - destroy_workqueue(ac97->power_workq); + cancel_delayed_work(&ac97->power_work); + flush_scheduled_work(); #endif snd_ac97_proc_done(ac97); if (ac97->bus) @@ -1184,13 +1191,13 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, /* * set dB information */ -static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); -static unsigned int *find_db_scale(unsigned int maxval) +static const unsigned int *find_db_scale(unsigned int maxval) { switch (maxval) { case 0x0f: return db_scale_4bit; @@ -1200,8 +1207,8 @@ static unsigned int *find_db_scale(unsigned int maxval) return NULL; } -static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv) -{ +static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv) +{ kctl->tlv.p = tlv; if (tlv) kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; @@ -1989,7 +1996,6 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, mutex_init(&ac97->reg_mutex); mutex_init(&ac97->page_mutex); #ifdef CONFIG_SND_AC97_POWER_SAVE - ac97->power_workq = create_workqueue("ac97"); INIT_DELAYED_WORK(&ac97->power_work, do_update_power); #endif @@ -2275,15 +2281,13 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) udelay(100); power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ snd_ac97_write(ac97, AC97_POWERDOWN, power); -#ifdef CONFIG_SND_AC97_POWER_SAVE - if (power_save) { + if (ac97_is_power_save_mode(ac97)) { udelay(100); /* AC-link powerdown, internal Clk disable */ /* FIXME: this may cause click noises on some boards */ power |= AC97_PD_PR4 | AC97_PD_PR5; snd_ac97_write(ac97, AC97_POWERDOWN, power); } -#endif } @@ -2337,14 +2341,16 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) } } - if (power_save && !powerup && ac97->power_workq) + if (ac97_is_power_save_mode(ac97) && !powerup) /* adjust power-down bits after two seconds delay * (for avoiding loud click noises for many (OSS) apps * that open/close frequently) */ - queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2); - else + schedule_delayed_work(&ac97->power_work, HZ*2); + else { + cancel_delayed_work(&ac97->power_work); update_power_regs(ac97); + } return 0; } @@ -2357,19 +2363,15 @@ static void update_power_regs(struct snd_ac97 *ac97) unsigned int power_up, bits; int i; + power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); + power_up |= (1 << PWIDX_MIC); + if (ac97->scaps & AC97_SCAP_SURROUND_DAC) + power_up |= (1 << PWIDX_SURR); + if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) + power_up |= (1 << PWIDX_CLFE); #ifdef CONFIG_SND_AC97_POWER_SAVE - if (power_save) + if (ac97_is_power_save_mode(ac97)) power_up = ac97->power_up; - else { -#endif - power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); - power_up |= (1 << PWIDX_MIC); - if (ac97->scaps & AC97_SCAP_SURROUND_DAC) - power_up |= (1 << PWIDX_SURR); - if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) - power_up |= (1 << PWIDX_CLFE); -#ifdef CONFIG_SND_AC97_POWER_SAVE - } #endif if (power_up) { if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) { @@ -2414,6 +2416,10 @@ void snd_ac97_suspend(struct snd_ac97 *ac97) return; if (ac97->build_ops->suspend) ac97->build_ops->suspend(ac97); +#ifdef CONFIG_SND_AC97_POWER_SAVE + cancel_delayed_work(&ac97->power_work); + flush_scheduled_work(); +#endif snd_ac97_powerdown(ac97); } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index e813968e0cf8..641d0c8d659e 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -54,7 +54,7 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro /* replace with a new TLV */ static void reset_tlv(struct snd_ac97 *ac97, const char *name, - unsigned int *tlv) + const unsigned int *tlv) { struct snd_ctl_elem_id sid; struct snd_kcontrol *kctl; @@ -190,14 +190,28 @@ static inline int is_clfe_on(struct snd_ac97 *ac97) return ac97->channel_mode >= 2; } +/* system has shared jacks with surround out enabled */ +static inline int is_shared_surrout(struct snd_ac97 *ac97) +{ + return !ac97->indep_surround && is_surround_on(ac97); +} + +/* system has shared jacks with center/lfe out enabled */ +static inline int is_shared_clfeout(struct snd_ac97 *ac97) +{ + return !ac97->indep_surround && is_clfe_on(ac97); +} + +/* system has shared jacks with line in enabled */ static inline int is_shared_linein(struct snd_ac97 *ac97) { - return ! ac97->indep_surround && is_surround_on(ac97); + return !ac97->indep_surround && !is_surround_on(ac97); } +/* system has shared jacks with mic in enabled */ static inline int is_shared_micin(struct snd_ac97 *ac97) { - return ! ac97->indep_surround && is_clfe_on(ac97); + return !ac97->indep_surround && !is_clfe_on(ac97); } @@ -941,6 +955,9 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97) { int err; + /* the register bit is writable, but the function is not implemented: */ + snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL); + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback"); if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0) return err; @@ -1552,7 +1569,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = { AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ }; -static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); static int patch_ad1885_specific(struct snd_ac97 * ac97) { @@ -1609,19 +1626,22 @@ int patch_ad1886(struct snd_ac97 * ac97) return 0; } -/* MISC bits */ +/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */ #define AC97_AD198X_MBC 0x0003 /* mic boost */ #define AC97_AD198X_MBC_20 0x0000 /* +20dB */ #define AC97_AD198X_MBC_10 0x0001 /* +10dB */ #define AC97_AD198X_MBC_30 0x0002 /* +30dB */ #define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */ -#define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */ -#define AC97_AD198X_VREF_0 0x000c /* 0V */ +#define AC97_AD198X_VREFH 0x0008 /* 0=2.25V, 1=3.7V */ +#define AC97_AD198X_VREF_0 0x000c /* 0V (AD1985 only) */ +#define AC97_AD198X_VREF_MASK (AC97_AD198X_VREFH | AC97_AD198X_VREFD) +#define AC97_AD198X_VREF_SHIFT 2 #define AC97_AD198X_SRU 0x0010 /* sample rate unlock */ #define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */ #define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */ #define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */ -#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */ +#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: */ + /* 0 = 6-to-4, 1 = 6-to-2 downmix */ #define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */ #define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */ #define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */ @@ -1630,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97) #define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */ #define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */ +/* MISC 1 bits (AD1986 register 0x76) */ +#define AC97_AD1986_MBC 0x0003 /* mic boost */ +#define AC97_AD1986_MBC_20 0x0000 /* +20dB */ +#define AC97_AD1986_MBC_10 0x0001 /* +10dB */ +#define AC97_AD1986_MBC_30 0x0002 /* +30dB */ +#define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */ +#define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */ +#define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0) +#define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */ +#define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */ +#define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */ +#define AC97_AD1986_SRU 0x0010 /* sample rate unlock */ +#define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */ +#define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */ +#define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */ +#define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */ + /* 0 = 6-to-4, 1 = 6-to-2 downmix */ +#define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */ +#define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */ +#define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */ +#define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */ +#define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */ +#define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */ + +/* MISC 2 bits (AD1986 register 0x70) */ +#define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */ + +#define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */ +#define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */ +#define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */ +#define AC97_AD1986_CVREF_MASK \ + (AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0) +#define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */ +#define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */ +#define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */ +#define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */ +#define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */ +#define AC97_AD1986_MVREF_MASK \ + (AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0) + +/* MISC 3 bits (AD1986 register 0x7a) */ +#define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */ + +#define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */ +#define AC97_AD1986_GPO 0x0008 /* General Purpose Out */ +#define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */ +#define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */ +#define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */ +#define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */ +#define AC97_AD1986_LVREF_MASK \ + (AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0) +#define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */ +#define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */ +#define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */ + /* input select Surround DACs */ +#define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */ + /* select C/LFE DACs */ +#define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */ + +/* Serial Config bits (AD1986 register 0x74) (incomplete) */ +#define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */ +#define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */ +#define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */ +#define AC97_AD1986_OMS_MASK \ + (AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0) +#define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */ +#define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */ +#define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */ +#define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */ + /* are MIC sources */ +#define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */ + /* are MIC sources */ +#define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */ + /* are MIC sources */ +#define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */ + /* are MIC sources */ + static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1952,8 +2049,80 @@ int patch_ad1980(struct snd_ac97 * ac97) return 0; } +static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"}; + + uinfo->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; +} + +static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + static const int reg2ctrl[4] = {2, 0, 1, 3}; + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK) + >> AC97_AD198X_VREF_SHIFT; + ucontrol->value.enumerated.item[0] = reg2ctrl[val]; + return 0; +} + +static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + static const int ctrl2reg[4] = {1, 2, 0, 3}; + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 3 + || ucontrol->value.enumerated.item[0] < 0) + return -EINVAL; + val = ctrl2reg[ucontrol->value.enumerated.item[0]] + << AC97_AD198X_VREF_SHIFT; + return snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD198X_VREF_MASK, val); +} + static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = { - AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) + AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Front/Surround", + .info = snd_ac97_ad1888_lohpsel_info, + .get = snd_ac97_ad1888_lohpsel_get, + .put = snd_ac97_ad1888_lohpsel_put + }, + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1), + AC97_SINGLE("Spread Front to Surround and Center/LFE", + AC97_AD_MISC, 7, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Downmix", + .info = snd_ac97_ad1888_downmix_info, + .get = snd_ac97_ad1888_downmix_get, + .put = snd_ac97_ad1888_downmix_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "V_REFOUT", + .info = snd_ac97_ad1985_vrefout_info, + .get = snd_ac97_ad1985_vrefout_get, + .put = snd_ac97_ad1985_vrefout_put + }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, + + AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0), + AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0), }; static void ad1985_update_jacks(struct snd_ac97 *ac97) @@ -1967,9 +2136,16 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97) { int err; - if ((err = patch_ad1980_specific(ac97)) < 0) + /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ + snd_ac97_rename_vol_ctl(ac97, "Master Playback", + "Master Surround Playback"); + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); + + if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) return err; - return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls)); + + return patch_build_controls(ac97, snd_ac97_ad1985_controls, + ARRAY_SIZE(snd_ac97_ad1985_controls)); } static struct snd_ac97_build_ops patch_ad1985_build_ops = { @@ -1989,24 +2165,311 @@ int patch_ad1985(struct snd_ac97 * ac97) ac97->build_ops = &patch_ad1985_build_ops; misc = snd_ac97_read(ac97, AC97_AD_MISC); /* switch front/surround line-out/hp-out */ - /* center/LFE, mic in 3.75V mode */ /* AD-compatible mode */ /* Stereo mutes enabled */ - /* in accordance with ADI driver: misc | 0x5c28 */ snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | - AC97_AD198X_VREFH | AC97_AD198X_LOSEL | AC97_AD198X_HPSEL | - AC97_AD198X_CLDIS | - AC97_AD198X_LODIS | AC97_AD198X_MSPLT | AC97_AD198X_AC97NC); ac97->flags |= AC97_STEREO_MUTES; + + /* update current jack configuration */ + ad1985_update_jacks(ac97); + /* on AD1985 rev. 3, AC'97 revision bits are zero */ ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23; return 0; } +static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC3]; + ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0; + return 0; +} + +static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + int ret0; + int ret1; + int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0; + + ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL, + ucontrol->value.integer.value[0] != 0 + ? AC97_AD1986_LOSEL : 0); + if (ret0 < 0) + return ret0; + + /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */ + ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL, + (ucontrol->value.integer.value[0] != 0 + || sprd) + ? AC97_AD1986_SOSEL : 0); + if (ret1 < 0) + return ret1; + + return (ret0 > 0 || ret1 > 0) ? 1 : 0; +} + +static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC]; + ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0; + return 0; +} + +static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + int ret0; + int ret1; + int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0; + + ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD, + ucontrol->value.integer.value[0] != 0 + ? AC97_AD1986_SPRD : 0); + if (ret0 < 0) + return ret0; + + /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */ + ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL, + (ucontrol->value.integer.value[0] != 0 + || sprd) + ? AC97_AD1986_SOSEL : 0); + if (ret1 < 0) + return ret1; + + return (ret0 > 0 || ret1 > 0) ? 1 : 0; +} + +static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein; + return 0; +} + +static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned char swap = ucontrol->value.integer.value[0] != 0; + + if (swap != ac97->spec.ad18xx.swap_mic_linein) { + ac97->spec.ad18xx.swap_mic_linein = swap; + if (ac97->build_ops->update_jacks) + ac97->build_ops->update_jacks(ac97); + return 1; + } + return 0; +} + +static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* Use MIC_1/2 V_REFOUT as the "get" value */ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + unsigned short reg = ac97->regs[AC97_AD_MISC2]; + if ((reg & AC97_AD1986_MVREF0) != 0) + val = 2; + else if ((reg & AC97_AD1986_MVREF1) != 0) + val = 3; + else if ((reg & AC97_AD1986_MVREF2) != 0) + val = 1; + else + val = 0; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short cval; + unsigned short lval; + unsigned short mval; + int cret; + int lret; + int mret; + + switch (ucontrol->value.enumerated.item[0]) + { + case 0: /* High-Z */ + cval = 0; + lval = 0; + mval = 0; + break; + case 1: /* 3.7 V */ + cval = AC97_AD1986_CVREF2; + lval = AC97_AD1986_LVREF2; + mval = AC97_AD1986_MVREF2; + break; + case 2: /* 2.25 V */ + cval = AC97_AD1986_CVREF0; + lval = AC97_AD1986_LVREF0; + mval = AC97_AD1986_MVREF0; + break; + case 3: /* 0 V */ + cval = AC97_AD1986_CVREF1; + lval = AC97_AD1986_LVREF1; + mval = AC97_AD1986_MVREF1; + break; + default: + return -EINVAL; + } + + cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2, + AC97_AD1986_CVREF_MASK, cval); + if (cret < 0) + return cret; + lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3, + AC97_AD1986_LVREF_MASK, lval); + if (lret < 0) + return lret; + mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2, + AC97_AD1986_MVREF_MASK, mval); + if (mret < 0) + return mret; + + return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0; +} + +static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = { + AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Front/Surround", + .info = snd_ac97_ad1986_bool_info, + .get = snd_ac97_ad1986_lososel_get, + .put = snd_ac97_ad1986_lososel_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Mic/Line In", + .info = snd_ac97_ad1986_bool_info, + .get = snd_ac97_ad1986_miclisel_get, + .put = snd_ac97_ad1986_miclisel_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Spread Front to Surround and Center/LFE", + .info = snd_ac97_ad1986_bool_info, + .get = snd_ac97_ad1986_spread_get, + .put = snd_ac97_ad1986_spread_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Downmix", + .info = snd_ac97_ad1888_downmix_info, + .get = snd_ac97_ad1888_downmix_get, + .put = snd_ac97_ad1888_downmix_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "V_REFOUT", + .info = snd_ac97_ad1985_vrefout_info, + .get = snd_ac97_ad1986_vrefout_get, + .put = snd_ac97_ad1986_vrefout_put + }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, + + AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0), + AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0) +}; + +static void ad1986_update_jacks(struct snd_ac97 *ac97) +{ + unsigned short misc_val = 0; + unsigned short ser_val; + + /* disable SURROUND and CENTER/LFE if not surround mode */ + if (! is_surround_on(ac97)) + misc_val |= AC97_AD1986_SODIS; + if (! is_clfe_on(ac97)) + misc_val |= AC97_AD1986_CLDIS; + + /* select line input (default=LINE_IN, SURROUND or MIC_1/2) */ + if (is_shared_linein(ac97)) + misc_val |= AC97_AD1986_LISEL_SURR; + else if (ac97->spec.ad18xx.swap_mic_linein != 0) + misc_val |= AC97_AD1986_LISEL_MIC; + snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD1986_SODIS | AC97_AD1986_CLDIS | + AC97_AD1986_LISEL_MASK, + misc_val); + + /* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */ + if (is_shared_micin(ac97)) + ser_val = AC97_AD1986_OMS_C; + else if (ac97->spec.ad18xx.swap_mic_linein != 0) + ser_val = AC97_AD1986_OMS_L; + else + ser_val = AC97_AD1986_OMS_M; + snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, + AC97_AD1986_OMS_MASK, + ser_val); +} + +static int patch_ad1986_specific(struct snd_ac97 *ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + return err; + + return patch_build_controls(ac97, snd_ac97_ad1986_controls, + ARRAY_SIZE(snd_ac97_ad1985_controls)); +} + +static struct snd_ac97_build_ops patch_ad1986_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1986_specific, +#ifdef CONFIG_PM + .resume = ad18xx_resume, +#endif + .update_jacks = ad1986_update_jacks, +}; + +int patch_ad1986(struct snd_ac97 * ac97) +{ + patch_ad1881(ac97); + ac97->build_ops = &patch_ad1986_build_ops; + ac97->flags |= AC97_STEREO_MUTES; + + /* update current jack configuration */ + ad1986_update_jacks(ac97); + + return 0; +} + + /* * realtek ALC65x/850 codecs */ @@ -2014,12 +2477,12 @@ static void alc650_update_jacks(struct snd_ac97 *ac97) { int shared; - /* shared Line-In */ - shared = is_shared_linein(ac97); + /* shared Line-In / Surround Out */ + shared = is_shared_surrout(ac97); snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, shared ? (1 << 9) : 0); - /* update shared Mic */ - shared = is_shared_micin(ac97); + /* update shared Mic In / Center/LFE Out */ + shared = is_shared_clfeout(ac97); /* disable/enable vref */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, shared ? (1 << 12) : 0); @@ -2064,7 +2527,7 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = { /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ }; -static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); static int patch_alc650_specific(struct snd_ac97 * ac97) { @@ -2149,12 +2612,12 @@ static void alc655_update_jacks(struct snd_ac97 *ac97) { int shared; - /* shared Line-In */ - shared = is_shared_linein(ac97); + /* shared Line-In / Surround Out */ + shared = is_shared_surrout(ac97); ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, shared ? (1 << 9) : 0, 0); - /* update shared mic */ - shared = is_shared_micin(ac97); + /* update shared Mic In / Center/LFE Out */ + shared = is_shared_clfeout(ac97); /* misc control; vrefout disable */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, shared ? (1 << 12) : 0); @@ -2264,7 +2727,8 @@ int patch_alc655(struct snd_ac97 * ac97) if (ac97->subsystem_vendor == 0x1462 && (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */ ac97->subsystem_device == 0x0161 || /* LG K1 Express */ - ac97->subsystem_device == 0x0351)) /* MSI L725 laptop */ + ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */ + ac97->subsystem_device == 0x0061)) /* MSI S250 laptop */ val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ else val |= (1 << 1); /* Pin 47 is spdif input pin */ @@ -2297,16 +2761,16 @@ static void alc850_update_jacks(struct snd_ac97 *ac97) { int shared; - /* shared Line-In */ - shared = is_shared_linein(ac97); + /* shared Line-In / Surround Out */ + shared = is_shared_surrout(ac97); /* SURR 1kOhm (bit4), Amp (bit5) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), shared ? (1<<5) : (1<<4)); /* LINE-IN = 0, SURROUND = 2 */ snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, shared ? (2<<12) : (0<<12)); - /* update shared mic */ - shared = is_shared_micin(ac97); + /* update shared Mic In / Center/LFE Out */ + shared = is_shared_clfeout(ac97); /* Vref disable (bit12), 1kOhm (bit13) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), shared ? (1<<12) : (1<<13)); @@ -2379,9 +2843,9 @@ int patch_alc850(struct snd_ac97 *ac97) */ static void cm9738_update_jacks(struct snd_ac97 *ac97) { - /* shared Line-In */ + /* shared Line-In / Surround Out */ snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, - is_shared_linein(ac97) ? (1 << 10) : 0); + is_shared_surrout(ac97) ? (1 << 10) : 0); } static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = { @@ -2463,12 +2927,12 @@ static const struct snd_kcontrol_new snd_ac97_cm9739_controls_spdif[] = { static void cm9739_update_jacks(struct snd_ac97 *ac97) { - /* shared Line-In */ + /* shared Line-In / Surround Out */ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, - is_shared_linein(ac97) ? (1 << 10) : 0); - /* shared Mic */ + is_shared_surrout(ac97) ? (1 << 10) : 0); + /* shared Mic In / Center/LFE Out **/ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, - is_shared_micin(ac97) ? 0x1000 : 0x2000); + is_shared_clfeout(ac97) ? 0x1000 : 0x2000); } static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = { @@ -2580,8 +3044,8 @@ static void cm9761_update_jacks(struct snd_ac97 *ac97) val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)]; val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)]; - val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)]; - val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)]; + val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)]; + val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)]; snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val); } @@ -2821,6 +3285,7 @@ int patch_vt1617a(struct snd_ac97 * ac97) snd_ac97_write_cache(ac97, 0x5c, 0x20); ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; + ac97->build_ops = &patch_vt1616_ops; return 0; } @@ -2828,12 +3293,12 @@ int patch_vt1617a(struct snd_ac97 * ac97) */ static void it2646_update_jacks(struct snd_ac97 *ac97) { - /* shared Line-In */ + /* shared Line-In / Surround Out */ snd_ac97_update_bits(ac97, 0x76, 1 << 9, - is_shared_linein(ac97) ? (1<<9) : 0); - /* shared Mic */ + is_shared_surrout(ac97) ? (1<<9) : 0); + /* shared Mic / Center/LFE Out */ snd_ac97_update_bits(ac97, 0x76, 1 << 10, - is_shared_micin(ac97) ? (1<<10) : 0); + is_shared_clfeout(ac97) ? (1<<10) : 0); } static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = { diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 741979217207..94340daaaf1f 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -48,6 +48,7 @@ int patch_ad1980(struct snd_ac97 * ac97); int patch_ad1981a(struct snd_ac97 * ac97); int patch_ad1981b(struct snd_ac97 * ac97); int patch_ad1985(struct snd_ac97 * ac97); +int patch_ad1986(struct snd_ac97 * ac97); int patch_alc650(struct snd_ac97 * ac97); int patch_alc655(struct snd_ac97 * ac97); int patch_alc850(struct snd_ac97 * ac97); diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index c153cb79c518..dc26820a03a5 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c @@ -267,9 +267,9 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl return change; } -static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); -static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); -static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); static struct snd_kcontrol_new snd_ak4531_controls[] = { diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 9f406fbe0d95..8afcb98ca7bb 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -444,7 +444,7 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream) } static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream, - snd_pcm_hw_params_t * hw_params) + struct snd_pcm_hw_params *hw_params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); @@ -673,7 +673,7 @@ static void snd_als300_init(struct snd_als300 *chip) snd_als300_dbgcallleave(); } -static int __devinit snd_als300_create(snd_card_t *card, +static int __devinit snd_als300_create(struct snd_card *card, struct pci_dev *pci, int chip_type, struct snd_als300 **rchip) { @@ -681,7 +681,7 @@ static int __devinit snd_als300_create(snd_card_t *card, void *irq_handler; int err; - static snd_device_ops_t ops = { + static struct snd_device_ops ops = { .dev_free = snd_als300_dev_free, }; *rchip = NULL; diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 476c3433073e..7d8053b5e8d5 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -45,6 +45,7 @@ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static int ac97_clock = 48000; static char *ac97_quirk; static int spdif_aclink = 1; +static int ac97_codec = -1; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); @@ -54,6 +55,8 @@ module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); +module_param(ac97_codec, int, 0444); +MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing."); module_param(spdif_aclink, bool, 0444); MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); @@ -293,6 +296,10 @@ static struct pci_device_id snd_atiixp_ids[] = { MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); +static struct snd_pci_quirk atiixp_quirks[] __devinitdata = { + SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0), + { } /* terminator */ +}; /* * lowlevel functions @@ -553,11 +560,33 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) ATI_REG_ISR_CODEC2_NOT_READY) #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) +static int ac97_probing_bugs(struct pci_dev *pci) +{ + const struct snd_pci_quirk *q; + + q = snd_pci_quirk_lookup(pci, atiixp_quirks); + if (q) { + snd_printdd(KERN_INFO "Atiixp quirk for %s. " + "Forcing codec %d\n", q->name, q->value); + return q->value; + } + /* this hardware doesn't need workarounds. Probe for codec */ + return -1; +} + static int snd_atiixp_codec_detect(struct atiixp *chip) { int timeout; chip->codec_not_ready_bits = 0; + if (ac97_codec == -1) + ac97_codec = ac97_probing_bugs(chip->pci); + if (ac97_codec >= 0) { + chip->codec_not_ready_bits |= + CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10)); + return 0; + } + atiixp_write(chip, IER, CODEC_CHECK_BITS); /* wait for the interrupts */ timeout = 50; @@ -1396,7 +1425,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock, ac97.private_data = chip; ac97.pci = chip->pci; ac97.num = i; - ac97.scaps = AC97_SCAP_SKIP_MODEM; + ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; if (! chip->spdif_over_aclink) ac97.scaps |= AC97_SCAP_NO_SPDIF; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index cc2e6b9d407e..904023fe4f26 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1090,7 +1090,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) ac97.private_data = chip; ac97.pci = chip->pci; ac97.num = i; - ac97.scaps = AC97_SCAP_SKIP_AUDIO; + ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { chip->ac97[i] = NULL; /* to be sure */ snd_printdd("atiixp-modem: codec %d not available for modem\n", i); diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index f61f052f6d14..ea6712b63c9f 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1382,7 +1382,6 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ chip->spdif_enable = 0; /* Set digital SPDIF output off */ - chip->capture_source = 3; /* Set CAPTURE_SOURCE */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ @@ -1402,8 +1401,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ } - snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ - chip->capture_source = 3; /* Set CAPTURE_SOURCE */ + if (chip->details->i2c_adc == 1) { + /* Select MIC, Line in, TAD in, AUX in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); + /* Default to CAPTURE_SOURCE to i2s in */ + chip->capture_source = 3; + } else if (chip->details->ac97 == 1) { + /* Default to AC97 in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); + /* Default to CAPTURE_SOURCE to AC97 in */ + chip->capture_source = 4; + } else { + /* Select MIC, Line in, TAD in, AUX in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); + /* Default to Set CAPTURE_SOURCE to i2s in */ + chip->capture_source = 3; + } if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ @@ -1605,6 +1618,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_ca0106_proc_init(chip); #endif + snd_card_set_dev(card, &pci->dev); + if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 9855f528ea78..b913a1fb8c21 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -74,8 +74,8 @@ #include "ca0106.h" -static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); -static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); +static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); +static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -482,19 +482,6 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, .private_value = ((chid) << 8) | (reg) \ } -#define I2C_VOLUME(xname,chid) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ - .info = snd_ca0106_i2c_volume_info, \ - .get = snd_ca0106_i2c_volume_get, \ - .put = snd_ca0106_i2c_volume_put, \ - .tlv = { .p = snd_ca0106_db_scale2 }, \ - .private_value = chid \ -} - - static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { CA_VOLUME("Analog Front Playback Volume", CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), @@ -517,11 +504,6 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { CA_VOLUME("CAPTURE feedback Playback Volume", 1, CAPTURE_CONTROL), - I2C_VOLUME("Phone Capture Volume", 0), - I2C_VOLUME("Mic Capture Volume", 1), - I2C_VOLUME("Line in Capture Volume", 2), - I2C_VOLUME("Aux Capture Volume", 3), - { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -539,14 +521,14 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Capture Source", + .name = "Digital Source Capture Enum", .info = snd_ca0106_capture_source_info, .get = snd_ca0106_capture_source_get, .put = snd_ca0106_capture_source_put }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", + .name = "Analog Source Capture Enum", .info = snd_ca0106_i2c_capture_source_info, .get = snd_ca0106_i2c_capture_source_get, .put = snd_ca0106_i2c_capture_source_put @@ -561,6 +543,25 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { }, }; +#define I2C_VOLUME(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_ca0106_i2c_volume_info, \ + .get = snd_ca0106_i2c_volume_get, \ + .put = snd_ca0106_i2c_volume_put, \ + .tlv = { .p = snd_ca0106_db_scale2 }, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = { + I2C_VOLUME("Phone Capture Volume", 0), + I2C_VOLUME("Mic Capture Volume", 1), + I2C_VOLUME("Line in Capture Volume", 2), + I2C_VOLUME("Aux Capture Volume", 3), +}; + static int __devinit remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; @@ -645,6 +646,11 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) return err; } if (emu->details->i2c_adc == 1) { + for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu)); + if (err < 0) + return err; + } if (emu->details->gpio_type == 1) err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); else /* gpio_type == 2 */ diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8e5519de7115..44cf54607647 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol, return change; } -static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); static struct snd_kcontrol_new snd_cs4281_fm_vol = { diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index b7108e29a668..8e7fe033270f 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c @@ -47,6 +47,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index e59a982ee361..a13c623eb999 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c @@ -51,6 +51,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 12099fe1547d..8fb15823aca5 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c @@ -58,6 +58,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index d26a1d1f3ed1..48eb7c599111 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -39,7 +39,7 @@ static int set_phantom_power(struct echoaudio *chip, char on); static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq, char force); -#include <linux/irq.h> +#include <linux/interrupt.h> static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 047e0b5bf15d..6a428b81dba6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -34,6 +34,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; +static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); static int get_firmware(const struct firmware **fw_entry, const struct firmware *frm, struct echoaudio *chip) @@ -1011,17 +1012,21 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { .name = "Line Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_output_gain_info, .get = snd_echo_output_gain_get, .put = snd_echo_output_gain_put, + .tlv = {.p = db_scale_output_gain}, }; #else static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_output_gain_info, .get = snd_echo_output_gain_get, .put = snd_echo_output_gain_put, + .tlv = {.p = db_scale_output_gain}, }; #endif @@ -1080,12 +1085,16 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, return changed; } +static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); + static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { .name = "Line Capture Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_input_gain_info, .get = snd_echo_input_gain_get, .put = snd_echo_input_gain_put, + .tlv = {.p = db_scale_input_gain}, }; #endif /* ECHOCARD_HAS_INPUT_GAIN */ @@ -1277,9 +1286,11 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = { .name = "Monitor Mixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_mixer_info, .get = snd_echo_mixer_get, .put = snd_echo_mixer_put, + .tlv = {.p = db_scale_output_gain}, }; #endif /* ECHOCARD_HAS_MONITOR */ @@ -1343,9 +1354,11 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = { .name = "VMixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_vmixer_info, .get = snd_echo_vmixer_get, .put = snd_echo_vmixer_put, + .tlv = {.p = db_scale_output_gain}, }; #endif /* ECHOCARD_HAS_VMIXER */ @@ -1753,9 +1766,12 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = { .name = "VU-meters", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_vumeters_info, .get = snd_echo_vumeters_get, + .tlv = {.p = db_scale_output_gain}, }; diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index 29d6d12f80ca..af4d32026e4a 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c @@ -51,6 +51,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index e464d720d0bd..9ff454a947ed 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c @@ -57,6 +57,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index bfd2467099ac..37eb726fd03d 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c @@ -49,6 +49,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 8ed7ff1fd875..dc8b91824181 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c @@ -49,6 +49,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index a8788e959171..eadf3263453a 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c @@ -50,6 +50,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index e503d74b3ba9..6cede497579e 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c @@ -56,6 +56,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index d4581fdc841c..44f735426aa0 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c @@ -58,6 +58,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index be40c64263d2..dc172d03ac3f 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c @@ -56,6 +56,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 5dc512add372..c856ed50dd9a 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c @@ -55,6 +55,7 @@ #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> +#include <sound/tlv.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/asoundef.h> diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 972ec40d8166..80aa585eade4 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -3,8 +3,10 @@ * Creative Labs, Inc. * Routines for control of EMU10K1 chips * - * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> + * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> * Added support for Audigy 2 Value. + * Added EMU 1010 support. + * General bug fixes and enhancements. * * * BUGS: @@ -41,8 +43,10 @@ #include <sound/core.h> #include <sound/emu10k1.h> +#include <linux/firmware.h> #include "p16v.h" #include "tina2.h" +#include "p17v.h" /************************************************************************* @@ -117,11 +121,28 @@ static unsigned int spi_dac_init[] = { 0x0622, 0x1400, }; + +static unsigned int i2c_adc_init[][2] = { + { 0x17, 0x00 }, /* Reset */ + { 0x07, 0x00 }, /* Timeout */ + { 0x0b, 0x22 }, /* Interface control */ + { 0x0c, 0x22 }, /* Master mode control */ + { 0x0d, 0x08 }, /* Powerdown control */ + { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ + { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ + { 0x10, 0x7b }, /* ALC Control 1 */ + { 0x11, 0x00 }, /* ALC Control 2 */ + { 0x12, 0x32 }, /* ALC Control 3 */ + { 0x13, 0x00 }, /* Noise gate control */ + { 0x14, 0xa6 }, /* Limiter control */ + { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ +}; static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) { unsigned int silent_page; int ch; + u32 tmp; /* disable audio and lock cache */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, @@ -160,8 +181,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ - u32 tmp; - //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; @@ -181,8 +200,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ - u32 tmp; - snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); @@ -211,7 +228,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) int size, n; size = ARRAY_SIZE(spi_dac_init); - for (n=0; n < size; n++) + for (n = 0; n < size; n++) snd_emu10k1_spi_write(emu, spi_dac_init[n]); snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10); @@ -228,6 +245,23 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ } + if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ + int size, n; + + snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f); + tmp = inl(emu->port + A_IOCFG); + outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */ + tmp = inl(emu->port + A_IOCFG); + size = ARRAY_SIZE(i2c_adc_init); + for (n = 0; n < size; n++) + snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); + for (n=0; n < 4; n++) { + emu->i2c_capture_volume[n][0]= 0xcf; + emu->i2c_capture_volume[n][1]= 0xcf; + } + + } + snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ @@ -239,6 +273,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); } + if (emu->card_capabilities->emu1010) { + outl(HCFG_AUTOMUTE_ASYNC | + HCFG_EMU32_SLAVE | + HCFG_AUDIOENABLE, emu->port + HCFG); /* * Hokay, setup HCFG * Mute Disable Audio = 0 @@ -246,7 +284,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) * Lock Sound Memory = 0 * Auto Mute = 1 */ - if (emu->audigy) { + } else if (emu->audigy) { if (emu->revision == 4) /* audigy2 */ outl(HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | @@ -265,8 +303,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); if (enable_ir) { /* enable IR for SB Live */ - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); @@ -284,8 +324,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } } - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { /* enable analog output */ unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); @@ -302,8 +344,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); /* Enable analog/digital outs on audigy */ - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); @@ -596,133 +640,423 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) return 0; } -static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value) +static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename) { - if (reg<0 || reg>0x3f) - return 1; - reg+=0x40; /* 0x40 upwards are registers. */ - if (value<0 || value>0x3f) /* 0 to 0x3f are values */ - return 1; - outl(reg, emu->port + A_IOCFG); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - outl(value, emu->port + A_IOCFG); - outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - - return 0; -} - -static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) -{ - if (reg<0 || reg>0x3f) - return 1; - reg+=0x40; /* 0x40 upwards are registers. */ - outl(reg, emu->port + A_IOCFG); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - *value = inl(emu->port + A_IOCFG); - - return 0; -} + int err; + int n, i; + int reg; + int value; + const struct firmware *fw_entry; + + if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { + snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); + return err; + } + snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); + if (fw_entry->size != 0x133a4) { + snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename); + return -EINVAL; + } -static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value) -{ - snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) ); + /* The FPGA is a Xilinx Spartan IIE XC2S50E */ + /* GPIO7 -> FPGA PGMN + * GPIO6 -> FPGA CCLK + * GPIO5 -> FPGA DIN + * FPGA CONFIG OFF -> FPGA PGMN + */ + outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ + udelay(1); + outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ + udelay(100); /* Allow FPGA memory to clean */ + for(n = 0; n < fw_entry->size; n++) { + value=fw_entry->data[n]; + for(i = 0; i < 8; i++) { + reg = 0x80; + if (value & 0x1) + reg = reg | 0x20; + value = value >> 1; + outl(reg, emu->port + A_IOCFG); + outl(reg | 0x40, emu->port + A_IOCFG); + } + } + /* After programming, set GPIO bit 4 high again. */ + outl(0x10, emu->port + A_IOCFG); + + release_firmware(fw_entry); return 0; } -static int snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) { unsigned int i; - int tmp; - - snd_printk(KERN_ERR "emu1212m: Special config.\n"); + int tmp,tmp2; + int reg; + int err; + const char *hana_filename = "emu/hana.fw"; + const char *dock_filename = "emu/audio_dock.fw"; + + snd_printk(KERN_INFO "emu1010: Special config.\n"); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Mute all codecs. + */ outl(0x0005a00c, emu->port + HCFG); - outl(0x0005a004, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Lock Tank Memory Cache, + * Mute all codecs. + */ + outl(0x0005a004, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Mute all codecs. + */ outl(0x0005a000, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Mute all codecs. + */ outl(0x0005a000, emu->port + HCFG); - snd_emu1212m_fpga_read(emu, 0x22, &tmp ); - snd_emu1212m_fpga_read(emu, 0x23, &tmp ); - snd_emu1212m_fpga_read(emu, 0x24, &tmp ); - snd_emu1212m_fpga_write(emu, 0x04, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x0b, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0b, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x10, &tmp ); - snd_emu1212m_fpga_write(emu, 0x10, 0x00 ); - snd_emu1212m_fpga_read(emu, 0x11, &tmp ); - snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); - snd_emu1212m_fpga_read(emu, 0x13, &tmp ); - snd_emu1212m_fpga_write(emu, 0x13, 0x0f ); - snd_emu1212m_fpga_read(emu, 0x11, &tmp ); - snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); - snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_write(emu, 0x09, 0x0f ); - snd_emu1212m_fpga_write(emu, 0x06, 0x00 ); - snd_emu1212m_fpga_write(emu, 0x05, 0x00 ); - snd_emu1212m_fpga_write(emu, 0x0e, 0x12 ); - snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200); - snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201); - snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500); - snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501); - snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400); - snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401); - snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402); - snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403); - snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404); - snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405); - snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406); - snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407); - snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100); - snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104); - snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200); - snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201); - for (i=0;i < 0x20;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000); + /* Disable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + + /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg1=0x%x\n",reg); + if (reg == 0x55) { + /* FPGA netlist already present so clear it */ + /* Return to programming mode */ + + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 ); } - for (i=0;i < 4;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg2=0x%x\n",reg); + if (reg == 0x55) { + /* FPGA failed to return to programming mode */ + return -ENODEV; } - for (i=0;i < 7;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000); + snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); + if ((err = snd_emu1010_load_firmware(emu, hana_filename)) != 0) { + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", hana_filename); + return err; } - for (i=0;i < 7;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000); + + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + if (reg != 0x55) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg); + return -ENODEV; } - snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108); - snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c); - snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110); - snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114); - snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118); - snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c); - snd_emu1212m_fpga_write(emu, 0x07, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); + snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 ); + snd_printk("Hana ver:%d.%d\n",tmp ,tmp2); + /* Enable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON ); + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); + /* ADAT input. */ + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 ); + snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); + /* Set no attenuation on Audio Dock pads. */ + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); + emu->emu1010.adc_pads = 0x00; + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + /* Unmute Audio dock DACs, Headphone source DAC-4. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); + snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp ); + /* DAC PADs. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f ); + emu->emu1010.dac_pads = 0x0f; + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); + /* MIDI routing */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); + /* Unknown. */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); + /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ + /* IRQ Enable: All off */ + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg); + /* Default WCLK set to 48kHz. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 ); + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + /* Audio Dock LEDs. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); - outl(0x0000a000, emu->port + HCFG); +#if 0 + /* For 96kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2); +#endif +#if 0 + /* For 192kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4); +#endif +#if 1 + /* For 48kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1); +#endif +#if 0 + /* Original */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); +#endif + for (i = 0;i < 0x20; i++ ) { + /* AudioDock Elink <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 4; i++) { + /* Hana SPDIF Out <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 7; i++) { + /* Hamoa DAC <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 7; i++) { + /* Hana ADAT Out <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); + } + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + + /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Mute all codecs. + */ + outl(0x0000a000, emu->port + HCFG); + /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Un-Mute all codecs. + */ outl(0x0000a001, emu->port + HCFG); + /* Initial boot complete. Now patches */ - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); - - snd_emu1212m_fpga_read(emu, 0x20, &tmp ); - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); - - snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312); - snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313); - snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302); - snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ + + /* Delay to allow Audio Dock to settle */ + msleep(100); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ + /* FIXME: The loading of this should be able to happen any time, + * as the user can plug/unplug it at any time + */ + if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) { + /* Audio Dock attached */ + /* Return to Audio Dock programming mode */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); + if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) { + return err; + } + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); + if (reg != 0x55) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); + return 0; + return -ENODEV; + } + snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); + snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); + } +#if 0 + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ +#endif + /* Default outputs */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[0] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[1] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); + emu->emu1010.output_source[2] = 23; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); + emu->emu1010.output_source[3] = 24; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); + emu->emu1010.output_source[4] = 25; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); + emu->emu1010.output_source[5] = 26; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); + emu->emu1010.output_source[6] = 27; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); + emu->emu1010.output_source[7] = 28; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[8] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[9] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[10] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[11] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[12] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[13] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[14] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[15] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[16] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[17] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); + emu->emu1010.output_source[18] = 23; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); + emu->emu1010.output_source[19] = 24; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); + emu->emu1010.output_source[20] = 25; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); + emu->emu1010.output_source[21] = 26; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); + emu->emu1010.output_source[22] = 27; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); + emu->emu1010.output_source[23] = 28; + + /* TEMP: Select SPDIF in/out */ + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ + + /* TEMP: Select 48kHz SPDIF out */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + emu->emu1010.internal_clock = 1; /* 48000 */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ + //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ + //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */ + //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */ return 0; } @@ -747,6 +1081,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } snd_emu10k1_free_efx(emu); } + if (emu->card_capabilities->emu1010) { + /* Disable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + } if (emu->memhdr) snd_util_memhdr_free(emu->memhdr); if (emu->silent_page.area) @@ -838,10 +1176,11 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , /* Audigy 2 ZS Notebook Cardbus card.*/ - /* Tested by James@superbug.co.uk 22th December 2005 */ + /* Tested by James@superbug.co.uk 6th November 2006 */ /* Audio output 7.1/Headphones working. * Digital output working. (AC3 not checked, only PCM) - * Audio inputs not tested. + * Audio Mic/Line inputs working. + * Digital input not tested. */ /* DSP: Tina2 * DAC: Wolfson WM8768/WM8568 @@ -849,6 +1188,25 @@ static struct snd_emu_chip_details emu_chip_details[] = { * AC97: None * CA0151: None */ + /* Tested by James@superbug.co.uk 4th April 2006 */ + /* A_IOCFG bits + * Output + * 0: Not Used + * 1: 0 = Mute all the 7.1 channel out. 1 = unmute. + * 2: Analog input 0 = line in, 1 = mic in + * 3: Not Used + * 4: Digital output 0 = off, 1 = on. + * 5: Not Used + * 6: Not Used + * 7: Not Used + * Input + * All bits 1 (0x3fxx) means nothing plugged in. + * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing. + * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing. + * C-D: 2 = Front/Rear/etc, 3 = nothing. + * E-F: Always 0 + * + */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", .id = "Audigy2", @@ -856,6 +1214,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .ca_cardbus_chip = 1, .spi_dac = 1, + .i2c_adc = 1, .spk71 = 1} , {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", @@ -865,11 +1224,12 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ac97_chip = 1} , /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, - .driver = "Audigy2", .name = "E-mu 1212m [4001]", - .id = "EMU1212m", + .driver = "Audigy2", .name = "E-mu 1010 [4001]", + .id = "EMU1010", .emu10k2_chip = 1, .ca0102_chip = 1, - .emu1212m = 1} , + .spk71 = 1, + .emu1010 = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", @@ -1297,8 +1657,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, } else if (emu->card_capabilities->ca_cardbus_chip) { if ((err = snd_emu10k1_cardbus_init(emu)) < 0) goto error; - } else if (emu->card_capabilities->emu1212m) { - if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) { + } else if (emu->card_capabilities->emu1010) { + if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { snd_emu10k1_free(emu); return err; } @@ -1446,8 +1806,8 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) snd_emu10k1_ecard_init(emu); else if (emu->card_capabilities->ca_cardbus_chip) snd_emu10k1_cardbus_init(emu); - else if (emu->card_capabilities->emu1212m) - snd_emu10k1_emu1212m_init(emu); + else if (emu->card_capabilities->emu1010) + snd_emu10k1_emu1010_init(emu); else snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); snd_emu10k1_init(emu, emu->enable_ir, 1); diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 2199b42a6019..bb0fec7f7e1b 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -460,7 +460,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream) u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; - for(i=0; i < runtime->periods; i++) { + for(i = 0; i < runtime->periods; i++) { *table_base++=runtime->dma_addr+(i*period_size_bytes); *table_base++=period_size_bytes<<16; } @@ -1042,8 +1042,8 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff) - && (channel_id >=0) && (channel_id <= 2) ) + if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) + && (channel_id >= 0) && (channel_id <= 2) ) snd_emu10k1x_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 13cd6ce89811..c02012cccd8e 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -3,6 +3,9 @@ * Creative Labs, Inc. * Routines for effect processor FX8010 * + * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> + * Added EMU 1010 support. + * * BUGS: * -- * @@ -293,7 +296,7 @@ static const u32 db_table[101] = { }; /* EMU10k1/EMU10k2 DSP control db gain */ -static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); +static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); static const u32 onoff_table[2] = { 0x00000000, 0x00000001 @@ -652,13 +655,66 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id) return NULL; } +#define MAX_TLV_SIZE 256 + +static unsigned int *copy_tlv(const unsigned int __user *_tlv) +{ + unsigned int data[2]; + unsigned int *tlv; + + if (!_tlv) + return NULL; + if (copy_from_user(data, _tlv, sizeof(data))) + return NULL; + if (data[1] >= MAX_TLV_SIZE) + return NULL; + tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL); + if (!tlv) + return NULL; + memcpy(tlv, data, sizeof(data)); + if (copy_from_user(tlv + 2, _tlv + 2, data[1])) { + kfree(tlv); + return NULL; + } + return tlv; +} + +static int copy_gctl(struct snd_emu10k1 *emu, + struct snd_emu10k1_fx8010_control_gpr *gctl, + struct snd_emu10k1_fx8010_control_gpr __user *_gctl, + int idx) +{ + struct snd_emu10k1_fx8010_control_old_gpr __user *octl; + + if (emu->support_tlv) + return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)); + octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; + if (copy_from_user(gctl, &octl[idx], sizeof(*octl))) + return -EFAULT; + gctl->tlv = NULL; + return 0; +} + +static int copy_gctl_to_user(struct snd_emu10k1 *emu, + struct snd_emu10k1_fx8010_control_gpr __user *_gctl, + struct snd_emu10k1_fx8010_control_gpr *gctl, + int idx) +{ + struct snd_emu10k1_fx8010_control_old_gpr __user *octl; + + if (emu->support_tlv) + return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl)); + + octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; + return copy_to_user(&octl[idx], gctl, sizeof(*octl)); +} + static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_code *icode) { unsigned int i; struct snd_ctl_elem_id __user *_id; struct snd_ctl_elem_id id; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_control_gpr *gctl; int err; @@ -673,9 +729,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, if (! gctl) return -ENOMEM; err = 0; - for (i = 0, _gctl = icode->gpr_add_controls; - i < icode->gpr_add_control_count; i++, _gctl++) { - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + for (i = 0; i < icode->gpr_add_control_count; i++) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { err = -EFAULT; goto __error; } @@ -694,10 +749,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, goto __error; } } - for (i = 0, _gctl = icode->gpr_list_controls; - i < icode->gpr_list_control_count; i++, _gctl++) { + for (i = 0; i < icode->gpr_list_control_count; i++) { /* FIXME: we need to check the WRITE access */ - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) { err = -EFAULT; goto __error; } @@ -715,13 +769,14 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl) kctl->private_value = 0; list_del(&ctl->list); kfree(ctl); + if (kctl->tlv.p) + kfree(kctl->tlv.p); } static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_code *icode) { unsigned int i, j; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_control_gpr *gctl; struct snd_emu10k1_fx8010_ctl *ctl, *nctl; struct snd_kcontrol_new knew; @@ -737,9 +792,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, goto __error; } - for (i = 0, _gctl = icode->gpr_add_controls; - i < icode->gpr_add_control_count; i++, _gctl++) { - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + for (i = 0; i < icode->gpr_add_control_count; i++) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { err = -EFAULT; goto __error; } @@ -760,11 +814,10 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, knew.device = gctl->id.device; knew.subdevice = gctl->id.subdevice; knew.info = snd_emu10k1_gpr_ctl_info; - if (gctl->tlv.p) { - knew.tlv.p = gctl->tlv.p; + knew.tlv.p = copy_tlv(gctl->tlv); + if (knew.tlv.p) knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ; - } knew.get = snd_emu10k1_gpr_ctl_get; knew.put = snd_emu10k1_gpr_ctl_put; memset(nctl, 0, sizeof(*nctl)); @@ -782,12 +835,14 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); if (ctl == NULL) { err = -ENOMEM; + kfree(knew.tlv.p); goto __error; } knew.private_value = (unsigned long)ctl; *ctl = *nctl; if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { kfree(ctl); + kfree(knew.tlv.p); goto __error; } kctl->private_free = snd_emu10k1_ctl_private_free; @@ -838,7 +893,6 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, unsigned int i = 0, j; unsigned int total = 0; struct snd_emu10k1_fx8010_control_gpr *gctl; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_ctl *ctl; struct snd_ctl_elem_id *id; struct list_head *list; @@ -847,11 +901,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, if (! gctl) return -ENOMEM; - _gctl = icode->gpr_list_controls; list_for_each(list, &emu->fx8010.gpr_ctl) { ctl = emu10k1_gpr_ctl(list); total++; - if (_gctl && i < icode->gpr_list_control_count) { + if (icode->gpr_list_controls && + i < icode->gpr_list_control_count) { memset(gctl, 0, sizeof(*gctl)); id = &ctl->kcontrol->id; gctl->id.iface = id->iface; @@ -868,11 +922,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, gctl->min = ctl->min; gctl->max = ctl->max; gctl->translation = ctl->translation; - if (copy_to_user(_gctl, gctl, sizeof(*gctl))) { + if (copy_gctl_to_user(emu, icode->gpr_list_controls, + gctl, i)) { kfree(gctl); return -EFAULT; } - _gctl++; i++; } } @@ -1023,7 +1077,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->min = 0; ctl->max = 100; - ctl->tlv.p = snd_emu10k1_db_scale1; + ctl->tlv = snd_emu10k1_db_scale1; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; } @@ -1038,7 +1092,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; ctl->min = 0; ctl->max = 100; - ctl->tlv.p = snd_emu10k1_db_scale1; + ctl->tlv = snd_emu10k1_db_scale1; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; } @@ -1069,6 +1123,21 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; } +static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( + struct snd_emu10k1_fx8010_code *icode, + u32 *ptr, int tmp, int bit_shifter16, + int reg_in, int reg_out) +{ + A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000); + A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2)); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000); + A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000); + A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2)); + A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000); + return 1; +} /* * initial DSP configuration for Audigy @@ -1077,6 +1146,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, nctl; + int bit_shifter16; const int playback = 10; const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ const int stereo_mix = capture + 2; @@ -1114,17 +1184,14 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) ptr = 0; nctl = 0; gpr = stereo_mix + 10; + gpr_map[gpr++] = 0x00007fff; + gpr_map[gpr++] = 0x00008000; + gpr_map[gpr++] = 0x0000ffff; + bit_shifter16 = gpr; /* stop FX processor */ snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); -#if 0 - /* FIX: jcd test */ - for (z = 0; z < 80; z=z+2) { - A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */ - A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */ - } -#endif /* jcd test */ #if 1 /* PCM front Playback Volume (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); @@ -1182,13 +1249,20 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0); gpr += 2; - + /* * inputs */ #define A_ADD_VOLUME_IN(var,vol,input) \ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) + /* emu1212 DSP 0 and DSP 1 Capture */ + if (emu->card_capabilities->emu1010) { + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0); + gpr += 2; + } /* AC'97 Playback Volume - used only for mic (renamed later) */ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); @@ -1429,6 +1503,13 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* digital outputs */ /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ + if (emu->card_capabilities->emu1010) { + /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ + snd_printk("EMU outputs on\n"); + for (z = 0; z < 8; z++) { + A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + } + } /* IEC958 Optical Raw Playback Switch */ gpr_map[gpr++] = 0; @@ -1466,9 +1547,57 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); #endif - /* EFX capture - capture the 16 EXTINs */ - for (z = 0; z < 16; z++) { - A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); + if (emu->card_capabilities->emu1010) { + snd_printk("EMU inputs on\n"); + /* Capture 8 channels of S32_LE sound */ + + /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ + /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ + /* A_P16VIN(0) is delayed by one sample, + * so all other A_P16VIN channels will need to also be delayed + */ + /* Left ADC in. 1 of 2 */ + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); + /* Right ADC in 1 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); + /* For 96kHz mode */ + /* Left ADC in. 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); + /* Right ADC in 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); + +#if 0 + for (z = 4; z < 8; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); + } + for (z = 0xc; z < 0x10; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); + } +#endif + } else { + /* EFX capture - capture the 16 EXTINs */ + /* Capture 16 channels of S16_LE sound */ + for (z = 0; z < 16; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); + } } #endif /* JCD test */ @@ -1488,7 +1617,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) seg = snd_enter_user(); icode->gpr_add_control_count = nctl; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; + emu->support_tlv = 1; /* support TLV */ err = snd_emu10k1_icode_poke(emu, icode); + emu->support_tlv = 0; /* clear again */ snd_leave_user(seg); __err: @@ -2105,7 +2236,9 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) seg = snd_enter_user(); icode->gpr_add_control_count = i; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; + emu->support_tlv = 1; /* support TLV */ err = snd_emu10k1_icode_poke(emu, icode); + emu->support_tlv = 0; /* clear again */ snd_leave_user(seg); if (err >= 0) err = snd_emu10k1_ipcm_poke(emu, ipcm); @@ -2138,7 +2271,7 @@ void snd_emu10k1_free_efx(struct snd_emu10k1 *emu) snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP); } -#if 0 // FIXME: who use them? +#if 0 /* FIXME: who use them? */ int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output) { if (output < 0 || output >= 6) @@ -2249,6 +2382,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un int res; switch (cmd) { + case SNDRV_EMU10K1_IOCTL_PVERSION: + emu->support_tlv = 1; + return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp); case SNDRV_EMU10K1_IOCTL_INFO: info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index c31f3d0877fa..4db6e1ca1665 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -5,6 +5,9 @@ * Routines for control of EMU10K1 chips / mixer routines * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> * + * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> + * Added EMU 1010 support. + * * BUGS: * -- * @@ -32,9 +35,15 @@ #include <linux/init.h> #include <sound/core.h> #include <sound/emu10k1.h> +#include <linux/delay.h> +#include <sound/tlv.h> + +#include "p17v.h" #define AC97_ID_STAC9758 0x83847658 +static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ + static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -68,6 +77,669 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, return 0; } +static char *emu1010_src_texts[] = { + "Silence", + "Dock Mic A", + "Dock Mic B", + "Dock ADC1 Left", + "Dock ADC1 Right", + "Dock ADC2 Left", + "Dock ADC2 Right", + "Dock ADC3 Left", + "Dock ADC3 Right", + "0202 ADC Left", + "0202 ADC Right", + "0202 SPDIF Left", + "0202 SPDIF Right", + "ADAT 0", + "ADAT 1", + "ADAT 2", + "ADAT 3", + "ADAT 4", + "ADAT 5", + "ADAT 6", + "ADAT 7", + "DSP 0", + "DSP 1", + "DSP 2", + "DSP 3", + "DSP 4", + "DSP 5", + "DSP 6", + "DSP 7", + "DSP 8", + "DSP 9", + "DSP 10", + "DSP 11", + "DSP 12", + "DSP 13", + "DSP 14", + "DSP 15", + "DSP 16", + "DSP 17", + "DSP 18", + "DSP 19", + "DSP 20", + "DSP 21", + "DSP 22", + "DSP 23", + "DSP 24", + "DSP 25", + "DSP 26", + "DSP 27", + "DSP 28", + "DSP 29", + "DSP 30", + "DSP 31", +}; + +static unsigned int emu1010_src_regs[] = { + EMU_SRC_SILENCE,/* 0 */ + EMU_SRC_DOCK_MIC_A1, /* 1 */ + EMU_SRC_DOCK_MIC_B1, /* 2 */ + EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ + EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ + EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ + EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ + EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ + EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ + EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ + EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ + EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ + EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ + EMU_SRC_HANA_ADAT, /* 13 */ + EMU_SRC_HANA_ADAT+1, /* 14 */ + EMU_SRC_HANA_ADAT+2, /* 15 */ + EMU_SRC_HANA_ADAT+3, /* 16 */ + EMU_SRC_HANA_ADAT+4, /* 17 */ + EMU_SRC_HANA_ADAT+5, /* 18 */ + EMU_SRC_HANA_ADAT+6, /* 19 */ + EMU_SRC_HANA_ADAT+7, /* 20 */ + EMU_SRC_ALICE_EMU32A, /* 21 */ + EMU_SRC_ALICE_EMU32A+1, /* 22 */ + EMU_SRC_ALICE_EMU32A+2, /* 23 */ + EMU_SRC_ALICE_EMU32A+3, /* 24 */ + EMU_SRC_ALICE_EMU32A+4, /* 25 */ + EMU_SRC_ALICE_EMU32A+5, /* 26 */ + EMU_SRC_ALICE_EMU32A+6, /* 27 */ + EMU_SRC_ALICE_EMU32A+7, /* 28 */ + EMU_SRC_ALICE_EMU32A+8, /* 29 */ + EMU_SRC_ALICE_EMU32A+9, /* 30 */ + EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ + EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ + EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ + EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ + EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ + EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ + EMU_SRC_ALICE_EMU32B, /* 37 */ + EMU_SRC_ALICE_EMU32B+1, /* 38 */ + EMU_SRC_ALICE_EMU32B+2, /* 39 */ + EMU_SRC_ALICE_EMU32B+3, /* 40 */ + EMU_SRC_ALICE_EMU32B+4, /* 41 */ + EMU_SRC_ALICE_EMU32B+5, /* 42 */ + EMU_SRC_ALICE_EMU32B+6, /* 43 */ + EMU_SRC_ALICE_EMU32B+7, /* 44 */ + EMU_SRC_ALICE_EMU32B+8, /* 45 */ + EMU_SRC_ALICE_EMU32B+9, /* 46 */ + EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ + EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ + EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ + EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ + EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ + EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ +}; + +static unsigned int emu1010_output_dst[] = { + EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ + EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ + EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ + EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ + EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ + EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ + EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ + EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ + EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ + EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ + EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ + EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ + EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ + EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ + EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ + EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ + EMU_DST_HANA_ADAT, /* 16 */ + EMU_DST_HANA_ADAT+1, /* 17 */ + EMU_DST_HANA_ADAT+2, /* 18 */ + EMU_DST_HANA_ADAT+3, /* 19 */ + EMU_DST_HANA_ADAT+4, /* 20 */ + EMU_DST_HANA_ADAT+5, /* 21 */ + EMU_DST_HANA_ADAT+6, /* 22 */ + EMU_DST_HANA_ADAT+7, /* 23 */ +}; + +static unsigned int emu1010_input_dst[] = { + EMU_DST_ALICE2_EMU32_0, + EMU_DST_ALICE2_EMU32_1, + EMU_DST_ALICE2_EMU32_2, + EMU_DST_ALICE2_EMU32_3, + EMU_DST_ALICE2_EMU32_4, + EMU_DST_ALICE2_EMU32_5, + EMU_DST_ALICE2_EMU32_6, + EMU_DST_ALICE2_EMU32_7, + EMU_DST_ALICE2_EMU32_8, + EMU_DST_ALICE2_EMU32_9, + EMU_DST_ALICE2_EMU32_A, + EMU_DST_ALICE2_EMU32_B, + EMU_DST_ALICE2_EMU32_C, + EMU_DST_ALICE2_EMU32_D, + EMU_DST_ALICE2_EMU32_E, + EMU_DST_ALICE2_EMU32_F, + EMU_DST_ALICE_I2S0_LEFT, + EMU_DST_ALICE_I2S0_RIGHT, + EMU_DST_ALICE_I2S1_LEFT, + EMU_DST_ALICE_I2S1_RIGHT, + EMU_DST_ALICE_I2S2_LEFT, + EMU_DST_ALICE_I2S2_RIGHT, +}; + +static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 53; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int channel; + + channel = (kcontrol->private_value) & 0xff; + ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; + return 0; +} + +static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int change = 0; + unsigned int val; + int channel; + + channel = (kcontrol->private_value) & 0xff; + if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) { + val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0]; + change = 1; + snd_emu1010_fpga_link_dst_src_write(emu, + emu1010_output_dst[channel], emu1010_src_regs[val]); + } + return change; +} + +static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int channel; + + channel = (kcontrol->private_value) & 0xff; + ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; + return 0; +} + +static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int change = 0; + unsigned int val; + int channel; + + channel = (kcontrol->private_value) & 0xff; + if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) { + val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0]; + change = 1; + snd_emu1010_fpga_link_dst_src_write(emu, + emu1010_input_dst[channel], emu1010_src_regs[val]); + } + return change; +} + +#define EMU1010_SOURCE_OUTPUT(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_input_output_source_info, \ + .get = snd_emu1010_output_source_get, \ + .put = snd_emu1010_output_source_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { + EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), + EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), + EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), + EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), + EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), + EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), + EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), + EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), + EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), + EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), + EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), + EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), + EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), + EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), +}; + +#define EMU1010_SOURCE_INPUT(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_input_output_source_info, \ + .get = snd_emu1010_input_source_get, \ + .put = snd_emu1010_input_source_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { + EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), + EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), + EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), + EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), + EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), + EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), + EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), + EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), + EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), + EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), + EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), + EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), + EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), + EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), + EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), + EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), + EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), + EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), + EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), + EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), + EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), + EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), +}; + + + + +static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; + return 0; +} + +static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + unsigned int val, cache; + val = ucontrol->value.integer.value[0]; + cache = emu->emu1010.adc_pads; + if (val == 1) + cache = cache | mask; + else + cache = cache & ~mask; + if (cache != emu->emu1010.adc_pads) { + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); + emu->emu1010.adc_pads = cache; + } + + return 0; +} + + + +#define EMU1010_ADC_PADS(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_adc_pads_info, \ + .get = snd_emu1010_adc_pads_get, \ + .put = snd_emu1010_adc_pads_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { + EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), + EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), + EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), + EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), +}; + +static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; + return 0; +} + +static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + unsigned int val, cache; + val = ucontrol->value.integer.value[0]; + cache = emu->emu1010.dac_pads; + if (val == 1) + cache = cache | mask; + else + cache = cache & ~mask; + if (cache != emu->emu1010.dac_pads) { + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); + emu->emu1010.dac_pads = cache; + } + + return 0; +} + + + +#define EMU1010_DAC_PADS(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_dac_pads_info, \ + .get = snd_emu1010_dac_pads_get, \ + .put = snd_emu1010_dac_pads_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { + EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), + EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), + EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), + EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), + EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), +}; + + +static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2] = { + "44100", "48000" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; + return 0; +} + +static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->emu1010.internal_clock != val); + if (change) { + emu->emu1010.internal_clock = val; + switch (val) { + case 0: + /* 44100 */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); + /* Word Clock source, Internal 44.1kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + case 1: + /* 48000 */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + } + } + return change; +} + +static struct snd_kcontrol_new snd_emu1010_internal_clock = +{ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Internal Rate", + .count = 1, + .info = snd_emu1010_internal_clock_info, + .get = snd_emu1010_internal_clock_get, + .put = snd_emu1010_internal_clock_put +}; + +static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ +#if 0 + static char *texts[4] = { + "Unknown1", "Unknown2", "Mic", "Line" + }; +#endif + static char *texts[2] = { + "Mic", "Line" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; + return 0; +} + +static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int source_id; + unsigned int ngain, ogain; + u32 gpio; + int change = 0; + unsigned long flags; + u32 source; + /* If the capture source has changed, + * update the capture volume from the cached value + * for the particular source. + */ + source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */ + change = (emu->i2c_capture_source != source_id); + if (change) { + snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + spin_lock_irqsave(&emu->emu_lock, flags); + gpio = inl(emu->port + A_IOCFG); + if (source_id==0) + outl(gpio | 0x4, emu->port + A_IOCFG); + else + outl(gpio & ~0x4, emu->port + A_IOCFG); + spin_unlock_irqrestore(&emu->emu_lock, flags); + + ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ + if (ngain != ogain) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); + ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ + if (ngain != ogain) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); + + source = 1 << (source_id + 2); + snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ + emu->i2c_capture_source = source_id; + } + return change; +} + +static struct snd_kcontrol_new snd_audigy_i2c_capture_source = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = snd_audigy_i2c_capture_source_info, + .get = snd_audigy_i2c_capture_source_get, + .put = snd_audigy_i2c_capture_source_put +}; + +static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + return 0; +} + +static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int source_id; + + source_id = kcontrol->private_value; + + ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; + ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; + return 0; +} + +static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int ogain; + unsigned int ngain; + int source_id; + int change = 0; + + source_id = kcontrol->private_value; + ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ + ngain = ucontrol->value.integer.value[0]; + if (ngain > 0xff) + return 0; + if (ogain != ngain) { + if (emu->i2c_capture_source == source_id) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); + emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; + change = 1; + } + ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ + ngain = ucontrol->value.integer.value[1]; + if (ngain > 0xff) + return 0; + if (ogain != ngain) { + if (emu->i2c_capture_source == source_id) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); + emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; + change = 1; + } + + return change; +} + +#define I2C_VOLUME(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_audigy_i2c_volume_info, \ + .get = snd_audigy_i2c_volume_get, \ + .put = snd_audigy_i2c_volume_put, \ + .tlv = { .p = snd_audigy_db_scale2 }, \ + .private_value = chid \ +} + + +static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { + I2C_VOLUME("Mic Capture Volume", 0), + I2C_VOLUME("Line Capture Volume", 0) +}; + #if 0 static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -668,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, int change = 0; spin_lock_irqsave(&emu->reg_lock, flags); - if (emu->audigy) { + if ( emu->card_capabilities->i2c_adc) { + /* Do nothing for Audigy 2 ZS Notebook */ + } else if (emu->audigy) { reg = inl(emu->port + A_IOCFG); val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; change = (reg & A_IOCFG_GPOUT0) != val; @@ -806,6 +1480,24 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "AMic Playback Volume", "Mic Playback Volume", NULL }; + static char *audigy_rename_ctls_i2c_adc[] = { + //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", + "Line Capture Volume", "Analog Mix Capture Volume", + "Wave Playback Volume", "OLD PCM Playback Volume", + "Wave Master Playback Volume", "Master Playback Volume", + "AMic Playback Volume", "Old Mic Playback Volume", + "CD Capture Volume", "IEC958 Optical Capture Volume", + NULL + }; + static char *audigy_remove_ctls_i2c_adc[] = { + /* On the Audigy2 ZS Notebook + * Capture via WM8775 */ + "Mic Capture Volume", + "Analog Mix Capture Volume", + "Aux Capture Volume", + "IEC958 Optical Capture Volume", + NULL + }; static char *audigy_remove_ctls_1361t_adc[] = { /* On the Audigy2 the AC97 playback is piped into * the Philips ADC for 24bit capture */ @@ -890,6 +1582,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (emu->ac97->id == AC97_ID_STAC9758) { emu->rear_ac97 = 1; snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); + snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); } /* remove unused AC97 controls */ snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); @@ -898,6 +1591,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, } for (; *c; c++) remove_ctl(card, *c); + } else if (emu->card_capabilities->i2c_adc) { + c = audigy_remove_ctls_i2c_adc; + for (; *c; c++) + remove_ctl(card, *c); } else { no_ac97: if (emu->card_capabilities->ecard) @@ -911,6 +1608,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (emu->audigy) if (emu->card_capabilities->adc_1361t) c = audigy_rename_ctls_1361t_adc; + else if (emu->card_capabilities->i2c_adc) + c = audigy_rename_ctls_i2c_adc; else c = audigy_rename_ctls; else @@ -1021,7 +1720,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, return err; } - if ( emu->card_capabilities->emu1212m) { + if ( emu->card_capabilities->emu1010) { ; /* Disable the snd_audigy_spdif_shared_spdif */ } else if (emu->audigy) { if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) @@ -1045,6 +1744,48 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if ((err = snd_p16v_mixer(emu))) return err; } + + if ( emu->card_capabilities->emu1010) { + int i; + + for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); + if (err < 0) + return err; + } + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); + if (err < 0) + return err; + } + + if ( emu->card_capabilities->i2c_adc) { + int i; + + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); + if (err < 0) + return err; + } + } return 0; } diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 717e92ec9e0a..ab4f5df5241b 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -147,7 +147,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic 1, &epcm->extra); if (err < 0) { - // printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); + /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */ for (i = 0; i < voices; i++) { snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); epcm->voices[i] = NULL; @@ -339,7 +339,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, } } - // setup routing + /* setup routing */ if (emu->audigy) { snd_emu10k1_ptr_write(emu, A_FXRT1, voice, snd_emu10k1_compose_audigy_fxrt1(send_routing)); @@ -353,12 +353,15 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, } else snd_emu10k1_ptr_write(emu, FXRT, voice, snd_emu10k1_compose_send_routing(send_routing)); - // Stop CA - // Assumption that PT is already 0 so no harm overwriting + /* Stop CA */ + /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); - pitch_target = emu10k1_calc_pitch_target(runtime->rate); + if (emu->card_capabilities->emu1010) + pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ + else + pitch_target = emu10k1_calc_pitch_target(runtime->rate); if (extra) snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | emu10k1_select_interprom(pitch_target) | @@ -367,14 +370,14 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | emu10k1_select_interprom(pitch_target) | (w_16 ? 0 : CCCA_8BITSELECT)); - // Clear filter delay memory + /* Clear filter delay memory */ snd_emu10k1_ptr_write(emu, Z1, voice, 0); snd_emu10k1_ptr_write(emu, Z2, voice, 0); - // invalidate maps + /* invalidate maps */ silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); - // modulation envelope + /* modulation envelope */ snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); @@ -385,12 +388,12 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); - // volume envelope + /* volume envelope */ snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); - // filter envelope + /* filter envelope */ snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); - // pitch envelope + /* pitch envelope */ snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); spin_unlock_irqrestore(&emu->reg_lock, flags); @@ -468,7 +471,7 @@ static int snd_emu10k1_efx_playback_hw_free(struct snd_pcm_substream *substream) snd_emu10k1_voice_free(epcm->emu, epcm->extra); epcm->extra = NULL; } - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { if (epcm->voices[i]) { snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); epcm->voices[i] = NULL; @@ -637,7 +640,7 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e stereo = (!extra && runtime->channels == 2); sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; ccis = emu10k1_ccis(stereo, sample == 0); - // set cs to 2 * number of cache registers beside the invalidated + /* set cs to 2 * number of cache registers beside the invalidated */ cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; if (cs > 16) cs = 16; for (i = 0; i < cs; i++) { @@ -646,14 +649,14 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); } } - // reset cache + /* reset cache */ snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); if (stereo) { snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); } - // fill cache + /* fill cache */ snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); if (stereo) { snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); @@ -698,7 +701,10 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s voice = evoice->number; pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; - pitch_target = emu10k1_calc_pitch_target(runtime->rate); + if (emu->card_capabilities->emu1010) + pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ + else + pitch_target = emu10k1_calc_pitch_target(runtime->rate); snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); if (master || evoice->epcm->type == PLAYBACK_EFX) snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); @@ -732,7 +738,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, struct snd_emu10k1_pcm_mixer *mix; int result = 0; - // printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); + /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */ spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -778,10 +784,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - // hmm this should cause full and half full interrupt to be raised? + /* hmm this should cause full and half full interrupt to be raised? */ outl(epcm->capture_ipr, emu->port + IPR); snd_emu10k1_intr_enable(emu, epcm->capture_inte); - // printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); + /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */ switch (epcm->type) { case CAPTURE_AC97ADC: snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); @@ -790,6 +796,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, if (emu->audigy) { snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); + snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2); } else snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); break; @@ -851,7 +858,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * ptr -= runtime->buffer_size; } #endif - // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); + /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */ return ptr; } @@ -868,7 +875,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - // prepare voices + /* prepare voices */ for (i = 0; i < NUM_EFX_PLAYBACK; i++) { snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); } @@ -917,7 +924,7 @@ static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *s if (!epcm->running) return 0; if (epcm->first_ptr) { - udelay(50); // hack, it takes awhile until capture is started + udelay(50); /* hack, it takes awhile until capture is started */ epcm->first_ptr = 0; } ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff; @@ -972,6 +979,28 @@ static struct snd_pcm_hardware snd_emu10k1_capture = .fifo_size = 0, }; +static struct snd_pcm_hardware snd_emu10k1_capture_efx = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .rate_min = 44100, + .rate_max = 192000, + .channels_min = 8, + .channels_max = 8, + .buffer_bytes_max = (64*1024), + .period_bytes_min = 384, + .period_bytes_max = (64*1024), + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0, +}; + /* * */ @@ -1016,7 +1045,7 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream) struct snd_emu10k1_pcm_mixer *mix; int i; - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { mix = &emu->efx_pcm_mixer[i]; mix->epcm = NULL; snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0); @@ -1045,7 +1074,7 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_efx_playback; - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { mix = &emu->efx_pcm_mixer[i]; mix->send_routing[0][0] = i; memset(&mix->send_volume, 0, sizeof(mix->send_volume)); @@ -1199,15 +1228,69 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) epcm->capture_idx_reg = FXIDX; substream->runtime->private_data = epcm; substream->runtime->private_free = snd_emu10k1_pcm_free_substream; - runtime->hw = snd_emu10k1_capture; + runtime->hw = snd_emu10k1_capture_efx; runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; spin_lock_irq(&emu->reg_lock); - runtime->hw.channels_min = runtime->hw.channels_max = 0; - for (idx = 0; idx < nefx; idx++) { - if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { - runtime->hw.channels_min++; - runtime->hw.channels_max++; + if (emu->card_capabilities->emu1010) { + /* TODO + * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE + * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 |