aboutsummaryrefslogtreecommitdiff
path: root/sound/isa
diff options
context:
space:
mode:
Diffstat (limited to 'sound/isa')
-rw-r--r--sound/isa/Kconfig315
-rw-r--r--sound/isa/Makefile16
-rw-r--r--sound/isa/ad1816a/Makefile2
-rw-r--r--sound/isa/ad1816a/ad1816a.c161
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c149
-rw-r--r--sound/isa/ad1848/Makefile9
-rw-r--r--sound/isa/ad1848/ad1848.c192
-rw-r--r--sound/isa/ad1848/ad1848_lib.c1271
-rw-r--r--sound/isa/adlib.c126
-rw-r--r--sound/isa/als100.c217
-rw-r--r--sound/isa/azt2320.c134
-rw-r--r--sound/isa/cmi8328.c483
-rw-r--r--sound/isa/cmi8330.c449
-rw-r--r--sound/isa/cs423x/Makefile22
-rw-r--r--sound/isa/cs423x/cs4231.c226
-rw-r--r--sound/isa/cs423x/cs4231_lib.c1858
-rw-r--r--sound/isa/cs423x/cs4232.c2
-rw-r--r--sound/isa/cs423x/cs4236.c463
-rw-r--r--sound/isa/cs423x/cs4236_lib.c542
-rw-r--r--sound/isa/dt019x.c358
-rw-r--r--sound/isa/es1688/Makefile2
-rw-r--r--sound/isa/es1688/es1688.c406
-rw-r--r--sound/isa/es1688/es1688_lib.c111
-rw-r--r--sound/isa/es18xx.c800
-rw-r--r--sound/isa/galaxy/Makefile10
-rw-r--r--sound/isa/galaxy/azt1605.c91
-rw-r--r--sound/isa/galaxy/azt2316.c111
-rw-r--r--sound/isa/galaxy/galaxy.c648
-rw-r--r--sound/isa/gus/Makefile14
-rw-r--r--sound/isa/gus/gus_dma.c40
-rw-r--r--sound/isa/gus/gus_dram.c3
-rw-r--r--sound/isa/gus/gus_instr.c3
-rw-r--r--sound/isa/gus/gus_io.c3
-rw-r--r--sound/isa/gus/gus_irq.c31
-rw-r--r--sound/isa/gus/gus_main.c61
-rw-r--r--sound/isa/gus/gus_mem.c33
-rw-r--r--sound/isa/gus/gus_mem_proc.c51
-rw-r--r--sound/isa/gus/gus_mixer.c18
-rw-r--r--sound/isa/gus/gus_pcm.c47
-rw-r--r--sound/isa/gus/gus_reset.c3
-rw-r--r--sound/isa/gus/gus_sample.c165
-rw-r--r--sound/isa/gus/gus_simple.c634
-rw-r--r--sound/isa/gus/gus_synth.c312
-rw-r--r--sound/isa/gus/gus_tables.h2
-rw-r--r--sound/isa/gus/gus_timer.c3
-rw-r--r--sound/isa/gus/gus_uart.c13
-rw-r--r--sound/isa/gus/gus_volume.c4
-rw-r--r--sound/isa/gus/gusclassic.c296
-rw-r--r--sound/isa/gus/gusextreme.c387
-rw-r--r--sound/isa/gus/gusmax.c154
-rw-r--r--sound/isa/gus/interwave.c330
-rw-r--r--sound/isa/msnd/Makefile9
-rw-r--r--sound/isa/msnd/msnd.c708
-rw-r--r--sound/isa/msnd/msnd.h308
-rw-r--r--sound/isa/msnd/msnd_classic.c3
-rw-r--r--sound/isa/msnd/msnd_classic.h129
-rw-r--r--sound/isa/msnd/msnd_midi.c182
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c1243
-rw-r--r--sound/isa/msnd/msnd_pinnacle.h181
-rw-r--r--sound/isa/msnd/msnd_pinnacle_mixer.c344
-rw-r--r--sound/isa/opl3sa2.c412
-rw-r--r--sound/isa/opti9xx/Makefile4
-rw-r--r--sound/isa/opti9xx/miro.c1662
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c1796
-rw-r--r--sound/isa/sb/Makefile31
-rw-r--r--sound/isa/sb/emu8000.c61
-rw-r--r--sound/isa/sb/emu8000_callback.c3
-rw-r--r--sound/isa/sb/emu8000_local.h1
-rw-r--r--sound/isa/sb/emu8000_patch.c5
-rw-r--r--sound/isa/sb/emu8000_pcm.c10
-rw-r--r--sound/isa/sb/emu8000_synth.c3
-rw-r--r--sound/isa/sb/es968.c266
-rw-r--r--sound/isa/sb/jazz16.c401
-rw-r--r--sound/isa/sb/sb16.c231
-rw-r--r--sound/isa/sb/sb16_csp.c132
-rw-r--r--sound/isa/sb/sb16_csp_codecs.h949
-rw-r--r--sound/isa/sb/sb16_main.c23
-rw-r--r--sound/isa/sb/sb8.c115
-rw-r--r--sound/isa/sb/sb8_main.c134
-rw-r--r--sound/isa/sb/sb8_midi.c23
-rw-r--r--sound/isa/sb/sb_common.c31
-rw-r--r--sound/isa/sb/sb_mixer.c440
-rw-r--r--sound/isa/sc6000.c725
-rw-r--r--sound/isa/sgalaxy.c394
-rw-r--r--sound/isa/sscape.c1240
-rw-r--r--sound/isa/wavefront/Makefile2
-rw-r--r--sound/isa/wavefront/wavefront.c316
-rw-r--r--sound/isa/wavefront/wavefront_fx.c830
-rw-r--r--sound/isa/wavefront/wavefront_midi.c29
-rw-r--r--sound/isa/wavefront/wavefront_synth.c175
-rw-r--r--sound/isa/wss/Makefile10
-rw-r--r--sound/isa/wss/wss_lib.c2307
92 files changed, 14725 insertions, 12924 deletions
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index ff8fef93278..0216475fc75 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -1,19 +1,43 @@
# ALSA ISA drivers
-menu "ISA devices"
- depends on SND!=n && ISA && ISA_DMA_API
+config SND_WSS_LIB
+ tristate
+ select SND_PCM
+
+config SND_SB_COMMON
+ tristate
-config SND_AD1848_LIB
+config SND_SB8_DSP
tristate
select SND_PCM
+ select SND_SB_COMMON
-config SND_CS4231_LIB
+config SND_SB16_DSP
tristate
select SND_PCM
+ select SND_SB_COMMON
+
+menuconfig SND_ISA
+ bool "ISA sound devices"
+ depends on ISA && ISA_DMA_API
+ default y
+ help
+ Support for sound devices connected via the ISA bus.
+
+if SND_ISA
+
+config SND_ADLIB
+ tristate "AdLib FM card"
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for AdLib FM cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-adlib.
config SND_AD1816A
tristate "Analog Devices SoundPort AD1816A"
- depends on SND && PNP && ISA
+ depends on PNP
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -27,39 +51,65 @@ config SND_AD1816A
config SND_AD1848
tristate "Generic AD1848/CS4248 driver"
- depends on SND
- select SND_AD1848_LIB
+ select SND_WSS_LIB
help
Say Y here to include support for AD1848 (Analog Devices) or
CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
- For newer chips from Cirrus Logic, use the CS4231, CS4232 or
- CS4236+ drivers.
+ For newer chips from Cirrus Logic, use the CS4231 or CS4232+
+ drivers.
To compile this driver as a module, choose M here: the module
will be called snd-ad1848.
config SND_ALS100
- tristate "Avance Logic ALS100/ALS120"
- depends on SND && PNP && ISA
+ tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx"
+ depends on PNP
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB16_DSP
help
- Say Y here to include support for soundcards based on Avance
- Logic ALS100, ALS110, ALS120 and ALS200 chips.
+ Say Y here to include support for soundcards based on the
+ Diamond Technologies DT-019X or Avance Logic chips: ALS007,
+ ALS100, ALS110, ALS120 and ALS200 chips.
To compile this driver as a module, choose M here: the module
will be called snd-als100.
+config SND_AZT1605
+ tristate "Aztech AZT1605 Driver"
+ depends on SND
+ select SND_WSS_LIB
+ select SND_MPU401_UART
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for Aztech Sound Galaxy cards
+ based on the AZT1605 chipset.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-azt1605.
+
+config SND_AZT2316
+ tristate "Aztech AZT2316 Driver"
+ depends on SND
+ select SND_WSS_LIB
+ select SND_MPU401_UART
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for Aztech Sound Galaxy cards
+ based on the AZT2316 chipset.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-azt2316.
+
config SND_AZT2320
tristate "Aztech Systems AZT2320"
- depends on SND && PNP && ISA
+ depends on PNP
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_CS4231_LIB
+ select SND_WSS_LIB
help
Say Y here to include support for soundcards based on the
Aztech Systems AZT2320 chip.
@@ -67,10 +117,24 @@ config SND_AZT2320
To compile this driver as a module, choose M here: the module
will be called snd-azt2320.
+config SND_CMI8328
+ tristate "C-Media CMI8328"
+ select SND_WSS_LIB
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
+ help
+ Say Y here to include support for soundcards based on the
+ C-Media CMI8328 chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-cmi8328.
+
config SND_CMI8330
tristate "C-Media CMI8330"
- depends on SND
- select SND_AD1848_LIB
+ select SND_WSS_LIB
+ select SND_SB16_DSP
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
help
Say Y here to include support for soundcards based on the
C-Media CMI8330 chip.
@@ -80,9 +144,8 @@ config SND_CMI8330
config SND_CS4231
tristate "Generic Cirrus Logic CS4231 driver"
- depends on SND
select SND_MPU401_UART
- select SND_CS4231_LIB
+ select SND_WSS_LIB
help
Say Y here to include support for CS4231 chips from Cirrus
Logic - Crystal Semiconductors.
@@ -90,74 +153,33 @@ config SND_CS4231
To compile this driver as a module, choose M here: the module
will be called snd-cs4231.
-config SND_CS4232
- tristate "Generic Cirrus Logic CS4232 driver"
- depends on SND
- select SND_OPL3_LIB
- select SND_MPU401_UART
- select SND_CS4231_LIB
- help
- Say Y here to include support for CS4232 chips from Cirrus
- Logic - Crystal Semiconductors.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-cs4232.
-
config SND_CS4236
- tristate "Generic Cirrus Logic CS4236+ driver"
- depends on SND
+ tristate "Generic Cirrus Logic CS4232/CS4236+ driver"
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_CS4231_LIB
+ select SND_WSS_LIB
help
- Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
- CS4239 chips from Cirrus Logic - Crystal Semiconductors.
+ Say Y to include support for CS4232,CS4235,CS4236,CS4237B,
+ CS4238B,CS4239 chips from Cirrus Logic - Crystal
+ Semiconductors.
To compile this driver as a module, choose M here: the module
will be called snd-cs4236.
-config SND_DT019X
- tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
- depends on SND && PNP && ISA
- select ISAPNP
- select SND_OPL3_LIB
- select SND_MPU401_UART
- select SND_PCM
- help
- Say Y here to include support for soundcards based on the
- Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-dt019x.
-
-config SND_ES968
- tristate "Generic ESS ES968 driver"
- depends on SND && PNP && ISA
- select ISAPNP
- select SND_MPU401_UART
- select SND_PCM
- help
- Say Y here to include support for ESS AudioDrive ES968 chips.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-es968.
-
config SND_ES1688
- tristate "Generic ESS ES688/ES1688 driver"
- depends on SND
+ tristate "Generic ESS ES688/ES1688 and ES968 PnP driver"
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
help
Say Y here to include support for ESS AudioDrive ES688 or
- ES1688 chips.
+ ES1688 chips. Also, this module support cards with ES968 PnP chip.
To compile this driver as a module, choose M here: the module
will be called snd-es1688.
config SND_ES18XX
tristate "Generic ESS ES18xx driver"
- depends on SND
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -167,15 +189,26 @@ config SND_ES18XX
To compile this driver as a module, choose M here: the module
will be called snd-es18xx.
-config SND_GUS_SYNTH
- tristate
+config SND_SC6000
+ tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16"
+ depends on HAS_IOPORT_MAP
+ select SND_WSS_LIB
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
+ help
+ Say Y here to include support for Gallant SC-6000, SC-6600, SC-7000
+ cards and clones:
+ Audio Excel DSP 16 and Zoltrix AV302.
+
+ These cards are based on CompuMedia ASC-9308 or ASC-9408 chips.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-sc6000.
config SND_GUSCLASSIC
tristate "Gravis UltraSound Classic"
- depends on SND
select SND_RAWMIDI
select SND_PCM
- select SND_GUS_SYNTH
help
Say Y here to include support for Gravis UltraSound Classic
soundcards.
@@ -185,11 +218,9 @@ config SND_GUSCLASSIC
config SND_GUSEXTREME
tristate "Gravis UltraSound Extreme"
- depends on SND
- select SND_HWDEP
+ select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
- select SND_GUS_SYNTH
help
Say Y here to include support for Gravis UltraSound Extreme
soundcards.
@@ -199,10 +230,8 @@ config SND_GUSEXTREME
config SND_GUSMAX
tristate "Gravis UltraSound MAX"
- depends on SND
select SND_RAWMIDI
- select SND_CS4231_LIB
- select SND_GUS_SYNTH
+ select SND_WSS_LIB
help
Say Y here to include support for Gravis UltraSound MAX
soundcards.
@@ -212,10 +241,9 @@ config SND_GUSMAX
config SND_INTERWAVE
tristate "AMD InterWave, Gravis UltraSound PnP"
- depends on SND && PNP && ISA
+ depends on PNP
select SND_RAWMIDI
- select SND_CS4231_LIB
- select SND_GUS_SYNTH
+ select SND_WSS_LIB
help
Say Y here to include support for AMD InterWave based
soundcards (Gravis UltraSound Plug & Play, STB SoundRage32,
@@ -226,10 +254,9 @@ config SND_INTERWAVE
config SND_INTERWAVE_STB
tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
- depends on SND && PNP && ISA
+ depends on PNP
select SND_RAWMIDI
- select SND_CS4231_LIB
- select SND_GUS_SYNTH
+ select SND_WSS_LIB
help
Say Y here to include support for AMD InterWave based
soundcards with a TEA6330T bass and treble regulator
@@ -238,12 +265,27 @@ config SND_INTERWAVE_STB
To compile this driver as a module, choose M here: the module
will be called snd-interwave-stb.
+config SND_JAZZ16
+ tristate "Media Vision Jazz16 card and compatibles"
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
+ select SND_SB8_DSP
+ help
+ Say Y here to include support for soundcards based on the
+ Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16),
+ codec MVA416 (CS4216) and mixer MVA514 (ICS2514).
+ Media Vision's Jazz16 cards were sold under names Pro Sonic 16,
+ Premium 3-D and Pro 3-D. There were also OEMs cards with the
+ Jazz16 chipset.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-jazz16.
+
config SND_OPL3SA2
tristate "Yamaha OPL3-SA2/SA3"
- depends on SND
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_CS4231_LIB
+ select SND_WSS_LIB
help
Say Y here to include support for Yamaha OPL3-SA2 and OPL3-SA3
chips.
@@ -253,11 +295,10 @@ config SND_OPL3SA2
config SND_OPTI92X_AD1848
tristate "OPTi 82C92x - AD1848"
- depends on SND
select SND_OPL3_LIB
select SND_OPL4_LIB
select SND_MPU401_UART
- select SND_AD1848_LIB
+ select SND_WSS_LIB
help
Say Y here to include support for soundcards based on Opti
82C92x or OTI-601 chips and using an AD1848 codec.
@@ -267,11 +308,10 @@ config SND_OPTI92X_AD1848
config SND_OPTI92X_CS4231
tristate "OPTi 82C92x - CS4231"
- depends on SND
select SND_OPL3_LIB
select SND_OPL4_LIB
select SND_MPU401_UART
- select SND_CS4231_LIB
+ select SND_WSS_LIB
help
Say Y here to include support for soundcards based on Opti
82C92x chips and using a CS4231 codec.
@@ -281,10 +321,9 @@ config SND_OPTI92X_CS4231
config SND_OPTI93X
tristate "OPTi 82C93x"
- depends on SND
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_WSS_LIB
help
Say Y here to include support for soundcards based on Opti
82C93x chips.
@@ -292,12 +331,24 @@ config SND_OPTI93X
To compile this driver as a module, choose M here: the module
will be called snd-opti93x.
+config SND_MIRO
+ tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver"
+ select SND_OPL4_LIB
+ select SND_WSS_LIB
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say 'Y' or 'M' to include support for Miro miroSOUND PCM1 pro,
+ miroSOUND PCM12 and miroSOUND PCM20 Radio soundcards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-miro.
+
config SND_SB8
tristate "Sound Blaster 1.0/2.0/Pro (8-bit)"
- depends on SND
select SND_OPL3_LIB
select SND_RAWMIDI
- select SND_PCM
+ select SND_SB8_DSP
help
Say Y here to include support for Creative Sound Blaster 1.0/
2.0/Pro (8-bit) or 100% compatible soundcards.
@@ -307,10 +358,9 @@ config SND_SB8
config SND_SB16
tristate "Sound Blaster 16 (PnP)"
- depends on SND
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB16_DSP
help
Say Y here to include support for Sound Blaster 16 soundcards
(including the Plug and Play version).
@@ -320,10 +370,9 @@ config SND_SB16
config SND_SBAWE
tristate "Sound Blaster AWE (32,64) (PnP)"
- depends on SND
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB16_DSP
help
Say Y here to include support for Sound Blaster AWE soundcards
(including the Plug and Play version).
@@ -334,41 +383,39 @@ 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
decompression algorithms.
-config SND_SGALAXY
- tristate "Aztech Sound Galaxy"
- depends on SND
- select SND_AD1848_LIB
- help
- Say Y here to include support for Aztech Sound Galaxy
- soundcards.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-sgalaxy.
-
config SND_SSCAPE
- tristate "Ensoniq SoundScape PnP driver"
- depends on SND
- select SND_HWDEP
+ tristate "Ensoniq SoundScape driver"
select SND_MPU401_UART
- select SND_CS4231_LIB
+ select SND_WSS_LIB
+ select FW_LOADER
help
- Say Y here to include support for Ensoniq SoundScape PnP
- soundcards.
+ Say Y here to include support for Ensoniq SoundScape
+ and Ensoniq OEM soundcards.
+
+ The PCM audio is supported on SoundScape Classic, Elite, PnP
+ and VIVO cards. The supported OEM cards are SPEA Media FX and
+ Reveal SC-600.
+ The MIDI support is very experimental and requires binary
+ firmware files called "scope.cod" and "sndscape.co?" where the
+ ? is digit 0, 1, 2, 3 or 4. The firmware files can be found
+ in DOS or Windows driver packages. One has to put the firmware
+ files into the /lib/firmware directory.
To compile this driver as a module, choose M here: the module
will be called 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
+ select SND_WSS_LIB
help
Say Y here to include support for Turtle Beach Maui, Tropez
and Tropez+ soundcards based on the Wavefront chip.
@@ -376,4 +423,36 @@ config SND_WAVEFRONT
To compile this driver as a module, choose M here: the module
will be called snd-wavefront.
-endmenu
+config SND_MSND_PINNACLE
+ tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
+ depends on X86
+ select FW_LOADER
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say Y to include support for Turtle Beach MultiSound Pinnacle/
+ Fiji soundcards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-msnd-pinnacle.
+
+config SND_MSND_CLASSIC
+ tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
+ depends on X86
+ select FW_LOADER
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+ Monterey (not for the Pinnacle or Fiji).
+
+ See <file:Documentation/sound/oss/MultiSound> for important information
+ about this driver. Note that it has been discontinued, but the
+ Voyetra Turtle Beach knowledge base entry for it is still available
+ at <http://www.turtlebeach.com/site/kb_ftp/790.asp>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-msnd-classic.
+
+endif # SND_ISA
+
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index 05724eb7bfe..9a15f1497b1 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -1,26 +1,28 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
+snd-adlib-objs := adlib.o
snd-als100-objs := als100.o
snd-azt2320-objs := azt2320.o
+snd-cmi8328-objs := cmi8328.o
snd-cmi8330-objs := cmi8330.o
-snd-dt019x-objs := dt019x.o
snd-es18xx-objs := es18xx.o
snd-opl3sa2-objs := opl3sa2.o
-snd-sgalaxy-objs := sgalaxy.o
+snd-sc6000-objs := sc6000.o
snd-sscape-objs := sscape.o
# Toplevel Module Dependency
+obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
obj-$(CONFIG_SND_ALS100) += snd-als100.o
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
+obj-$(CONFIG_SND_CMI8328) += snd-cmi8328.o
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
-obj-$(CONFIG_SND_DT019X) += snd-dt019x.o
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
-obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
+obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \
- sb/ wavefront/
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
+ sb/ wavefront/ wss/
diff --git a/sound/isa/ad1816a/Makefile b/sound/isa/ad1816a/Makefile
index 90e00e842e4..487ab23860e 100644
--- a/sound/isa/ad1816a/Makefile
+++ b/sound/isa/ad1816a/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
snd-ad1816a-objs := ad1816a.o ad1816a_lib.o
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 7051f7798ed..f481a41e027 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -18,12 +18,11 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/ad1816a.h>
@@ -45,7 +44,7 @@ MODULE_SUPPORTED_DEVICE("{{Highscreen,Sound-Boostar 16 3D},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 1-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
@@ -61,28 +60,9 @@ module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for ad1816a based soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for ad1816a driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ad1816a driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for ad1816a driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for ad1816a driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ad1816a driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver.");
-module_param_array(dma2, int, NULL, 0444);
-MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver.");
module_param_array(clockfreq, int, NULL, 0444);
MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
-struct snd_card_ad1816a {
- struct pnp_dev *dev;
- struct pnp_dev *devmpu;
-};
-
static struct pnp_card_device_id snd_ad1816a_pnpids[] = {
/* Analog Devices AD1815 */
{ .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } },
@@ -98,8 +78,10 @@ static struct pnp_card_device_id snd_ad1816a_pnpids[] = {
{ .id = "MDK1605", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
/* Shark Predator ISA - added by Ken Arromdee */
{ .id = "SMM7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
- /* Analog Devices AD1816A - Terratec AudioSystem EWS64S */
+ /* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */
{ .id = "TER1112", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
+ /* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */
+ { .id = "TER1112", .devs = { { .id = "TER1100" }, { .id = "TER1101" } } },
/* Analog Devices AD1816A - Terratec Base 64 */
{ .id = "TER1411", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
/* end */
@@ -112,45 +94,19 @@ MODULE_DEVICE_TABLE(pnp_card, snd_ad1816a_pnpids);
#define DRIVER_NAME "snd-card-ad1816a"
-static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
int err;
- acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->dev == NULL) {
- kfree(cfg);
- return -EBUSY;
- }
- acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
- if (acard->devmpu == NULL) {
- kfree(cfg);
+ pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+ if (pdev == NULL)
return -EBUSY;
- }
- pdev = acard->dev;
- pnp_init_resource_table(cfg);
-
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[2], port[dev], 16);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
- if (dma1[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
- if (dma2[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
printk(KERN_ERR PFX "AUDIO PnP configure failure\n");
- kfree(cfg);
return -EBUSY;
}
@@ -160,55 +116,51 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- pdev = acard->devmpu;
- pnp_init_resource_table(cfg);
-
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
- if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
+ pdev = pnp_request_card_device(card, id->devs[1].id, NULL);
+ if (pdev == NULL) {
+ mpu_port[dev] = -1;
+ snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
+ return 0;
+ }
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
printk(KERN_ERR PFX "MPU401 PnP configure failure\n");
mpu_port[dev] = -1;
- acard->devmpu = NULL;
} else {
mpu_port[dev] = pnp_port_start(pdev, 0);
mpu_irq[dev] = pnp_irq(pdev, 0);
}
- kfree(cfg);
return 0;
}
-static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
int error;
struct snd_card *card;
- struct snd_card_ad1816a *acard;
struct snd_ad1816a *chip;
struct snd_opl3 *opl3;
+ struct snd_timer *timer;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_ad1816a))) == NULL)
- return -ENOMEM;
- acard = (struct snd_card_ad1816a *)card->private_data;
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_ad1816a), &card);
+ if (error < 0)
+ return error;
+ chip = card->private_data;
- if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
+ if ((error = snd_card_ad1816a_pnp(dev, pcard, pid))) {
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((error = snd_ad1816a_create(card, port[dev],
irq[dev],
dma1[dev],
dma2[dev],
- &chip)) < 0) {
+ chip)) < 0) {
snd_card_free(card);
return error;
}
@@ -230,9 +182,15 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
return error;
}
+ error = snd_ad1816a_timer(chip, 0, &timer);
+ if (error < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
if (mpu_port[dev] > 0) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
- mpu_port[dev], 0, mpu_irq[dev], SA_INTERRUPT,
+ mpu_port[dev], 0, mpu_irq[dev],
NULL) < 0)
printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpu_port[dev]);
}
@@ -243,11 +201,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
OPL3_HW_AUTO, 0, &opl3) < 0) {
printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx.\n", fm_port[dev], fm_port[dev] + 2);
} else {
- if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
- snd_card_free(card);
- return error;
- }
- if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
+ error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (error < 0) {
snd_card_free(card);
return error;
}
@@ -262,8 +217,10 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
return 0;
}
-static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static unsigned int ad1816a_devices;
+
+static int snd_ad1816a_pnp_detect(struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
static int dev;
int res;
@@ -275,32 +232,60 @@ static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card,
if (res < 0)
return res;
dev++;
+ ad1816a_devices++;
return 0;
}
return -ENODEV;
}
-static void __devexit snd_ad1816a_pnp_remove(struct pnp_card_link * pcard)
+static void snd_ad1816a_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
}
+#ifdef CONFIG_PM
+static int snd_ad1816a_pnp_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_ad1816a_suspend(card->private_data);
+ return 0;
+}
+
+static int snd_ad1816a_pnp_resume(struct pnp_card_link *pcard)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+ snd_ad1816a_resume(card->private_data);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
static struct pnp_card_driver ad1816a_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "ad1816a",
.id_table = snd_ad1816a_pnpids,
.probe = snd_ad1816a_pnp_detect,
- .remove = __devexit_p(snd_ad1816a_pnp_remove),
- /* FIXME: suspend/resume */
+ .remove = snd_ad1816a_pnp_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_ad1816a_pnp_suspend,
+ .resume = snd_ad1816a_pnp_resume,
+#endif
};
static int __init alsa_card_ad1816a_init(void)
{
- int cards;
+ int err;
+
+ err = pnp_register_card_driver(&ad1816a_pnpc_driver);
+ if (err)
+ return err;
- cards = pnp_register_card_driver(&ad1816a_pnpc_driver);
- if (cards <= 0) {
+ if (!ad1816a_devices) {
pnp_unregister_card_driver(&ad1816a_pnpc_driver);
#ifdef MODULE
printk(KERN_ERR "no AD1816A based soundcards found.\n");
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index ac0d808fff5..f0fd98e695e 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -1,4 +1,3 @@
-
/*
ad1816a.c - lowlevel code for Analog Devices AD1816A chip.
Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
@@ -18,13 +17,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h>
+#include <sound/tlv.h>
#include <sound/ad1816a.h>
#include <asm/io.h>
@@ -38,7 +37,7 @@ static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
if (inb(AD1816A_REG(AD1816A_CHIP_STATUS)) & AD1816A_READY)
return 0;
- snd_printk("chip busy.\n");
+ snd_printk(KERN_WARNING "chip busy.\n");
return -EBUSY;
}
@@ -175,7 +174,7 @@ static void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode)
static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
- int channel, int cmd)
+ int channel, int cmd, int iscapture)
{
int error = 0;
@@ -184,16 +183,20 @@ static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
case SNDRV_PCM_TRIGGER_STOP:
spin_lock(&chip->lock);
cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00;
- if (what & AD1816A_PLAYBACK_ENABLE)
+ /* if (what & AD1816A_PLAYBACK_ENABLE) */
+ /* That is not valid, because playback and capture enable
+ * are the same bit pattern, just to different addresses
+ */
+ if (! iscapture)
snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
AD1816A_PLAYBACK_ENABLE, cmd);
- if (what & AD1816A_CAPTURE_ENABLE)
+ else
snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
AD1816A_CAPTURE_ENABLE, cmd);
spin_unlock(&chip->lock);
break;
default:
- snd_printk("invalid trigger mode 0x%x.\n", what);
+ snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
error = -EINVAL;
}
@@ -204,14 +207,14 @@ static int snd_ad1816a_playback_trigger(struct snd_pcm_substream *substream, int
{
struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
return snd_ad1816a_trigger(chip, AD1816A_PLAYBACK_ENABLE,
- SNDRV_PCM_STREAM_PLAYBACK, cmd);
+ SNDRV_PCM_STREAM_PLAYBACK, cmd, 0);
}
static int snd_ad1816a_capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
return snd_ad1816a_trigger(chip, AD1816A_CAPTURE_ENABLE,
- SNDRV_PCM_STREAM_CAPTURE, cmd);
+ SNDRV_PCM_STREAM_CAPTURE, cmd, 1);
}
static int snd_ad1816a_hw_params(struct snd_pcm_substream *substream,
@@ -311,7 +314,7 @@ static snd_pcm_uframes_t snd_ad1816a_capture_pointer(struct snd_pcm_substream *s
}
-static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id)
{
struct snd_ad1816a *chip = dev_id;
unsigned char status;
@@ -374,7 +377,6 @@ static struct snd_pcm_hardware snd_ad1816a_capture = {
.fifo_size = 0,
};
-#if 0 /* not used now */
static int snd_ad1816a_timer_close(struct snd_timer *timer)
{
struct snd_ad1816a *chip = snd_timer_chip(timer);
@@ -391,7 +393,8 @@ static int snd_ad1816a_timer_open(struct snd_timer *timer)
static unsigned long snd_ad1816a_timer_resolution(struct snd_timer *timer)
{
- snd_assert(timer != NULL, return 0);
+ if (snd_BUG_ON(!timer))
+ return 0;
return 10000;
}
@@ -438,8 +441,6 @@ static struct snd_timer_hardware snd_ad1816a_timer_table = {
.start = snd_ad1816a_timer_start,
.stop = snd_ad1816a_timer_stop,
};
-#endif /* not used now */
-
static int snd_ad1816a_playback_open(struct snd_pcm_substream *substream)
{
@@ -449,7 +450,6 @@ static int snd_ad1816a_playback_open(struct snd_pcm_substream *substream)
if ((error = snd_ad1816a_open(chip, AD1816A_MODE_PLAYBACK)) < 0)
return error;
- snd_pcm_set_sync(substream);
runtime->hw = snd_ad1816a_playback;
snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
@@ -465,7 +465,6 @@ static int snd_ad1816a_capture_open(struct snd_pcm_substream *substream)
if ((error = snd_ad1816a_open(chip, AD1816A_MODE_CAPTURE)) < 0)
return error;
- snd_pcm_set_sync(substream);
runtime->hw = snd_ad1816a_capture;
snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
@@ -492,7 +491,7 @@ static int snd_ad1816a_capture_close(struct snd_pcm_substream *substream)
}
-static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
+static void snd_ad1816a_init(struct snd_ad1816a *chip)
{
unsigned long flags;
@@ -512,7 +511,33 @@ static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
spin_unlock_irqrestore(&chip->lock, flags);
}
-static int __devinit snd_ad1816a_probe(struct snd_ad1816a *chip)
+#ifdef CONFIG_PM
+void snd_ad1816a_suspend(struct snd_ad1816a *chip)
+{
+ int reg;
+ unsigned long flags;
+
+ snd_pcm_suspend_all(chip->pcm);
+ spin_lock_irqsave(&chip->lock, flags);
+ for (reg = 0; reg < 48; reg++)
+ chip->image[reg] = snd_ad1816a_read(chip, reg);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+void snd_ad1816a_resume(struct snd_ad1816a *chip)
+{
+ int reg;
+ unsigned long flags;
+
+ snd_ad1816a_init(chip);
+ spin_lock_irqsave(&chip->lock, flags);
+ for (reg = 0; reg < 48; reg++)
+ snd_ad1816a_write(chip, reg, chip->image[reg]);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+#endif
+
+static int snd_ad1816a_probe(struct snd_ad1816a *chip)
{
unsigned long flags;
@@ -549,7 +574,6 @@ static int snd_ad1816a_free(struct snd_ad1816a *chip)
snd_dma_disable(chip->dma2);
free_dma(chip->dma2);
}
- kfree(chip);
return 0;
}
@@ -559,34 +583,28 @@ static int snd_ad1816a_dev_free(struct snd_device *device)
return snd_ad1816a_free(chip);
}
-static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
+static const char *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
{
switch (chip->hardware) {
case AD1816A_HW_AD1816A: return "AD1816A";
case AD1816A_HW_AD1815: return "AD1815";
case AD1816A_HW_AD18MAX10: return "AD18max10";
default:
- snd_printk("Unknown chip version %d:%d.\n",
+ snd_printk(KERN_WARNING "Unknown chip version %d:%d.\n",
chip->version, chip->hardware);
return "AD1816A - unknown";
}
}
-int __devinit snd_ad1816a_create(struct snd_card *card,
- unsigned long port, int irq, int dma1, int dma2,
- struct snd_ad1816a **rchip)
+int snd_ad1816a_create(struct snd_card *card,
+ unsigned long port, int irq, int dma1, int dma2,
+ struct snd_ad1816a *chip)
{
static struct snd_device_ops ops = {
.dev_free = snd_ad1816a_dev_free,
};
int error;
- struct snd_ad1816a *chip;
- *rchip = NULL;
-
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
chip->irq = -1;
chip->dma1 = -1;
chip->dma2 = -1;
@@ -596,7 +614,7 @@ int __devinit snd_ad1816a_create(struct snd_card *card,
snd_ad1816a_free(chip);
return -EBUSY;
}
- if (request_irq(irq, snd_ad1816a_interrupt, SA_INTERRUPT, "AD1816A", (void *) chip)) {
+ if (request_irq(irq, snd_ad1816a_interrupt, 0, "AD1816A", (void *) chip)) {
snd_printk(KERN_ERR "ad1816a: can't grab IRQ %d\n", irq);
snd_ad1816a_free(chip);
return -EBUSY;
@@ -632,7 +650,6 @@ int __devinit snd_ad1816a_create(struct snd_card *card,
return error;
}
- *rchip = chip;
return 0;
}
@@ -658,7 +675,7 @@ static struct snd_pcm_ops snd_ad1816a_capture_ops = {
.pointer = snd_ad1816a_capture_pointer,
};
-int __devinit snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm)
+int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm)
{
int error;
struct snd_pcm *pcm;
@@ -685,8 +702,8 @@ int __devinit snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_p
return 0;
}
-#if 0 /* not used now */
-int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd_timer **rtimer)
+int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
+ struct snd_timer **rtimer)
{
struct snd_timer *timer;
struct snd_timer_id tid;
@@ -707,7 +724,6 @@ int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd
*rtimer = timer;
return 0;
}
-#endif /* not used now */
/*
*
@@ -762,6 +778,13 @@ static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
return change;
}
+#define AD1816A_SINGLE_TLV(xname, reg, shift, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .name = xname, .info = snd_ad1816a_info_single, \
+ .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
+ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
+ .tlv = { .p = (xtlv) } }
#define AD1816A_SINGLE(xname, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \
.get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
@@ -819,6 +842,14 @@ static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
return change;
}
+#define AD1816A_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .name = xname, .info = snd_ad1816a_info_double, \
+ .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
+ .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \
+ .tlv = { .p = (xtlv) } }
+
#define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \
.get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
@@ -887,28 +918,44 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
return change;
}
-static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
+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[] = {
AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
-AD1816A_DOUBLE("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1),
+AD1816A_DOUBLE_TLV("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1,
+ db_scale_5bit),
AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1),
-AD1816A_DOUBLE("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1),
+AD1816A_DOUBLE_TLV("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1,
+ db_scale_6bit),
AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1),
-AD1816A_DOUBLE("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1),
+AD1816A_DOUBLE_TLV("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1,
+ db_scale_5bit_12db_max),
AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1),
-AD1816A_DOUBLE("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1),
+AD1816A_DOUBLE_TLV("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1,
+ db_scale_5bit_12db_max),
AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1),
-AD1816A_DOUBLE("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1),
+AD1816A_DOUBLE_TLV("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1,
+ db_scale_5bit_12db_max),
AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1),
-AD1816A_DOUBLE("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1),
+AD1816A_DOUBLE_TLV("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1,
+ db_scale_6bit),
AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1),
-AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1),
+AD1816A_SINGLE_TLV("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1,
+ db_scale_5bit_12db_max),
AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0),
AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1),
-AD1816A_DOUBLE("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1),
+AD1816A_DOUBLE_TLV("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1,
+ db_scale_5bit_12db_max),
AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1),
-AD1816A_SINGLE("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1),
+AD1816A_SINGLE_TLV("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1,
+ db_scale_4bit),
AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1),
-AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1),
+AD1816A_SINGLE_TLV("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1,
+ db_scale_5bit),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
@@ -917,18 +964,20 @@ AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1),
.put = snd_ad1816a_put_mux,
},
AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1),
-AD1816A_DOUBLE("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0),
+AD1816A_DOUBLE_TLV("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0,
+ db_scale_rec_gain),
AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1),
AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0),
};
-int __devinit snd_ad1816a_mixer(struct snd_ad1816a *chip)
+int snd_ad1816a_mixer(struct snd_ad1816a *chip)
{
struct snd_card *card;
unsigned int idx;
int err;
- snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!chip || !chip->card))
+ return -EINVAL;
card = chip->card;
diff --git a/sound/isa/ad1848/Makefile b/sound/isa/ad1848/Makefile
index 45d59998aa6..3d6dea3ff92 100644
--- a/sound/isa/ad1848/Makefile
+++ b/sound/isa/ad1848/Makefile
@@ -1,15 +1,10 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ad1848-lib-objs := ad1848_lib.o
snd-ad1848-objs := ad1848.o
# Toplevel Module Dependency
-obj-$(CONFIG_SND_CMI8330) += snd-ad1848-lib.o
-obj-$(CONFIG_SND_SGALAXY) += snd-ad1848-lib.o
-obj-$(CONFIG_SND_AD1848) += snd-ad1848.o snd-ad1848-lib.o
-obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-ad1848-lib.o
+obj-$(CONFIG_SND_AD1848) += snd-ad1848.o
-obj-m := $(sort $(obj-m))
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index e091bbeffd2..093f22a464d 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -1,8 +1,8 @@
/*
* Generic driver for AD1848/AD1847/CS4248 chips (0.1 Alpha)
* Copyright (c) by Tugrul Galatali <galatalt@stuy.edu>,
- * Jaroslav Kysela <perex@suse.cz>
- * Based on card-4232.c by Jaroslav Kysela <perex@suse.cz>
+ * Jaroslav Kysela <perex@perex.cz>
+ * Based on card-4232.c by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -21,19 +21,21 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
#include <sound/initval.h>
-MODULE_AUTHOR("Tugrul Galatali <galatalt@stuy.edu>, Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("AD1848/AD1847/CS4248");
+#define CRD_NAME "Generic AD1848/AD1847/CS4248"
+#define DEV_NAME "ad1848"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Tugrul Galatali <galatalt@stuy.edu>, Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1848},"
"{Analog Devices,AD1847},"
@@ -41,113 +43,114 @@ MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1848},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
-static int thinkpad[SNDRV_CARDS]; /* Thinkpad special case */
+static bool thinkpad[SNDRV_CARDS]; /* Thinkpad special case */
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for AD1848 soundcard.");
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for AD1848 soundcard.");
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable AD1848 soundcard.");
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for AD1848 driver.");
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for AD1848 driver.");
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for AD1848 driver.");
+MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver.");
module_param_array(thinkpad, bool, NULL, 0444);
MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 360/750/755 series.");
-static struct platform_device *devices[SNDRV_CARDS];
+static int snd_ad1848_match(struct device *dev, unsigned int n)
+{
+ if (!enable[n])
+ return 0;
+ if (port[n] == SNDRV_AUTO_PORT) {
+ dev_err(dev, "please specify port\n");
+ return 0;
+ }
+ if (irq[n] == SNDRV_AUTO_IRQ) {
+ dev_err(dev, "please specify irq\n");
+ return 0;
+ }
+ if (dma1[n] == SNDRV_AUTO_DMA) {
+ dev_err(dev, "please specify dma1\n");
+ return 0;
+ }
+ return 1;
+}
-static int __init snd_ad1848_probe(struct platform_device *pdev)
+static int snd_ad1848_probe(struct device *dev, unsigned int n)
{
- int dev = pdev->id;
struct snd_card *card;
- struct snd_ad1848 *chip;
+ struct snd_wss *chip;
struct snd_pcm *pcm;
- int err;
+ int error;
- if (port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "ad1848: specify port\n");
- return -EINVAL;
- }
- if (irq[dev] == SNDRV_AUTO_IRQ) {
- snd_printk(KERN_ERR "ad1848: specify irq\n");
- return -EINVAL;
- }
- if (dma1[dev] == SNDRV_AUTO_DMA) {
- snd_printk(KERN_ERR "ad1848: specify dma1\n");
- return -EINVAL;
- }
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1,
+ thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT,
+ 0, &chip);
+ if (error < 0)
+ goto out;
- if ((err = snd_ad1848_create(card, port[dev],
- irq[dev],
- dma1[dev],
- thinkpad[dev] ? AD1848_HW_THINKPAD : AD1848_HW_DETECT,
- &chip)) < 0)
- goto _err;
card->private_data = chip;
- if ((err = snd_ad1848_pcm(chip, 0, &pcm)) < 0)
- goto _err;
+ error = snd_wss_pcm(chip, 0, &pcm);
+ if (error < 0)
+ goto out;
- if ((err = snd_ad1848_mixer(chip)) < 0)
- goto _err;
+ error = snd_wss_mixer(chip);
+ if (error < 0)
+ goto out;
strcpy(card->driver, "AD1848");
strcpy(card->shortname, pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
- pcm->name, chip->port, irq[dev], dma1[dev]);
-
- if (thinkpad[dev])
+ pcm->name, chip->port, irq[n], dma1[n]);
+ if (thinkpad[n])
strcat(card->longname, " [Thinkpad]");
- snd_card_set_dev(card, &pdev->dev);
-
- if ((err = snd_card_register(card)) < 0)
- goto _err;
+ error = snd_card_register(card);
+ if (error < 0)
+ goto out;
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(dev, card);
return 0;
- _err:
- snd_card_free(card);
- return err;
+out: snd_card_free(card);
+ return error;
}
-static int __devexit snd_ad1848_remove(struct platform_device *devptr)
+static int snd_ad1848_remove(struct device *dev, unsigned int n)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(dev));
return 0;
}
#ifdef CONFIG_PM
-static int snd_ad1848_suspend(struct platform_device *pdev, pm_message_t state)
+static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t state)
{
- struct snd_card *card = platform_get_drvdata(pdev);
- struct snd_ad1848 *chip = card->private_data;
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_wss *chip = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
chip->suspend(chip);
return 0;
}
-static int snd_ad1848_resume(struct platform_device *pdev)
+static int snd_ad1848_resume(struct device *dev, unsigned int n)
{
- struct snd_card *card = platform_get_drvdata(pdev);
- struct snd_ad1848 *chip = card->private_data;
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_wss *chip = card->private_data;
chip->resume(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -155,67 +158,28 @@ static int snd_ad1848_resume(struct platform_device *pdev)
}
#endif
-#define SND_AD1848_DRIVER "snd_ad1848"
-
-static struct platform_driver snd_ad1848_driver = {
+static struct isa_driver snd_ad1848_driver = {
+ .match = snd_ad1848_match,
.probe = snd_ad1848_probe,
- .remove = __devexit_p(snd_ad1848_remove),
+ .remove = snd_ad1848_remove,
#ifdef CONFIG_PM
.suspend = snd_ad1848_suspend,
.resume = snd_ad1848_resume,
#endif
.driver = {
- .name = SND_AD1848_DRIVER
- },
+ .name = DEV_NAME
+ }
};
-static void __init_or_module snd_ad1848_unregister_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_ad1848_driver);
-}
-
static int __init alsa_card_ad1848_init(void)
{
- int i, cards, err;
-
- err = platform_driver_register(&snd_ad1848_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(SND_AD1848_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
- }
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR "AD1848 soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_ad1848_unregister_all();
- return err;
+ return isa_register_driver(&snd_ad1848_driver, SNDRV_CARDS);
}
static void __exit alsa_card_ad1848_exit(void)
{
- snd_ad1848_unregister_all();
+ isa_unregister_driver(&snd_ad1848_driver);
}
-module_init(alsa_card_ad1848_init)
-module_exit(alsa_card_ad1848_exit)
+module_init(alsa_card_ad1848_init);
+module_exit(alsa_card_ad1848_exit);
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
deleted file mode 100644
index b78530d7ea9..00000000000
--- a/sound/isa/ad1848/ad1848_lib.c
+++ /dev/null
@@ -1,1271 +0,0 @@
-/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- * Routines for control of AD1848/AD1847/CS4248
- *
- *
- * 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
- *
- */
-
-#define SNDRV_MAIN_OBJECT_FILE
-#include <sound/driver.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <sound/core.h>
-#include <sound/ad1848.h>
-#include <sound/control.h>
-#include <sound/pcm_params.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248");
-MODULE_LICENSE("GPL");
-
-#if 0
-#define SNDRV_DEBUG_MCE
-#endif
-
-/*
- * Some variables
- */
-
-static unsigned char freq_bits[14] = {
- /* 5510 */ 0x00 | AD1848_XTAL2,
- /* 6620 */ 0x0E | AD1848_XTAL2,
- /* 8000 */ 0x00 | AD1848_XTAL1,
- /* 9600 */ 0x0E | AD1848_XTAL1,
- /* 11025 */ 0x02 | AD1848_XTAL2,
- /* 16000 */ 0x02 | AD1848_XTAL1,
- /* 18900 */ 0x04 | AD1848_XTAL2,
- /* 22050 */ 0x06 | AD1848_XTAL2,
- /* 27042 */ 0x04 | AD1848_XTAL1,
- /* 32000 */ 0x06 | AD1848_XTAL1,
- /* 33075 */ 0x0C | AD1848_XTAL2,
- /* 37800 */ 0x08 | AD1848_XTAL2,
- /* 44100 */ 0x0A | AD1848_XTAL2,
- /* 48000 */ 0x0C | AD1848_XTAL1
-};
-
-static unsigned int rates[14] = {
- 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
- 27042, 32000, 33075, 37800, 44100, 48000
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
- .count = 14,
- .list = rates,
- .mask = 0,
-};
-
-static unsigned char snd_ad1848_original_image[16] =
-{
- 0x00, /* 00 - lic */
- 0x00, /* 01 - ric */
- 0x9f, /* 02 - la1ic */
- 0x9f, /* 03 - ra1ic */
- 0x9f, /* 04 - la2ic */
- 0x9f, /* 05 - ra2ic */
- 0xbf, /* 06 - loc */
- 0xbf, /* 07 - roc */
- 0x20, /* 08 - dfr */
- AD1848_AUTOCALIB, /* 09 - ic */
- 0x00, /* 0a - pc */
- 0x00, /* 0b - ti */
- 0x00, /* 0c - mi */
- 0x00, /* 0d - lbc */
- 0x00, /* 0e - dru */
- 0x00, /* 0f - drl */
-};
-
-/*
- * Basic I/O functions
- */
-
-void snd_ad1848_out(struct snd_ad1848 *chip,
- unsigned char reg,
- unsigned char value)
-{
- int timeout;
-
- for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
- udelay(100);
-#ifdef CONFIG_SND_DEBUG
- if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
- snd_printk(KERN_WARNING "auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
- outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
- outb(chip->image[reg] = value, AD1848P(chip, REG));
- mb();
-#if 0
- printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);
-#endif
-}
-
-static void snd_ad1848_dout(struct snd_ad1848 *chip,
- unsigned char reg, unsigned char value)
-{
- int timeout;
-
- for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
- udelay(100);
- outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
- outb(value, AD1848P(chip, REG));
- mb();
-}
-
-static unsigned char snd_ad1848_in(struct snd_ad1848 *chip, unsigned char reg)
-{
- int timeout;
-
- for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
- udelay(100);
-#ifdef CONFIG_SND_DEBUG
- if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
- snd_printk(KERN_WARNING "auto calibration time out - reg = 0x%x\n", reg);
-#endif
- outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));
- mb();
- return inb(AD1848P(chip, REG));
-}
-
-#if 0
-
-static void snd_ad1848_debug(struct snd_ad1848 *chip)
-{
- printk("AD1848 REGS: INDEX = 0x%02x ", inb(AD1848P(chip, REGSEL)));
- printk(" STATUS = 0x%02x\n", inb(AD1848P(chip, STATUS)));
- printk(" 0x00: left input = 0x%02x ", snd_ad1848_in(chip, 0x00));
- printk(" 0x08: playback format = 0x%02x\n", snd_ad1848_in(chip, 0x08));
- printk(" 0x01: right input = 0x%02x ", snd_ad1848_in(chip, 0x01));
- printk(" 0x09: iface (CFIG 1) = 0x%02x\n", snd_ad1848_in(chip, 0x09));
- printk(" 0x02: AUXA left = 0x%02x ", snd_ad1848_in(chip, 0x02));
- printk(" 0x0a: pin control = 0x%02x\n", snd_ad1848_in(chip, 0x0a));
- printk(" 0x03: AUXA right = 0x%02x ", snd_ad1848_in(chip, 0x03));
- printk(" 0x0b: init & status = 0x%02x\n", snd_ad1848_in(chip, 0x0b));
- printk(" 0x04: AUXB left = 0x%02x ", snd_ad1848_in(chip, 0x04));
- printk(" 0x0c: revision & mode = 0x%02x\n", snd_ad1848_in(chip, 0x0c));
- printk(" 0x05: AUXB right = 0x%02x ", snd_ad1848_in(chip, 0x05));
- printk(" 0x0d: loopback = 0x%02x\n", snd_ad1848_in(chip, 0x0d));
- printk(" 0x06: left output = 0x%02x ", snd_ad1848_in(chip, 0x06));
- printk(" 0x0e: data upr count = 0x%02x\n", snd_ad1848_in(chip, 0x0e));
- printk(" 0x07: right output = 0x%02x ", snd_ad1848_in(chip, 0x07));
- printk(" 0x0f: data lwr count = 0x%02x\n", snd_ad1848_in(chip, 0x0f));
-}
-
-#endif
-
-/*
- * AD1848 detection / MCE routines
- */
-
-static void snd_ad1848_mce_up(struct snd_ad1848 *chip)
-{
- unsigned long flags;
- int timeout;
-
- for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
- udelay(100);
-#ifdef CONFIG_SND_DEBUG
- if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
- snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n");
-#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->mce_bit |= AD1848_MCE;
- timeout = inb(AD1848P(chip, REGSEL));
- if (timeout == 0x80)
- snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
- if (!(timeout & AD1848_MCE))
- outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
-{
- unsigned long flags;
- int timeout;
- signed long time;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (timeout = 5; timeout > 0; timeout--)
- inb(AD1848P(chip, REGSEL));
- /* end of cleanup sequence */
- for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
- udelay(100);
-#if 0
- printk("(1) timeout = %i\n", timeout);
-#endif
-#ifdef CONFIG_SND_DEBUG
- if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
- snd_printk(KERN_WARNING "mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL));
-#endif
- chip->mce_bit &= ~AD1848_MCE;
- timeout = inb(AD1848P(chip, REGSEL));
- outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL));
- if (timeout == 0x80)
- snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
- if ((timeout & AD1848_MCE) == 0) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return;
- }
- /* calibration process */
-
- for (timeout = 500; timeout > 0 && (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0; timeout--);
- if ((snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0) {
- snd_printd("mce_down - auto calibration time out (1)\n");
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return;
- }
-#if 0
- printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);
-#endif
- time = HZ / 4;
- while (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (time <= 0) {
- snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n");
- return;
- }
- time = schedule_timeout_interruptible(time);
- spin_lock_irqsave(&chip->reg_lock, flags);
- }
-#if 0
- printk("(3) jiffies = %li\n", jiffies);
-#endif
- time = HZ / 10;
- while (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (time <= 0) {
- snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
- return;
- }
- time = schedule_timeout_interruptible(time);
- spin_lock_irqsave(&chip->reg_lock, flags);
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-#if 0
- printk("(4) jiffies = %li\n", jiffies);
- snd_printk("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL)));
-#endif
-}
-
-static unsigned int snd_ad1848_get_count(unsigned char format,
- unsigned int size)
-{
- switch (format & 0xe0) {
- case AD1848_LINEAR_16:
- size >>= 1;
- break;
- }
- if (format & AD1848_STEREO)
- size >>= 1;
- return size;
-}
-
-static int snd_ad1848_trigger(struct snd_ad1848 *chip, unsigned char what,
- int channel, int cmd)
-{
- int result = 0;
-
-#if 0
- printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(AD1848P(card, STATUS)));
-#endif
- spin_lock(&chip->reg_lock);
- if (cmd == SNDRV_PCM_TRIGGER_START) {
- if (chip->image[AD1848_IFACE_CTRL] & what) {
- spin_unlock(&chip->reg_lock);
- return 0;
- }
- snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] |= what);
- chip->mode |= AD1848_MODE_RUNNING;
- } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- if (!(chip->image[AD1848_IFACE_CTRL] & what)) {
- spin_unlock(&chip->reg_lock);
- return 0;
- }
- snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] &= ~what);
- chip->mode &= ~AD1848_MODE_RUNNING;
- } else {
- result = -EINVAL;
- }
- spin_unlock(&chip->reg_lock);
- return result;
-}
-
-/*
- * CODEC I/O
- */
-
-static unsigned char snd_ad1848_get_rate(unsigned int rate)
-{
- int i;
-
- for (i = 0; i < 14; i++)
- if (rate == rates[i])
- return freq_bits[i];
- snd_BUG();
- return freq_bits[13];
-}
-
-static int snd_ad1848_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-
-static unsigned char snd_ad1848_get_format(int format, int channels)
-{
- unsigned char rformat;
-
- rformat = AD1848_LINEAR_8;
- switch (format) {
- case SNDRV_PCM_FORMAT_A_LAW: rformat = AD1848_ALAW_8; break;
- case SNDRV_PCM_FORMAT_MU_LAW: rformat = AD1848_ULAW_8; break;
- case SNDRV_PCM_FORMAT_S16_LE: rformat = AD1848_LINEAR_16; break;
- }
- if (channels > 1)
- rformat |= AD1848_STEREO;
-#if 0
- snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
-#endif
- return rformat;
-}
-
-static void snd_ad1848_calibrate_mute(struct snd_ad1848 *chip, int mute)
-{
- unsigned long flags;
-
- mute = mute ? 1 : 0;
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (chip->calibrate_mute == mute) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return;
- }
- if (!mute) {
- snd_ad1848_dout(chip, AD1848_LEFT_INPUT, chip->image[AD1848_LEFT_INPUT]);
- snd_ad1848_dout(chip, AD1848_RIGHT_INPUT, chip->image[AD1848_RIGHT_INPUT]);
- }
- snd_ad1848_dout(chip, AD1848_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_LEFT_INPUT]);
- snd_ad1848_dout(chip, AD1848_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_RIGHT_INPUT]);
- snd_ad1848_dout(chip, AD1848_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_LEFT_INPUT]);
- snd_ad1848_dout(chip, AD1848_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_RIGHT_INPUT]);
- snd_ad1848_dout(chip, AD1848_LEFT_OUTPUT, mute ? 0x80 : chip->image[AD1848_LEFT_OUTPUT]);
- snd_ad1848_dout(chip, AD1848_RIGHT_OUTPUT, mute ? 0x80 : chip->image[AD1848_RIGHT_OUTPUT]);
- chip->calibrate_mute = mute;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_ad1848_set_data_format(struct snd_ad1848 *chip, struct snd_pcm_hw_params *hw_params)
-{
- if (hw_params == NULL) {
- chip->image[AD1848_DATA_FORMAT] = 0x20;
- } else {
- chip->image[AD1848_DATA_FORMAT] =
- snd_ad1848_get_format(params_format(hw_params), params_channels(hw_params)) |
- snd_ad1848_get_rate(params_rate(hw_params));
- }
- // snd_printk(">>> pmode = 0x%x, dfr = 0x%x\n", pstr->mode, chip->image[AD1848_DATA_FORMAT]);
-}
-
-static int snd_ad1848_open(struct snd_ad1848 *chip, unsigned int mode)
-{
- unsigned long flags;
-
- down(&chip->open_mutex);
- if (chip->mode & AD1848_MODE_OPEN) {
- up(&chip->open_mutex);
- return -EAGAIN;
- }
- snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("open: (1)\n");
-#endif
- snd_ad1848_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO |
- AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO |
- AD1848_CALIB_MODE);
- chip->image[AD1848_IFACE_CTRL] |= AD1848_AUTOCALIB;
- snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("open: (2)\n");
-#endif
-
- snd_ad1848_set_data_format(chip, NULL);
-
- snd_ad1848_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_ad1848_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("open: (3)\n");
-#endif
-
- /* ok. now enable and ack CODEC IRQ */
- spin_lock_irqsave(&chip->reg_lock, flags);
- outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
- outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
- chip->image[AD1848_PIN_CTRL] |= AD1848_IRQ_ENABLE;
- snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- chip->mode = mode;
- up(&chip->open_mutex);
-
- return 0;
-}
-
-static void snd_ad1848_close(struct snd_ad1848 *chip)
-{
- unsigned long flags;
-
- down(&chip->open_mutex);
- if (!chip->mode) {
- up(&chip->open_mutex);
- return;
- }
- /* disable IRQ */
- spin_lock_irqsave(&chip->reg_lock, flags);
- outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
- outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
- chip->image[AD1848_PIN_CTRL] &= ~AD1848_IRQ_ENABLE;
- snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- /* now disable capture & playback */
-
- snd_ad1848_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO |
- AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO);
- snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_ad1848_mce_down(chip);
-
- /* clear IRQ again */
- spin_lock_irqsave(&chip->reg_lock, flags);
- outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
- outb(0, AD1848P(chip, STATUS)); /* clear IRQ */
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- chip->mode = 0;
- up(&chip->open_mutex);
-}
-
-/*
- * ok.. exported functions..
- */
-
-static int snd_ad1848_playback_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- return snd_ad1848_trigger(chip, AD1848_PLAYBACK_ENABLE, SNDRV_PCM_STREAM_PLAYBACK, cmd);
-}
-
-static int snd_ad1848_capture_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- return snd_ad1848_trigger(chip, AD1848_CAPTURE_ENABLE, SNDRV_PCM_STREAM_CAPTURE, cmd);
-}
-
-static int snd_ad1848_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- unsigned long flags;
- int err;
-
- if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
- return err;
- snd_ad1848_calibrate_mute(chip, 1);
- snd_ad1848_set_data_format(chip, hw_params);
- snd_ad1848_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_ad1848_mce_down(chip);
- snd_ad1848_calibrate_mute(chip, 0);
- return 0;
-}
-
-static int snd_ad1848_playback_hw_free(struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_ad1848_playback_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- unsigned int size = snd_pcm_lib_buffer_bytes(substream);
- unsigned int count = snd_pcm_lib_period_bytes(substream);
-
- chip->dma_size = size;
- chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO);
- snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
- count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1;
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count);
- snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
-}
-
-static int snd_ad1848_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- unsigned long flags;
- int err;
-
- if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
- return err;
- snd_ad1848_calibrate_mute(chip, 1);
- snd_ad1848_set_data_format(chip, hw_params);
- snd_ad1848_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_ad1848_mce_down(chip);
- snd_ad1848_calibrate_mute(chip, 0);
- return 0;
-}
-
-static int snd_ad1848_capture_hw_free(struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_ad1848_capture_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- unsigned int size = snd_pcm_lib_buffer_bytes(substream);
- unsigned int count = snd_pcm_lib_period_bytes(substream);
-
- chip->dma_size = size;
- chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO);
- snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
- count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1;
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count);
- snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
-}
-
-static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct snd_ad1848 *chip = dev_id;
-
- if ((chip->mode & AD1848_MODE_PLAY) && chip->playback_substream &&
- (chip->mode & AD1848_MODE_RUNNING))
- snd_pcm_period_elapsed(chip->playback_substream);
- if ((chip->mode & AD1848_MODE_CAPTURE) && chip->capture_substream &&
- (chip->mode & AD1848_MODE_RUNNING))
- snd_pcm_period_elapsed(chip->capture_substream);
- outb(0, AD1848P(chip, STATUS)); /* clear global interrupt bit */
- return IRQ_HANDLED;
-}
-
-static snd_pcm_uframes_t snd_ad1848_playback_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- size_t ptr;
-
- if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_PLAYBACK_ENABLE))
- return 0;
- ptr = snd_dma_pointer(chip->dma, chip->dma_size);
- return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_ad1848_capture_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- size_t ptr;
-
- if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_CAPTURE_ENABLE))
- return 0;
- ptr = snd_dma_pointer(chip->dma, chip->dma_size);
- return bytes_to_frames(substream->runtime, ptr);
-}
-
-/*
-
- */
-
-static void snd_ad1848_thinkpad_twiddle(struct snd_ad1848 *chip, int on) {
-
- int tmp;
-
- if (!chip->thinkpad_flag) return;
-
- outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
- tmp = inb(AD1848_THINKPAD_CTL_PORT2);
-
- if (on)
- /* turn it on */
- tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
- else
- /* turn it off */
- tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
-
- outb(tmp, AD1848_THINKPAD_CTL_PORT2);
-
-}
-
-#ifdef CONFIG_PM
-static void snd_ad1848_suspend(struct snd_ad1848 *chip)
-{
- snd_pcm_suspend_all(chip->pcm);
- if (chip->thinkpad_flag)
- snd_ad1848_thinkpad_twiddle(chip, 0);
-}
-
-static void snd_ad1848_resume(struct snd_ad1848 *chip)
-{
- int i;
-
- if (chip->thinkpad_flag)
- snd_ad1848_thinkpad_twiddle(chip, 1);
-
- /* clear any pendings IRQ */
- inb(AD1848P(chip, STATUS));
- outb(0, AD1848P(chip, STATUS));
- mb();
-
- snd_ad1848_mce_down(chip);
- for (i = 0; i < 16; i++)
- snd_ad1848_out(chip, i, chip->image[i]);
- snd_ad1848_mce_up(chip);
- snd_ad1848_mce_down(chip);
-}
-#endif /* CONFIG_PM */
-
-static int snd_ad1848_probe(struct snd_ad1848 * chip)
-{
- unsigned long flags;
- int i, id, rev, ad1847;
- unsigned char *ptr;
-
-#if 0
- snd_ad1848_debug(chip);
-#endif
- id = ad1847 = 0;
- for (i = 0; i < 1000; i++) {
- mb();
- if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
- udelay(500);
- else {
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00);
- snd_ad1848_out(chip, AD1848_LEFT_INPUT, 0xaa);
- snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45);
- rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT);
- if (rev == 0x65) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- id = 1;
- ad1847 = 1;
- break;
- }
- if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- id = 1;
- break;
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- }
- }
- if (id != 1)
- return -ENODEV; /* no valid device found */
- if (chip->hardware == AD1848_HW_DETECT) {
- if (ad1847) {
- chip->hardware = AD1848_HW_AD1847;
- } else {
- chip->hardware = AD1848_HW_AD1848;
- rev = snd_ad1848_in(chip, AD1848_MISC_INFO);
- if (rev & 0x80) {
- chip->hardware = AD1848_HW_CS4248;
- } else if ((rev & 0x0f) == 0x0a) {
- snd_ad1848_out(chip, AD1848_MISC_INFO, 0x40);
- for (i = 0; i < 16; ++i) {
- if (snd_ad1848_in(chip, i) != snd_ad1848_in(chip, i + 16)) {
- chip->hardware = AD1848_HW_CMI8330;
- break;
- }
- }
- snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00);
- }
- }
- }
- spin_lock_irqsave(&chip->reg_lock, flags);
- inb(AD1848P(chip, STATUS)); /* clear any pendings IRQ */
- outb(0, AD1848P(chip, STATUS));
- mb();
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- chip->image[AD1848_MISC_INFO] = 0x00;
- chip->image[AD1848_IFACE_CTRL] =
- (chip->image[AD1848_IFACE_CTRL] & ~AD1848_SINGLE_DMA) | AD1848_SINGLE_DMA;
- ptr = (unsigned char *) &chip->image;
- snd_ad1848_mce_down(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (i = 0; i < 16; i++) /* ok.. fill all AD1848 registers */
- snd_ad1848_out(chip, i, *ptr++);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_ad1848_mce_up(chip);
- snd_ad1848_mce_down(chip);
- return 0; /* all things are ok.. */
-}
-
-/*
-
- */
-
-static struct snd_pcm_hardware snd_ad1848_playback =
-{
- .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID),
- .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
- SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
- .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 5510,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = (128*1024),
- .period_bytes_min = 64,
- .period_bytes_max = (128*1024),
- .periods_min = 1,
- .periods_max = 1024,
- .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware snd_ad1848_capture =
-{
- .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID),
- .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
- SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
- .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 5510,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = (128*1024),
- .period_bytes_min = 64,
- .period_bytes_max = (128*1024),
- .periods_min = 1,
- .periods_max = 1024,
- .fifo_size = 0,
-};
-
-/*
-
- */
-
-static int snd_ad1848_playback_open(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- if ((err = snd_ad1848_open(chip, AD1848_MODE_PLAY)) < 0)
- return err;
- chip->playback_substream = substream;
- runtime->hw = snd_ad1848_playback;
- snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max);
- snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
- return 0;
-}
-
-static int snd_ad1848_capture_open(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- if ((err = snd_ad1848_open(chip, AD1848_MODE_CAPTURE)) < 0)
- return err;
- chip->capture_substream = substream;
- runtime->hw = snd_ad1848_capture;
- snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max);
- snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
- return 0;
-}
-
-static int snd_ad1848_playback_close(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-
- chip->mode &= ~AD1848_MODE_PLAY;
- chip->playback_substream = NULL;
- snd_ad1848_close(chip);
- return 0;
-}
-
-static int snd_ad1848_capture_close(struct snd_pcm_substream *substream)
-{
- struct snd_ad1848 *chip = snd_pcm_substream_chip(substream);
-
- chip->mode &= ~AD1848_MODE_CAPTURE;
- chip->capture_substream = NULL;
- snd_ad1848_close(chip);
- return 0;
-}
-
-static int snd_ad1848_free(struct snd_ad1848 *chip)
-{
- release_and_free_resource(chip->res_port);
- if (chip->irq >= 0)
- free_irq(chip->irq, (void *) chip);
- if (chip->dma >= 0) {
- snd_dma_disable(chip->dma);
- free_dma(chip->dma);
- }
- kfree(chip);
- return 0;
-}
-
-static int snd_ad1848_dev_free(struct snd_device *device)
-{
- struct snd_ad1848 *chip = device->device_data;
- return snd_ad1848_free(chip);
-}
-
-static const char *snd_ad1848_chip_id(struct snd_ad1848 *chip)
-{
- switch (chip->hardware) {
- case AD1848_HW_AD1847: return "AD1847";
- case AD1848_HW_AD1848: return "AD1848";
- case AD1848_HW_CS4248: return "CS4248";
- case AD1848_HW_CMI8330: return "CMI8330/C3D";
- default: return "???";
- }
-}
-
-int snd_ad1848_create(struct snd_card *card,
- unsigned long port,
- int irq, int dma,
- unsigned short hardware,
- struct snd_ad1848 ** rchip)
-{
- static struct snd_device_ops ops = {
- .dev_free = snd_ad1848_dev_free,
- };
- struct snd_ad1848 *chip;
- int err;
-
- *rchip = NULL;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
- spin_lock_init(&chip->reg_lock);
- init_MUTEX(&chip->open_mutex);
- chip->card = card;
- chip->port = port;
- chip->irq = -1;
- chip->dma = -1;
- chip->hardware = hardware;
- memcpy(&chip->image, &snd_ad1848_original_image, sizeof(snd_ad1848_original_image));
-
- if ((chip->res_port = request_region(port, 4, "AD1848")) == NULL) {
- snd_printk(KERN_ERR "ad1848: can't grab port 0x%lx\n", port);
- snd_ad1848_free(chip);
- return -EBUSY;
- }
- if (request_irq(irq, snd_ad1848_interrupt, SA_INTERRUPT, "AD1848", (void *) chip)) {
- snd_printk(KERN_ERR "ad1848: can't grab IRQ %d\n", irq);
- snd_ad1848_free(chip);
- return -EBUSY;
- }
- chip->irq = irq;
- if (request_dma(dma, "AD1848")) {
- snd_printk(KERN_ERR "ad1848: can't grab DMA %d\n", dma);
- snd_ad1848_free(chip);
- return -EBUSY;
- }
- chip->dma = dma;
-
- if (hardware == AD1848_HW_THINKPAD) {
- chip->thinkpad_flag = 1;
- chip->hardware = AD1848_HW_DETECT; /* reset */
- snd_ad1848_thinkpad_twiddle(chip, 1);
- }
-
- if (snd_ad1848_probe(chip) < 0) {
- snd_ad1848_free(chip);
- return -ENODEV;
- }
-
- /* Register device */
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
- snd_ad1848_free(chip);
- return err;
- }
-
-#ifdef CONFIG_PM
- chip->suspend = snd_ad1848_suspend;
- chip->resume = snd_ad1848_resume;
-#endif
-
- *rchip = chip;
- return 0;
-}
-
-static struct snd_pcm_ops snd_ad1848_playback_ops = {
- .open = snd_ad1848_playback_open,
- .close = snd_ad1848_playback_close,
- .ioctl = snd_ad1848_ioctl,
- .hw_params = snd_ad1848_playback_hw_params,
- .hw_free = snd_ad1848_playback_hw_free,
- .prepare = snd_ad1848_playback_prepare,
- .trigger = snd_ad1848_playback_trigger,
- .pointer = snd_ad1848_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_ad1848_capture_ops = {
- .open = snd_ad1848_capture_open,
- .close = snd_ad1848_capture_close,
- .ioctl = snd_ad1848_ioctl,
- .hw_params = snd_ad1848_capture_hw_params,
- .hw_free = snd_ad1848_capture_hw_free,
- .prepare = snd_ad1848_capture_prepare,
- .trigger = snd_ad1848_capture_trigger,
- .pointer = snd_ad1848_capture_pointer,
-};
-
-int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm)
-{
- struct snd_pcm *pcm;
- int err;
-
- if ((err = snd_pcm_new(chip->card, "AD1848", device, 1, 1, &pcm)) < 0)
- return err;
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ad1848_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ad1848_capture_ops);
-
- pcm->private_data = chip;
- pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
- strcpy(pcm->name, snd_ad1848_chip_id(chip));
-
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_isa_data(),
- 64*1024, chip->dma > 3 ? 128*1024 : 64*1024);
-
- chip->pcm = pcm;
- if (rpcm)
- *rpcm = pcm;
- return 0;
-}
-
-const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
-{
- return direction == SNDRV_PCM_STREAM_PLAYBACK ?
- &snd_ad1848_playback_ops : &snd_ad1848_capture_ops;
-}
-
-/*
- * MIXER part
- */
-
-static int snd_ad1848_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- static char *texts[4] = {
- "Line", "Aux", "Mic", "Mix"
- };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- 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_ad1848_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- ucontrol->value.enumerated.item[0] = (chip->image[AD1848_LEFT_INPUT] & AD1848_MIXS_ALL) >> 6;
- ucontrol->value.enumerated.item[1] = (chip->image[AD1848_RIGHT_INPUT] & AD1848_MIXS_ALL) >> 6;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
-}
-
-static int snd_ad1848_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- unsigned short left, right;
- int change;
-
- if (ucontrol->value.enumerated.item[0] > 3 ||
- ucontrol->value.enumerated.item[1] > 3)
- return -EINVAL;
- left = ucontrol->value.enumerated.item[0] << 6;
- right = ucontrol->value.enumerated.item[1] << 6;
- spin_lock_irqsave(&chip->reg_lock, flags);
- left = (chip->image[AD1848_LEFT_INPUT] & ~AD1848_MIXS_ALL) | left;
- right = (chip->image[AD1848_RIGHT_INPUT] & ~AD1848_MIXS_ALL) | right;
- change = left != chip->image[AD1848_LEFT_INPUT] ||
- right != chip->image[AD1848_RIGHT_INPUT];
- snd_ad1848_out(chip, AD1848_LEFT_INPUT, left);
- snd_ad1848_out(chip, AD1848_RIGHT_INPUT, right);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return change;
-}
-
-static int snd_ad1848_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 16) & 0xff;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-static int snd_ad1848_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int reg = kcontrol->private_value & 0xff;
- int shift = (kcontrol->private_value >> 8) & 0xff;
- int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (invert)
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- return 0;
-}
-
-static int snd_ad1848_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int reg = kcontrol->private_value & 0xff;
- int shift = (kcontrol->private_value >> 8) & 0xff;
- int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
- int change;
- unsigned short val;
-
- val = (ucontrol->value.integer.value[0] & mask);
- if (invert)
- val = mask - val;
- val <<= shift;
- spin_lock_irqsave(&chip->reg_lock, flags);
- val = (chip->image[reg] & ~(mask << shift)) | val;
- change = val != chip->image[reg];
- snd_ad1848_out(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return change;
-}
-
-static int snd_ad1848_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 24) & 0xff;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-static int snd_ad1848_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
- int mask = (kcontrol->private_value >> 24) & 0xff;
- int invert = (kcontrol->private_value >> 22) & 1;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
- ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (invert) {
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
- }
- return 0;
-}
-
-static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
- int mask = (kcontrol->private_value >> 24) & 0xff;
- int invert = (kcontrol->private_value >> 22) & 1;
- int change;
- unsigned short val1, val2;
-
- val1 = ucontrol->value.integer.value[0] & mask;
- val2 = ucontrol->value.integer.value[1] & mask;
- if (invert) {
- val1 = mask - val1;
- val2 = mask - val2;
- }
- val1 <<= shift_left;
- val2 <<= shift_right;
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (left_reg != right_reg) {
- val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
- val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
- change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
- snd_ad1848_out(chip, left_reg, val1);
- snd_ad1848_out(chip, right_reg, val2);
- } else {
- val1 = (chip->image[left_reg] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
- change = val1 != chip->image[left_reg];
- snd_ad1848_out(chip, left_reg, val1);
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return change;
-}
-
-/*
- */
-int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value)
-{
- static struct snd_kcontrol_new newctls[] = {
- [AD1848_MIX_SINGLE] = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = snd_ad1848_info_single,
- .get = snd_ad1848_get_single,
- .put = snd_ad1848_put_single,
- },
- [AD1848_MIX_DOUBLE] = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = snd_ad1848_info_double,
- .get = snd_ad1848_get_double,
- .put = snd_ad1848_put_double,
- },
- [AD1848_MIX_CAPTURE] = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = snd_ad1848_info_mux,
- .get = snd_ad1848_get_mux,
- .put = snd_ad1848_put_mux,
- },
- };
- struct snd_kcontrol *ctl;
- int err;
-
- ctl = snd_ctl_new1(&newctls[type], chip);
- if (! ctl)
- return -ENOMEM;
- strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
- ctl->id.index = index;
- ctl->private_value = value;
- if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
- snd_ctl_free_one(ctl);
- return err;
- }
- return 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),
-AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1),
-AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-AD1848_DOUBLE("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-AD1848_DOUBLE("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-AD1848_DOUBLE("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0),
-{
- .name = "Capture Source",
- .type = AD1848_MIX_CAPTURE,
-},
-AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0),
-AD1848_SINGLE("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0)
-};
-
-int snd_ad1848_mixer(struct snd_ad1848 *chip)
-{
- struct snd_card *card;
- struct snd_pcm *pcm;
- unsigned int idx;
- int err;
-
- snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
-
- pcm = chip->pcm;
- card = chip->card;
-
- strcpy(card->mixername, pcm->name);
-
- for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++)
- if ((err = snd_ad1848_add_ctl_elem(chip, &snd_ad1848_controls[idx])) < 0)
- return err;
-
- return 0;
-}
-
-EXPORT_SYMBOL(snd_ad1848_out);
-EXPORT_SYMBOL(snd_ad1848_create);
-EXPORT_SYMBOL(snd_ad1848_pcm);
-EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
-EXPORT_SYMBOL(snd_ad1848_mixer);
-EXPORT_SYMBOL(snd_ad1848_add_ctl);
-
-/*
- * INIT part
- */
-
-static int __init alsa_ad1848_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_ad1848_exit(void)
-{
-}
-
-module_init(alsa_ad1848_init)
-module_exit(alsa_ad1848_exit)
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
new file mode 100644
index 00000000000..120c524bb2a
--- /dev/null
+++ b/sound/isa/adlib.c
@@ -0,0 +1,126 @@
+/*
+ * AdLib FM card driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/opl3.h>
+
+#define CRD_NAME "AdLib FM"
+#define DEV_NAME "adlib"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+
+static int snd_adlib_match(struct device *dev, unsigned int n)
+{
+ if (!enable[n])
+ return 0;
+
+ if (port[n] == SNDRV_AUTO_PORT) {
+ dev_err(dev, "please specify port\n");
+ return 0;
+ }
+ return 1;
+}
+
+static void snd_adlib_free(struct snd_card *card)
+{
+ release_and_free_resource(card->private_data);
+}
+
+static int snd_adlib_probe(struct device *dev, unsigned int n)
+{
+ struct snd_card *card;
+ struct snd_opl3 *opl3;
+ int error;
+
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0) {
+ dev_err(dev, "could not create card\n");
+ return error;
+ }
+
+ card->private_data = request_region(port[n], 4, CRD_NAME);
+ if (!card->private_data) {
+ dev_err(dev, "could not grab ports\n");
+ error = -EBUSY;
+ goto out;
+ }
+ card->private_free = snd_adlib_free;
+
+ strcpy(card->driver, DEV_NAME);
+ strcpy(card->shortname, CRD_NAME);
+ sprintf(card->longname, CRD_NAME " at %#lx", port[n]);
+
+ error = snd_opl3_create(card, port[n], port[n] + 2, OPL3_HW_AUTO, 1, &opl3);
+ if (error < 0) {
+ dev_err(dev, "could not create OPL\n");
+ goto out;
+ }
+
+ error = snd_opl3_hwdep_new(opl3, 0, 0, NULL);
+ if (error < 0) {
+ dev_err(dev, "could not create FM\n");
+ goto out;
+ }
+
+ error = snd_card_register(card);
+ if (error < 0) {
+ dev_err(dev, "could not register card\n");
+ goto out;
+ }
+
+ dev_set_drvdata(dev, card);
+ return 0;
+
+out: snd_card_free(card);
+ return error;
+}
+
+static int snd_adlib_remove(struct device *dev, unsigned int n)
+{
+ snd_card_free(dev_get_drvdata(dev));
+ return 0;
+}
+
+static struct isa_driver snd_adlib_driver = {
+ .match = snd_adlib_match,
+ .probe = snd_adlib_probe,
+ .remove = snd_adlib_remove,
+
+ .driver = {
+ .name = DEV_NAME
+ }
+};
+
+static int __init alsa_card_adlib_init(void)
+{
+ return isa_register_driver(&snd_adlib_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_adlib_exit(void)
+{
+ isa_unregister_driver(&snd_adlib_driver);
+}
+
+module_init(alsa_card_adlib_init);
+module_exit(alsa_card_adlib_exit);
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index 9b77c17b3f6..32d01525211 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -2,9 +2,13 @@
/*
card-als100.c - driver for Avance Logic ALS100 based soundcards.
Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
+ Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it>
Thanks to Pierfrancesco 'qM2' Passerini.
+ Generalised for soundcards based on DT-0196 and ALS-007 chips
+ by Jonathan Woithe <jwoithe@just42.net>: June 2002.
+
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
@@ -20,12 +24,11 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/time.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/mpu401.h>
@@ -34,10 +37,10 @@
#define PFX "als100: "
-MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
-MODULE_DESCRIPTION("Avance Logic ALS1X0");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
+MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
+MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
+ "{Avance Logic ALS-007}}"
+ "{{Avance Logic,ALS100 - PRO16PNP},"
"{Avance Logic,ALS110},"
"{Avance Logic,ALS120},"
"{Avance Logic,ALS200},"
@@ -46,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
"{Avance Logic,ALS120},"
"{RTL,RTL3000}}");
+MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
+MODULE_LICENSE("GPL");
+
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
@@ -58,28 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for als100 based soundcard.");
+MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for als100 based soundcard.");
+MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable als100 based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for als100 driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for als100 driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for als100 driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for als100 driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for als100 driver.");
-module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for als100 driver.");
-module_param_array(dma16, int, NULL, 0444);
-MODULE_PARM_DESC(dma16, "16-bit DMA # for als100 driver.");
+MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");
+
+MODULE_ALIAS("snd-dt019x");
struct snd_card_als100 {
- int dev_no;
struct pnp_dev *dev;
struct pnp_dev *devmpu;
struct pnp_dev *devopl;
@@ -87,78 +80,75 @@ struct snd_card_als100 {
};
static struct pnp_card_device_id snd_als100_pnpids[] = {
+ /* DT197A30 */
+ { .id = "RWB1688",
+ .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
+ .driver_data = SB_HW_DT019X },
+ /* DT0196 / ALS-007 */
+ { .id = "ALS0007",
+ .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
+ .driver_data = SB_HW_DT019X },
/* ALS100 - PRO16PNP */
- { .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
+ { .id = "ALS0001",
+ .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
+ .driver_data = SB_HW_ALS100 },
/* ALS110 - MF1000 - Digimate 3D Sound */
- { .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } },
+ { .id = "ALS0110",
+ .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } },
+ .driver_data = SB_HW_ALS100 },
/* ALS120 */
- { .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
+ { .id = "ALS0120",
+ .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
+ .driver_data = SB_HW_ALS100 },
/* ALS200 */
- { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } },
+ { .id = "ALS0200",
+ .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } },
+ .driver_data = SB_HW_ALS100 },
/* ALS200 OEM */
- { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } },
+ { .id = "ALS0200",
+ .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } },
+ .driver_data = SB_HW_ALS100 },
/* RTL3000 */
- { .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
- { .id = "", } /* end */
+ { .id = "RTL3000",
+ .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
+ .driver_data = SB_HW_ALS100 },
+ { .id = "" } /* end */
};
MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);
-#define DRIVER_NAME "snd-card-als100"
-
-static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
int err;
- if (!cfg)
- return -ENOMEM;
acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->dev == NULL) {
- kfree(cfg);
+ if (acard->dev == NULL)
return -ENODEV;
- }
+
acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);
acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev);
pdev = acard->dev;
- pnp_init_resource_table(cfg);
-
- /* override resources */
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
- if (dma8[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
- if (dma16[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
- kfree(cfg);
return err;
}
port[dev] = pnp_port_start(pdev, 0);
- dma8[dev] = pnp_dma(pdev, 1);
- dma16[dev] = pnp_dma(pdev, 0);
+ if (id->driver_data == SB_HW_DT019X)
+ dma8[dev] = pnp_dma(pdev, 0);
+ else {
+ dma8[dev] = pnp_dma(pdev, 1);
+ dma16[dev] = pnp_dma(pdev, 0);
+ }
irq[dev] = pnp_irq(pdev, 0);
pdev = acard->devmpu;
if (pdev != NULL) {
- pnp_init_resource_table(cfg);
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
- if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0)
goto __mpu_error;
@@ -176,11 +166,6 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
pdev = acard->devopl;
if (pdev != NULL) {
- pnp_init_resource_table(cfg);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], fm_port[dev], 4);
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "OPL3 the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0)
goto __fm_error;
@@ -195,13 +180,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
fm_port[dev] = -1;
}
- kfree(cfg);
return 0;
}
-static int __init snd_card_als100_probe(int dev,
- struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_card_als100_probe(int dev,
+ struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
int error;
struct snd_sb *chip;
@@ -209,35 +193,47 @@ static int __init snd_card_als100_probe(int dev,
struct snd_card_als100 *acard;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_als100))) == NULL)
- return -ENOMEM;
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_als100), &card);
+ if (error < 0)
+ return error;
acard = card->private_data;
if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
-
- if ((error = snd_sbdsp_create(card, port[dev],
- irq[dev],
- snd_sb16dsp_interrupt,
- dma8[dev],
- dma16[dev],
- SB_HW_ALS100, &chip)) < 0) {
+
+ if (pid->driver_data == SB_HW_DT019X)
+ dma16[dev] = -1;
+
+ error = snd_sbdsp_create(card, port[dev], irq[dev],
+ snd_sb16dsp_interrupt,
+ dma8[dev], dma16[dev],
+ pid->driver_data,
+ &chip);
+ if (error < 0) {
snd_card_free(card);
return error;
}
acard->chip = chip;
- strcpy(card->driver, "ALS100");
- strcpy(card->shortname, "Avance Logic ALS100");
- sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, chip->name, chip->port,
- irq[dev], dma8[dev], dma16[dev]);
+ if (pid->driver_data == SB_HW_DT019X) {
+ strcpy(card->driver, "DT-019X");
+ strcpy(card->shortname, "Diamond Tech. DT-019X");
+ sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
+ card->shortname, chip->name, chip->port,
+ irq[dev], dma8[dev]);
+ } else {
+ strcpy(card->driver, "ALS100");
+ strcpy(card->shortname, "Avance Logic ALS100");
+ sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
+ card->shortname, chip->name, chip->port,
+ irq[dev], dma8[dev], dma16[dev]);
+ }
- if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
+ if ((error = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) {
snd_card_free(card);
return error;
}
@@ -248,9 +244,18 @@ static int __init snd_card_als100_probe(int dev,
}
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
- if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100,
+ int mpu_type = MPU401_HW_ALS100;
+
+ if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
+ mpu_irq[dev] = -1;
+
+ if (pid->driver_data == SB_HW_DT019X)
+ mpu_type = MPU401_HW_MPU401;
+
+ if (snd_mpu401_uart_new(card, 0,
+ mpu_type,
mpu_port[dev], 0,
- mpu_irq[dev], SA_INTERRUPT,
+ mpu_irq[dev],
NULL) < 0)
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
}
@@ -281,8 +286,10 @@ static int __init snd_card_als100_probe(int dev,
return 0;
}
-static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static unsigned int als100_devices;
+
+static int snd_als100_pnp_detect(struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
static int dev;
int res;
@@ -294,12 +301,13 @@ static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card,
if (res < 0)
return res;
dev++;
+ als100_devices++;
return 0;
}
return -ENODEV;
}
-static void __devexit snd_als100_pnp_remove(struct pnp_card_link * pcard)
+static void snd_als100_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -333,10 +341,10 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard)
static struct pnp_card_driver als100_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
- .name = "als100",
+ .name = "als100",
.id_table = snd_als100_pnpids,
.probe = snd_als100_pnp_detect,
- .remove = __devexit_p(snd_als100_pnp_remove),
+ .remove = snd_als100_pnp_remove,
#ifdef CONFIG_PM
.suspend = snd_als100_pnp_suspend,
.resume = snd_als100_pnp_resume,
@@ -345,13 +353,16 @@ static struct pnp_card_driver als100_pnpc_driver = {
static int __init alsa_card_als100_init(void)
{
- int cards;
+ int err;
+
+ err = pnp_register_card_driver(&als100_pnpc_driver);
+ if (err)
+ return err;
- cards = pnp_register_card_driver(&als100_pnpc_driver);
- if (cards <= 0) {
+ if (!als100_devices) {
pnp_unregister_card_driver(&als100_pnpc_driver);
#ifdef MODULE
- snd_printk(KERN_ERR "no ALS100 based soundcards found\n");
+ snd_printk(KERN_ERR "no Avance Logic based soundcards found\n");
#endif
return -ENODEV;
}
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index a530691bf4f..0ea75fc6207 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -29,17 +29,16 @@
activation method (full-duplex audio!).
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
@@ -56,7 +55,7 @@ MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
@@ -72,28 +71,12 @@ module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for azt2320 driver.");
-module_param_array(wss_port, long, NULL, 0444);
-MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver.");
-module_param_array(dma2, int, NULL, 0444);
-MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver.");
struct snd_card_azt2320 {
int dev_no;
struct pnp_dev *dev;
struct pnp_dev *devmpu;
- struct snd_cs4231 *chip;
+ struct snd_wss *chip;
};
static struct pnp_card_device_id snd_azt2320_pnpids[] = {
@@ -116,48 +99,24 @@ MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
#define DRIVER_NAME "snd-card-azt2320"
-static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
int err;
- if (!cfg)
- return -ENOMEM;
-
acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->dev == NULL) {
- kfree(cfg);
+ if (acard->dev == NULL)
return -ENODEV;
- }
acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
pdev = acard->dev;
- pnp_init_resource_table(cfg);
-
- /* override resources */
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
- if (wss_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[2], wss_port[dev], 4);
- if (dma1[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
- if (dma2[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
- kfree(cfg);
return err;
}
port[dev] = pnp_port_start(pdev, 0);
@@ -169,13 +128,6 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar
pdev = acard->devmpu;
if (pdev != NULL) {
- pnp_init_resource_table(cfg);
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
- if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0)
goto __mpu_error;
@@ -191,12 +143,11 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar
mpu_port[dev] = -1;
}
- kfree (cfg);
return 0;
}
/* same of snd_sbdsp_command by Jaroslav Kysela */
-static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char val)
+static int snd_card_azt2320_command(unsigned long port, unsigned char val)
{
int i;
unsigned long limit;
@@ -210,7 +161,7 @@ static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char
return -EBUSY;
}
-static int __devinit snd_card_azt2320_enable_wss(unsigned long port)
+static int snd_card_azt2320_enable_wss(unsigned long port)
{
int error;
@@ -223,37 +174,38 @@ static int __devinit snd_card_azt2320_enable_wss(unsigned long port)
return 0;
}
-static int __devinit snd_card_azt2320_probe(int dev,
- struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_card_azt2320_probe(int dev,
+ struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
int error;
struct snd_card *card;
struct snd_card_azt2320 *acard;
- struct snd_cs4231 *chip;
+ struct snd_wss *chip;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_azt2320))) == NULL)
- return -ENOMEM;
- acard = (struct snd_card_azt2320 *)card->private_data;
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_azt2320), &card);
+ if (error < 0)
+ return error;
+ acard = card->private_data;
if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
snd_card_free(card);
return error;
}
- if ((error = snd_cs4231_create(card, wss_port[dev], -1,
- irq[dev],
- dma1[dev],
- dma2[dev],
- CS4231_HW_DETECT, 0, &chip)) < 0) {
+ error = snd_wss_create(card, wss_port[dev], -1,
+ irq[dev],
+ dma1[dev], dma2[dev],
+ WSS_HW_DETECT, 0, &chip);
+ if (error < 0) {
snd_card_free(card);
return error;
}
@@ -263,15 +215,18 @@ static int __devinit snd_card_azt2320_probe(int dev,
sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
- if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
+ error = snd_wss_pcm(chip, 0, NULL);
+ if (error < 0) {
snd_card_free(card);
return error;
}
- if ((error = snd_cs4231_mixer(chip)) < 0) {
+ error = snd_wss_mixer(chip);
+ if (error < 0) {
snd_card_free(card);
return error;
}
- if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
+ error = snd_wss_timer(chip, 0, NULL);
+ if (error < 0) {
snd_card_free(card);
return error;
}
@@ -279,8 +234,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
mpu_port[dev], 0,
- mpu_irq[dev], SA_INTERRUPT,
- NULL) < 0)
+ mpu_irq[dev], NULL) < 0)
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
}
@@ -310,8 +264,10 @@ static int __devinit snd_card_azt2320_probe(int dev,
return 0;
}
-static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static unsigned int azt2320_devices;
+
+static int snd_azt2320_pnp_detect(struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
static int dev;
int res;
@@ -323,12 +279,13 @@ static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card,
if (res < 0)
return res;
dev++;
+ azt2320_devices++;
return 0;
}
return -ENODEV;
}
-static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard)
+static void snd_azt2320_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -339,7 +296,7 @@ static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t sta
{
struct snd_card *card = pnp_get_card_drvdata(pcard);
struct snd_card_azt2320 *acard = card->private_data;
- struct snd_cs4231 *chip = acard->chip;
+ struct snd_wss *chip = acard->chip;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
chip->suspend(chip);
@@ -350,7 +307,7 @@ static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
{
struct snd_card *card = pnp_get_card_drvdata(pcard);
struct snd_card_azt2320 *acard = card->private_data;
- struct snd_cs4231 *chip = acard->chip;
+ struct snd_wss *chip = acard->chip;
chip->resume(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -363,7 +320,7 @@ static struct pnp_card_driver azt2320_pnpc_driver = {
.name = "azt2320",
.id_table = snd_azt2320_pnpids,
.probe = snd_azt2320_pnp_detect,
- .remove = __devexit_p(snd_azt2320_pnp_remove),
+ .remove = snd_azt2320_pnp_remove,
#ifdef CONFIG_PM
.suspend = snd_azt2320_pnp_suspend,
.resume = snd_azt2320_pnp_resume,
@@ -372,10 +329,13 @@ static struct pnp_card_driver azt2320_pnpc_driver = {
static int __init alsa_card_azt2320_init(void)
{
- int cards;
+ int err;
+
+ err = pnp_register_card_driver(&azt2320_pnpc_driver);
+ if (err)
+ return err;
- cards = pnp_register_card_driver(&azt2320_pnpc_driver);
- if (cards <= 0) {
+ if (!azt2320_devices) {
pnp_unregister_card_driver(&azt2320_pnpc_driver);
#ifdef MODULE
snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
new file mode 100644
index 00000000000..4778852a120
--- /dev/null
+++ b/sound/isa/cmi8328.c
@@ -0,0 +1,483 @@
+/*
+ * Driver for C-Media CMI8328-based soundcards, such as AudioExcel AV500
+ * Copyright (c) 2012 Ondrej Zary
+ *
+ * AudioExcel AV500 card consists of:
+ * - CMI8328 - main chip (SB Pro emulation, gameport, OPL3, MPU401, CD-ROM)
+ * - CS4231A - WSS codec
+ * - Dream SAM9233+GMS950400+RAM+ROM: Wavetable MIDI, connected to MPU401
+ */
+
+#include <linux/init.h>
+#include <linux/isa.h>
+#include <linux/module.h>
+#include <linux/gameport.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ondrej Zary <linux@rainbow-software.org>");
+MODULE_DESCRIPTION("C-Media CMI8328");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#define SUPPORT_JOYSTICK 1
+#endif
+
+/* I/O port is configured by jumpers on the card to one of these */
+static int cmi8328_ports[] = { 0x530, 0xe80, 0xf40, 0x604 };
+#define CMI8328_MAX ARRAY_SIZE(cmi8328_ports)
+
+static int index[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = -1};
+static char *id[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = NULL};
+static long port[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int irq[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+static int dma1[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static int dma2[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static long mpuport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int mpuirq[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+#ifdef SUPPORT_JOYSTICK
+static bool gameport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = true};
+#endif
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for CMI8328 soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for CMI8328 soundcard.");
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for CMI8328 driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for CMI8328 driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "DMA1 for CMI8328 driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "DMA2 for CMI8328 driver.");
+
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8328 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8328 MPU-401 port.");
+#ifdef SUPPORT_JOYSTICK
+module_param_array(gameport, bool, NULL, 0444);
+MODULE_PARM_DESC(gameport, "Enable gameport.");
+#endif
+
+struct snd_cmi8328 {
+ u16 port;
+ u8 cfg[3];
+ u8 wss_cfg;
+ struct snd_card *card;
+ struct snd_wss *wss;
+#ifdef SUPPORT_JOYSTICK
+ struct gameport *gameport;
+#endif
+};
+
+/* CMI8328 configuration registers */
+#define CFG1 0x61
+#define CFG1_SB_DISABLE (1 << 0)
+#define CFG1_GAMEPORT (1 << 1)
+/*
+ * bit 0: SB: 0=enabled, 1=disabled
+ * bit 1: gameport: 0=disabled, 1=enabled
+ * bits 2-4: SB IRQ: 001=3, 010=5, 011=7, 100=9, 101=10, 110=11
+ * bits 5-6: SB DMA: 00=disabled (when SB disabled), 01=DMA0, 10=DMA1, 11=DMA3
+ * bit 7: SB port: 0=0x220, 1=0x240
+ */
+#define CFG2 0x62
+#define CFG2_MPU_ENABLE (1 << 2)
+/*
+ * bits 0-1: CD-ROM mode: 00=disabled, 01=Panasonic, 10=Sony/Mitsumi/Wearnes,
+ 11=IDE
+ * bit 2: MPU401: 0=disabled, 1=enabled
+ * bits 3-4: MPU401 IRQ: 00=3, 01=5, 10=7, 11=9,
+ * bits 5-7: MPU401 port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x332,
+ 101=0x334, 110=0x336
+ */
+#define CFG3 0x63
+/*
+ * bits 0-2: CD-ROM IRQ: 000=disabled, 001=3, 010=5, 011=7, 100=9, 101=10,
+ 110=11
+ * bits 3-4: CD-ROM DMA: 00=disabled, 01=DMA0, 10=DMA1, 11=DMA3
+ * bits 5-7: CD-ROM port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x340,
+ 101=0x350, 110=0x360, 111=0x370
+ */
+
+static u8 snd_cmi8328_cfg_read(u16 port, u8 reg)
+{
+ outb(0x43, port + 3);
+ outb(0x21, port + 3);
+ outb(reg, port + 3);
+ return inb(port);
+}
+
+static void snd_cmi8328_cfg_write(u16 port, u8 reg, u8 val)
+{
+ outb(0x43, port + 3);
+ outb(0x21, port + 3);
+ outb(reg, port + 3);
+ outb(val, port + 3); /* yes, value goes to the same port as index */
+}
+
+#ifdef CONFIG_PM
+static void snd_cmi8328_cfg_save(u16 port, u8 cfg[])
+{
+ cfg[0] = snd_cmi8328_cfg_read(port, CFG1);
+ cfg[1] = snd_cmi8328_cfg_read(port, CFG2);
+ cfg[2] = snd_cmi8328_cfg_read(port, CFG3);
+}
+
+static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[])
+{
+ snd_cmi8328_cfg_write(port, CFG1, cfg[0]);
+ snd_cmi8328_cfg_write(port, CFG2, cfg[1]);
+ snd_cmi8328_cfg_write(port, CFG3, cfg[2]);
+}
+#endif /* CONFIG_PM */
+
+static int snd_cmi8328_mixer(struct snd_wss *chip)
+{
+ struct snd_card *card;
+ struct snd_ctl_elem_id id1, id2;
+ int err;
+
+ card = chip->card;
+
+ memset(&id1, 0, sizeof(id1));
+ memset(&id2, 0, sizeof(id2));
+ id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ /* rename AUX0 switch to CD */
+ strcpy(id1.name, "Aux Playback Switch");
+ strcpy(id2.name, "CD Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+ /* rename AUX0 volume to CD */
+ strcpy(id1.name, "Aux Playback Volume");
+ strcpy(id2.name, "CD Playback Volume");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+ /* rename AUX1 switch to Synth */
+ strcpy(id1.name, "Aux Playback Switch");
+ id1.index = 1;
+ strcpy(id2.name, "Synth Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+ /* rename AUX1 volume to Synth */
+ strcpy(id1.name, "Aux Playback Volume");
+ id1.index = 1;
+ strcpy(id2.name, "Synth Playback Volume");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "error renaming control\n");
+ return err;
+ }
+
+ return 0;
+}
+
+/* find index of an item in "-1"-ended array */
+int array_find(int array[], int item)
+{
+ int i;
+
+ for (i = 0; array[i] != -1; i++)
+ if (array[i] == item)
+ return i;
+
+ return -1;
+}
+/* the same for long */
+int array_find_l(long array[], long item)
+{
+ int i;
+
+ for (i = 0; array[i] != -1; i++)
+ if (array[i] == item)
+ return i;
+
+ return -1;
+}
+
+static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
+{
+ struct snd_card *card;
+ struct snd_opl3 *opl3;
+ struct snd_cmi8328 *cmi;
+#ifdef SUPPORT_JOYSTICK
+ struct resource *res;
+#endif
+ int err, pos;
+ static long mpu_ports[] = { 0x330, 0x300, 0x310, 0x320, 0x332, 0x334,
+ 0x336, -1 };
+ static u8 mpu_port_bits[] = { 3, 0, 1, 2, 4, 5, 6 };
+ static int mpu_irqs[] = { 9, 7, 5, 3, -1 };
+ static u8 mpu_irq_bits[] = { 3, 2, 1, 0 };
+ static int irqs[] = { 9, 10, 11, 7, -1 };
+ static u8 irq_bits[] = { 2, 3, 4, 1 };
+ static int dma1s[] = { 3, 1, 0, -1 };
+ static u8 dma_bits[] = { 3, 2, 1 };
+ static int dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, {0, -1} };
+ u16 port = cmi8328_ports[ndev];
+ u8 val;
+
+ /* 0xff is invalid configuration (but settable - hope it isn't set) */
+ if (snd_cmi8328_cfg_read(port, CFG1) == 0xff)
+ return -ENODEV;
+ /* the SB disable bit must NEVER EVER be cleared or the WSS dies */
+ snd_cmi8328_cfg_write(port, CFG1, CFG1_SB_DISABLE);
+ if (snd_cmi8328_cfg_read(port, CFG1) != CFG1_SB_DISABLE)
+ return -ENODEV;
+ /* disable everything first */
+ snd_cmi8328_cfg_write(port, CFG2, 0); /* disable CDROM and MPU401 */
+ snd_cmi8328_cfg_write(port, CFG3, 0); /* disable CDROM IRQ and DMA */
+
+ if (irq[ndev] == SNDRV_AUTO_IRQ) {
+ irq[ndev] = snd_legacy_find_free_irq(irqs);
+ if (irq[ndev] < 0) {
+ snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ return -EBUSY;
+ }
+ }
+ if (dma1[ndev] == SNDRV_AUTO_DMA) {
+ dma1[ndev] = snd_legacy_find_free_dma(dma1s);
+ if (dma1[ndev] < 0) {
+ snd_printk(KERN_ERR "unable to find a free DMA1\n");
+ return -EBUSY;
+ }
+ }
+ if (dma2[ndev] == SNDRV_AUTO_DMA) {
+ dma2[ndev] = snd_legacy_find_free_dma(dma2s[dma1[ndev] % 4]);
+ if (dma2[ndev] < 0) {
+ snd_printk(KERN_WARNING "unable to find a free DMA2, full-duplex will not work\n");
+ dma2[ndev] = -1;
+ }
+ }
+ /* configure WSS IRQ... */
+ pos = array_find(irqs, irq[ndev]);
+ if (pos < 0) {
+ snd_printk(KERN_ERR "invalid IRQ %d\n", irq[ndev]);
+ return -EINVAL;
+ }
+ val = irq_bits[pos] << 3;
+ /* ...and DMA... */
+ pos = array_find(dma1s, dma1[ndev]);
+ if (pos < 0) {
+ snd_printk(KERN_ERR "invalid DMA1 %d\n", dma1[ndev]);
+ return -EINVAL;
+ }
+ val |= dma_bits[pos];
+ /* ...and DMA2 */
+ if (dma2[ndev] >= 0 && dma1[ndev] != dma2[ndev]) {
+ pos = array_find(dma2s[dma1[ndev]], dma2[ndev]);
+ if (pos < 0) {
+ snd_printk(KERN_ERR "invalid DMA2 %d\n", dma2[ndev]);
+ return -EINVAL;
+ }
+ val |= 0x04; /* enable separate capture DMA */
+ }
+ outb(val, port);
+
+ err = snd_card_new(pdev, index[ndev], id[ndev], THIS_MODULE,
+ sizeof(struct snd_cmi8328), &card);
+ if (err < 0)
+ return err;
+ cmi = card->private_data;
+ cmi->card = card;
+ cmi->port = port;
+ cmi->wss_cfg = val;
+
+ err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev],
+ dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_pcm(cmi->wss, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_mixer(cmi->wss);
+ if (err < 0)
+ goto error;
+ err = snd_cmi8328_mixer(cmi->wss);
+ if (err < 0)
+ goto error;
+
+ if (snd_wss_timer(cmi->wss, 0, NULL) < 0)
+ snd_printk(KERN_WARNING "error initializing WSS timer\n");
+
+ if (mpuport[ndev] == SNDRV_AUTO_PORT) {
+ mpuport[ndev] = snd_legacy_find_free_ioport(mpu_ports, 2);
+ if (mpuport[ndev] < 0)
+ snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
+ }
+ if (mpuirq[ndev] == SNDRV_AUTO_IRQ) {
+ mpuirq[ndev] = snd_legacy_find_free_irq(mpu_irqs);
+ if (mpuirq[ndev] < 0)
+ snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
+ }
+ /* enable and configure MPU401 */
+ if (mpuport[ndev] > 0 && mpuirq[ndev] > 0) {
+ val = CFG2_MPU_ENABLE;
+ pos = array_find_l(mpu_ports, mpuport[ndev]);
+ if (pos < 0)
+ snd_printk(KERN_WARNING "invalid MPU401 port 0x%lx\n",
+ mpuport[ndev]);
+ else {
+ val |= mpu_port_bits[pos] << 5;
+ pos = array_find(mpu_irqs, mpuirq[ndev]);
+ if (pos < 0)
+ snd_printk(KERN_WARNING "invalid MPU401 IRQ %d\n",
+ mpuirq[ndev]);
+ else {
+ val |= mpu_irq_bits[pos] << 3;
+ snd_cmi8328_cfg_write(port, CFG2, val);
+ if (snd_mpu401_uart_new(card, 0,
+ MPU401_HW_MPU401, mpuport[ndev],
+ 0, mpuirq[ndev], NULL) < 0)
+ snd_printk(KERN_ERR "error initializing MPU401\n");
+ }
+ }
+ }
+ /* OPL3 is hardwired to 0x388 and cannot be disabled */
+ if (snd_opl3_create(card, 0x388, 0x38a, OPL3_HW_AUTO, 0, &opl3) < 0)
+ snd_printk(KERN_ERR "error initializing OPL3\n");
+ else
+ if (snd_opl3_hwdep_new(opl3, 0, 1, NULL) < 0)
+ snd_printk(KERN_WARNING "error initializing OPL3 hwdep\n");
+
+ strcpy(card->driver, "CMI8328");
+ strcpy(card->shortname, "C-Media CMI8328");
+ sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d",
+ card->shortname, cmi->wss->port, irq[ndev], dma1[ndev],
+ (dma2[ndev] >= 0) ? dma2[ndev] : dma1[ndev]);
+
+ dev_set_drvdata(pdev, card);
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+#ifdef SUPPORT_JOYSTICK
+ if (!gameport[ndev])
+ return 0;
+ /* gameport is hardwired to 0x200 */
+ res = request_region(0x200, 8, "CMI8328 gameport");
+ if (!res)
+ snd_printk(KERN_WARNING "unable to allocate gameport I/O port\n");
+ else {
+ struct gameport *gp = cmi->gameport = gameport_allocate_port();
+ if (!cmi->gameport)
+ release_and_free_resource(res);
+ else {
+ gameport_set_name(gp, "CMI8328 Gameport");
+ gameport_set_phys(gp, "%s/gameport0", dev_name(pdev));
+ gameport_set_dev_parent(gp, pdev);
+ gp->io = 0x200;
+ gameport_set_port_data(gp, res);
+ /* Enable gameport */
+ snd_cmi8328_cfg_write(port, CFG1,
+ CFG1_SB_DISABLE | CFG1_GAMEPORT);
+ gameport_register_port(gp);
+ }
+ }
+#endif
+ return 0;
+error:
+ snd_card_free(card);
+
+ return err;
+}
+
+static int snd_cmi8328_remove(struct device *pdev, unsigned int dev)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_cmi8328 *cmi = card->private_data;
+
+#ifdef SUPPORT_JOYSTICK
+ if (cmi->gameport) {
+ struct resource *res = gameport_get_port_data(cmi->gameport);
+ gameport_unregister_port(cmi->gameport);
+ release_and_free_resource(res);
+ }
+#endif
+ /* disable everything */
+ snd_cmi8328_cfg_write(cmi->port, CFG1, CFG1_SB_DISABLE);
+ snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
+ snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
+ snd_card_free(card);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_cmi8328_suspend(struct device *pdev, unsigned int n,
+ pm_message_t state)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_cmi8328 *cmi;
+
+ if (!card) /* ignore absent devices */
+ return 0;
+ cmi = card->private_data;
+ snd_cmi8328_cfg_save(cmi->port, cmi->cfg);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(cmi->wss->pcm);
+ cmi->wss->suspend(cmi->wss);
+
+ return 0;
+}
+
+static int snd_cmi8328_resume(struct device *pdev, unsigned int n)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_cmi8328 *cmi;
+
+ if (!card) /* ignore absent devices */
+ return 0;
+ cmi = card->private_data;
+ snd_cmi8328_cfg_restore(cmi->port, cmi->cfg);
+ outb(cmi->wss_cfg, cmi->port);
+ cmi->wss->resume(cmi->wss);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+#endif
+
+static struct isa_driver snd_cmi8328_driver = {
+ .probe = snd_cmi8328_probe,
+ .remove = snd_cmi8328_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_cmi8328_suspend,
+ .resume = snd_cmi8328_resume,
+#endif
+ .driver = {
+ .name = "cmi8328"
+ },
+};
+
+static int __init alsa_card_cmi8328_init(void)
+{
+ return isa_register_driver(&snd_cmi8328_driver, CMI8328_MAX);
+}
+
+static void __exit alsa_card_cmi8328_exit(void)
+{
+ isa_unregister_driver(&snd_cmi8328_driver);
+}
+
+module_init(alsa_card_cmi8328_init)
+module_exit(alsa_card_cmi8328_exit)
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index bd8e2381846..dfedfd85f20 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -1,5 +1,5 @@
/*
- * Driver for C-Media's CMI8330 soundcards.
+ * Driver for C-Media's CMI8330 and CMI8329 soundcards.
* Copyright (c) by George Talusan <gstalusan@uwaterloo.ca>
* http://www.undergrad.math.uwaterloo.ca/~gstalusa
*
@@ -31,7 +31,7 @@
* To quickly load the module,
*
* modprobe -a snd-cmi8330 sbport=0x220 sbirq=5 sbdma8=1
- * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0
+ * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0 fmport=0x388
*
* This card has two mixers and two PCM devices. I've cheesed it such
* that recording and playback can be done through the same device.
@@ -43,15 +43,15 @@
* full control over both mixers.
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <linux/isa.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
-#include <sound/ad1848.h>
+#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
#include <sound/sb.h>
#include <sound/initval.h>
@@ -63,15 +63,15 @@
/*
*/
MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>");
-MODULE_DESCRIPTION("C-Media CMI8330");
+MODULE_DESCRIPTION("C-Media CMI8330/CMI8329");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
#ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#endif
static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
static int sbirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
@@ -80,36 +80,47 @@ static int sbdma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
static int wssirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
static int wssdma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static long fmport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard.");
+MODULE_PARM_DESC(index, "Index value for CMI8330/CMI8329 soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for CMI8330 soundcard.");
+MODULE_PARM_DESC(id, "ID string for CMI8330/CMI8329 soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard.");
+MODULE_PARM_DESC(enable, "Enable CMI8330/CMI8329 soundcard.");
#ifdef CONFIG_PNP
module_param_array(isapnp, bool, NULL, 0444);
MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
#endif
module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbport, "Port # for CMI8330/CMI8329 SB driver.");
module_param_array(sbirq, int, NULL, 0444);
-MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330/CMI8329 SB driver.");
module_param_array(sbdma8, int, NULL, 0444);
-MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330/CMI8329 SB driver.");
module_param_array(sbdma16, int, NULL, 0444);
-MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330/CMI8329 SB driver.");
module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver.");
+MODULE_PARM_DESC(wssport, "Port # for CMI8330/CMI8329 WSS driver.");
module_param_array(wssirq, int, NULL, 0444);
-MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver.");
+MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330/CMI8329 WSS driver.");
module_param_array(wssdma, int, NULL, 0444);
-MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver.");
-
-static struct platform_device *platform_devices[SNDRV_CARDS];
+MODULE_PARM_DESC(wssdma, "DMA for CMI8330/CMI8329 WSS driver.");
+
+module_param_array(fmport, long, NULL, 0444);
+MODULE_PARM_DESC(fmport, "FM port # for CMI8330/CMI8329 driver.");
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330/CMI8329 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330/CMI8329 MPU-401 port.");
+#ifdef CONFIG_PNP
+static int isa_registered;
static int pnp_registered;
+#endif
#define CMI8330_RMUX3D 16
#define CMI8330_MUTEMUX 17
@@ -144,13 +155,19 @@ static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] =
typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *);
+enum card_type {
+ CMI8330,
+ CMI8329
+};
+
struct snd_cmi8330 {
#ifdef CONFIG_PNP
struct pnp_dev *cap;
struct pnp_dev *play;
+ struct pnp_dev *mpu;
#endif
struct snd_card *card;
- struct snd_ad1848 *wss;
+ struct snd_wss *wss;
struct snd_sb *sb;
struct snd_pcm *pcm;
@@ -159,12 +176,15 @@ struct snd_cmi8330 {
snd_pcm_open_callback_t open;
void *private_data; /* sb or wss */
} streams[2];
+
+ enum card_type type;
};
#ifdef CONFIG_PNP
static struct pnp_card_device_id snd_cmi8330_pnpids[] = {
- { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" } } },
+ { .id = "CMI0001", .devs = { { "@X@0001" }, { "@@@0001" }, { "@H@0001" }, { "A@@0001" } } },
+ { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
{ .id = "" }
};
@@ -173,36 +193,63 @@ MODULE_DEVICE_TABLE(pnp_card, snd_cmi8330_pnpids);
#endif
-static struct ad1848_mix_elem snd_cmi8330_controls[] __initdata = {
-AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
-AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1),
-AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
-AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1),
-AD1848_DOUBLE("Line Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0),
-AD1848_DOUBLE("Line Playback Volume", 0, CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("Line Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0),
-AD1848_DOUBLE("Line Capture Volume", 0, CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0),
-AD1848_DOUBLE("CD Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0),
-AD1848_DOUBLE("CD Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0),
-AD1848_DOUBLE("CD Playback Volume", 0, CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("CD Capture Volume", 0, CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
-AD1848_SINGLE("Mic Playback Switch", 0, CMI8330_MUTEMUX, 0, 1, 0),
-AD1848_SINGLE("Mic Playback Volume", 0, CMI8330_OUTPUTVOL, 0, 7, 0),
-AD1848_SINGLE("Mic Capture Switch", 0, CMI8330_RMUX3D, 0, 1, 0),
-AD1848_SINGLE("Mic Capture Volume", 0, CMI8330_OUTPUTVOL, 5, 7, 0),
-AD1848_DOUBLE("Wavetable Playback Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0),
-AD1848_DOUBLE("Wavetable Playback Volume", 0, CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0),
-AD1848_DOUBLE("Wavetable Capture Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0),
-AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
-AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1),
-AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0),
-AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1),
-AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1),
-AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1),
+static struct snd_kcontrol_new snd_cmi8330_controls[] = {
+WSS_DOUBLE("Master Playback Volume", 0,
+ CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
+WSS_SINGLE("Loud Playback Switch", 0,
+ CMI8330_MUTEMUX, 6, 1, 1),
+WSS_DOUBLE("PCM Playback Switch", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Playback Volume", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Line Playback Switch", 0,
+ CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0),
+WSS_DOUBLE("Line Playback Volume", 0,
+ CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0),
+WSS_DOUBLE("Line Capture Switch", 0,
+ CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0),
+WSS_DOUBLE("Line Capture Volume", 0,
+ CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0),
+WSS_DOUBLE("CD Playback Switch", 0,
+ CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0),
+WSS_DOUBLE("CD Capture Switch", 0,
+ CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0),
+WSS_DOUBLE("CD Playback Volume", 0,
+ CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0),
+WSS_DOUBLE("CD Capture Volume", 0,
+ CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
+WSS_SINGLE("Mic Playback Switch", 0,
+ CMI8330_MUTEMUX, 0, 1, 0),
+WSS_SINGLE("Mic Playback Volume", 0,
+ CMI8330_OUTPUTVOL, 0, 7, 0),
+WSS_SINGLE("Mic Capture Switch", 0,
+ CMI8330_RMUX3D, 0, 1, 0),
+WSS_SINGLE("Mic Capture Volume", 0,
+ CMI8330_OUTPUTVOL, 5, 7, 0),
+WSS_DOUBLE("Wavetable Playback Switch", 0,
+ CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0),
+WSS_DOUBLE("Wavetable Playback Volume", 0,
+ CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0),
+WSS_DOUBLE("Wavetable Capture Switch", 0,
+ CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0),
+WSS_DOUBLE("Wavetable Capture Volume", 0,
+ CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
+WSS_SINGLE("3D Control - Switch", 0,
+ CMI8330_RMUX3D, 5, 1, 1),
+WSS_SINGLE("Beep Playback Volume", 0,
+ CMI8330_OUTPUTVOL, 3, 3, 0),
+WSS_DOUBLE("FM Playback Switch", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("FM Playback Volume", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", CAPTURE, SWITCH), 0,
+ CMI8330_RMUX3D, 7, 1, 1),
+WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0,
+ CMI8330_MUTEMUX, 7, 1, 1),
};
#ifdef ENABLE_SB_MIXER
-static struct sbmix_elem cmi8330_sb_mixers[] __initdata = {
+static struct sbmix_elem cmi8330_sb_mixers[] = {
SB_DOUBLE("SB Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15),
@@ -214,13 +261,13 @@ SB_DOUBLE("SB Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3,
SB_DOUBLE("SB Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
SB_SINGLE("SB Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
SB_SINGLE("SB Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
-SB_SINGLE("SB PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
+SB_SINGLE("SB Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
SB_DOUBLE("SB Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
};
-static unsigned char cmi8330_sb_init_values[][2] __initdata = {
+static unsigned char cmi8330_sb_init_values[][2] = {
{ SB_DSP4_MASTER_DEV + 0, 0 },
{ SB_DSP4_MASTER_DEV + 1, 0 },
{ SB_DSP4_PCM_DEV + 0, 0 },
@@ -234,7 +281,7 @@ static unsigned char cmi8330_sb_init_values[][2] __initdata = {
};
-static int __devinit cmi8330_add_sb_mixers(struct snd_sb *chip)
+static int cmi8330_add_sb_mixers(struct snd_sb *chip)
{
int idx, err;
unsigned long flags;
@@ -259,15 +306,18 @@ static int __devinit cmi8330_add_sb_mixers(struct snd_sb *chip)
}
#endif
-static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 *acard)
+static int snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 *acard)
{
unsigned int idx;
int err;
- strcpy(card->mixername, "CMI8330/C3D");
+ strcpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) {
- if ((err = snd_ad1848_add_ctl_elem(acard->wss, &snd_cmi8330_controls[idx])) < 0)
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_cmi8330_controls[idx],
+ acard->wss));
+ if (err < 0)
return err;
}
@@ -279,75 +329,71 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330
}
#ifdef CONFIG_PNP
-static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
int err;
+ /* CMI8329 has a device with ID A@@0001, CMI8330 does not */
+ acard->type = (id->devs[3].id[0]) ? CMI8329 : CMI8330;
+
acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->cap == NULL) {
- kfree(cfg);
+ if (acard->cap == NULL)
return -EBUSY;
- }
+
acard->play = pnp_request_card_device(card, id->devs[1].id, NULL);
- if (acard->play == NULL) {
- kfree(cfg);
+ if (acard->play == NULL)
+ return -EBUSY;
+
+ acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
+ if (acard->mpu == NULL)
return -EBUSY;
- }
pdev = acard->cap;
- pnp_init_resource_table(cfg);
- /* allocate AD1848 resources */
- if (wssport[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], wssport[dev], 8);
- if (wssdma[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], wssdma[dev], 1);
- if (wssirq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], wssirq[dev], 1);
-
- err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
- snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP manual resources are invalid, using auto config\n");
+
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n");
- kfree(cfg);
+ snd_printk(KERN_ERR "AD1848 PnP configure failure\n");
return -EBUSY;
}
wssport[dev] = pnp_port_start(pdev, 0);
wssdma[dev] = pnp_dma(pdev, 0);
wssirq[dev] = pnp_irq(pdev, 0);
+ if (pnp_port_start(pdev, 1))
+ fmport[dev] = pnp_port_start(pdev, 1);
/* allocate SB16 resources */
pdev = acard->play;
- pnp_init_resource_table(cfg);
- if (sbport[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], sbport[dev], 16);
- if (sbdma8[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], sbdma8[dev], 1);
- if (sbdma16[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], sbdma16[dev], 1);
- if (sbirq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], sbirq[dev], 1);
-
- err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
- snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP manual resources are invalid, using auto config\n");
+
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n");
- kfree(cfg);
+ snd_printk(KERN_ERR "SB16 PnP configure failure\n");
return -EBUSY;
}
sbport[dev] = pnp_port_start(pdev, 0);
sbdma8[dev] = pnp_dma(pdev, 0);
sbdma16[dev] = pnp_dma(pdev, 1);
sbirq[dev] = pnp_irq(pdev, 0);
+ /* On CMI8239, the OPL3 port might be present in SB16 PnP resources */
+ if (fmport[dev] == SNDRV_AUTO_PORT) {
+ if (pnp_port_start(pdev, 1))
+ fmport[dev] = pnp_port_start(pdev, 1);
+ else
+ fmport[dev] = 0x388; /* Or hardwired */
+ }
+
+ /* allocate MPU-401 resources */
+ pdev = acard->mpu;
- kfree(cfg);
+ err = pnp_activate_dev(pdev);
+ if (err < 0)
+ snd_printk(KERN_ERR "MPU-401 PnP configure failure: will be disabled\n");
+ else {
+ mpuport[dev] = pnp_port_start(pdev, 0);
+ mpuirq[dev] = pnp_irq(pdev, 0);
+ }
return 0;
}
#endif
@@ -391,7 +437,7 @@ static int snd_cmi8330_capture_open(struct snd_pcm_substream *substream)
return chip->streams[SNDRV_PCM_STREAM_CAPTURE].open(substream);
}
-static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip)
+static int snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip)
{
struct snd_pcm *pcm;
const struct snd_pcm_ops *ops;
@@ -401,9 +447,9 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *
snd_cmi8330_capture_open
};
- if ((err = snd_pcm_new(card, "CMI8330", 0, 1, 1, &pcm)) < 0)
+ if ((err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm)) < 0)
return err;
- strcpy(pcm->name, "CMI8330");
+ strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330");
pcm->private_data = chip;
/* SB16 */
@@ -414,7 +460,7 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *
chip->streams[CMI_SB_STREAM].private_data = chip->sb;
/* AD1848 */
- ops = snd_ad1848_get_pcm_ops(CMI_AD_STREAM);
+ ops = snd_wss_get_pcm_ops(CMI_AD_STREAM);
chip->streams[CMI_AD_STREAM].ops = *ops;
chip->streams[CMI_AD_STREAM].open = ops->open;
chip->streams[CMI_AD_STREAM].ops.open = cmi_open_callbacks[CMI_AD_STREAM];
@@ -468,39 +514,42 @@ static int snd_cmi8330_resume(struct snd_card *card)
#define PFX "cmi8330: "
-static struct snd_card *snd_cmi8330_card_new(int dev)
+static int snd_cmi8330_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
struct snd_cmi8330 *acard;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_cmi8330));
- if (card == NULL) {
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_cmi8330), &card);
+ if (err < 0) {
snd_printk(KERN_ERR PFX "could not get a new card\n");
- return NULL;
+ return err;
}
acard = card->private_data;
acard->card = card;
- return card;
+ *cardp = card;
+ return 0;
}
-static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
+static int snd_cmi8330_probe(struct snd_card *card, int dev)
{
struct snd_cmi8330 *acard;
int i, err;
+ struct snd_opl3 *opl3;
acard = card->private_data;
- if ((err = snd_ad1848_create(card,
- wssport[dev] + 4,
- wssirq[dev],
- wssdma[dev],
- AD1848_HW_DETECT,
- &acard->wss)) < 0) {
- snd_printk(KERN_ERR PFX "(AD1848) device busy??\n");
+ err = snd_wss_create(card, wssport[dev] + 4, -1,
+ wssirq[dev],
+ wssdma[dev], -1,
+ WSS_HW_DETECT, 0, &acard->wss);
+ if (err < 0) {
+ snd_printk(KERN_ERR PFX "AD1848 device busy??\n");
return err;
}
- if (acard->wss->hardware != AD1848_HW_CMI8330) {
- snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n");
+ if (acard->wss->hardware != WSS_HW_CMI8330) {
+ snd_printk(KERN_ERR PFX "AD1848 not found during probe\n");
return -ENODEV;
}
@@ -510,17 +559,18 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
sbdma8[dev],
sbdma16[dev],
SB_HW_AUTO, &acard->sb)) < 0) {
- snd_printk(KERN_ERR PFX "(SB16) device busy??\n");
+ snd_printk(KERN_ERR PFX "SB16 device busy??\n");
return err;
}
if (acard->sb->hardware != SB_HW_16) {
- snd_printk(KERN_ERR PFX "(SB16) not found during probe\n");
+ snd_printk(KERN_ERR PFX "SB16 not found during probe\n");
return err;
}
- snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */
+ snd_wss_out(acard->wss, CS4231_MISC_INFO, 0x40); /* switch on MODE2 */
for (i = CMI8330_RMUX3D; i <= CMI8330_CDINGAIN; i++)
- snd_ad1848_out(acard->wss, i, snd_cmi8330_image[i - CMI8330_RMUX3D]);
+ snd_wss_out(acard->wss, i,
+ snd_cmi8330_image[i - CMI8330_RMUX3D]);
if ((err = snd_cmi8330_mixer(card, acard)) < 0) {
snd_printk(KERN_ERR PFX "failed to create mixers\n");
@@ -531,9 +581,30 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
snd_printk(KERN_ERR PFX "failed to create pcms\n");
return err;
}
+ if (fmport[dev] != SNDRV_AUTO_PORT) {
+ if (snd_opl3_create(card,
+ fmport[dev], fmport[dev] + 2,
+ OPL3_HW_AUTO, 0, &opl3) < 0) {
+ snd_printk(KERN_ERR PFX
+ "no OPL device at 0x%lx-0x%lx ?\n",
+ fmport[dev], fmport[dev] + 2);
+ } else {
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ return err;
+ }
+ }
- strcpy(card->driver, "CMI8330/C3D");
- strcpy(card->shortname, "C-Media CMI8330/C3D");
+ if (mpuport[dev] != SNDRV_AUTO_PORT) {
+ if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpuport[dev], 0, mpuirq[dev],
+ NULL) < 0)
+ printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n",
+ mpuport[dev]);
+ }
+
+ strcpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
+ strcpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D");
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
card->shortname,
acard->wss->port,
@@ -543,70 +614,78 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
return snd_card_register(card);
}
-static int __init snd_cmi8330_nonpnp_probe(struct platform_device *pdev)
+static int snd_cmi8330_isa_match(struct device *pdev,
+ unsigned int dev)
{
- struct snd_card *card;
- int err;
- int dev = pdev->id;
-
+ if (!enable[dev] || is_isapnp_selected(dev))
+ return 0;
if (wssport[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR PFX "specify wssport\n");
- return -EINVAL;
+ return 0;
}
if (sbport[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR PFX "specify sbport\n");
- return -EINVAL;
+ return 0;
}
+ return 1;
+}
+
+static int snd_cmi8330_isa_probe(struct device *pdev,
+ unsigned int dev)
+{
+ struct snd_card *card;
+ int err;
- card = snd_cmi8330_card_new(dev);
- if (! card)
- return -ENOMEM;
- snd_card_set_dev(card, &pdev->dev);
+ err = snd_cmi8330_card_new(pdev, dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_cmi8330_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
}
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(pdev, card);
return 0;
}
-static int snd_cmi8330_nonpnp_remove(struct platform_device *devptr)
+static int snd_cmi8330_isa_remove(struct device *devptr,
+ unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
return 0;
}
#ifdef CONFIG_PM
-static int snd_cmi8330_nonpnp_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_cmi8330_isa_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
{
- return snd_cmi8330_suspend(platform_get_drvdata(dev));
+ return snd_cmi8330_suspend(dev_get_drvdata(dev));
}
-static int snd_cmi8330_nonpnp_resume(struct platform_device *dev)
+static int snd_cmi8330_isa_resume(struct device *dev, unsigned int n)
{
- return snd_cmi8330_resume(platform_get_drvdata(dev));
+ return snd_cmi8330_resume(dev_get_drvdata(dev));
}
#endif
-#define CMI8330_DRIVER "snd_cmi8330"
+#define DEV_NAME "cmi8330"
-static struct platform_driver snd_cmi8330_driver = {
- .probe = snd_cmi8330_nonpnp_probe,
- .remove = snd_cmi8330_nonpnp_remove,
+static struct isa_driver snd_cmi8330_driver = {
+ .match = snd_cmi8330_isa_match,
+ .probe = snd_cmi8330_isa_probe,
+ .remove = snd_cmi8330_isa_remove,
#ifdef CONFIG_PM
- .suspend = snd_cmi8330_nonpnp_suspend,
- .resume = snd_cmi8330_nonpnp_resume,
+ .suspend = snd_cmi8330_isa_suspend,
+ .resume = snd_cmi8330_isa_resume,
#endif
.driver = {
- .name = CMI8330_DRIVER
+ .name = DEV_NAME
},
};
#ifdef CONFIG_PNP
-static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
static int dev;
struct snd_card *card;
@@ -619,15 +698,14 @@ static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cmi8330_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_cmi8330_card_new(&pcard->card->dev, dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) {
snd_printk(KERN_ERR PFX "PnP detection failed\n");
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_cmi8330_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
@@ -637,7 +715,7 @@ static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
return 0;
}
-static void __devexit snd_cmi8330_pnp_remove(struct pnp_card_link * pcard)
+static void snd_cmi8330_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -660,7 +738,7 @@ static struct pnp_card_driver cmi8330_pnpc_driver = {
.name = "cmi8330",
.id_table = snd_cmi8330_pnpids,
.probe = snd_cmi8330_pnp_detect,
- .remove = __devexit_p(snd_cmi8330_pnp_remove),
+ .remove = snd_cmi8330_pnp_remove,
#ifdef CONFIG_PM
.suspend = snd_cmi8330_pnp_suspend,
.resume = snd_cmi8330_pnp_resume,
@@ -668,61 +746,34 @@ static struct pnp_card_driver cmi8330_pnpc_driver = {
};
#endif /* CONFIG_PNP */
-static void __init_or_module snd_cmi8330_unregister_all(void)
-{
- int i;
-
- if (pnp_registered)
- pnp_unregister_card_driver(&cmi8330_pnpc_driver);
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&snd_cmi8330_driver);
-}
-
static int __init alsa_card_cmi8330_init(void)
{
- int i, err, cards = 0;
-
- if ((err = platform_driver_register(&snd_cmi8330_driver)) < 0)
- return err;
+ int err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- if (is_isapnp_selected(i))
- continue;
- device = platform_device_register_simple(CMI8330_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- cards++;
- }
+ err = isa_register_driver(&snd_cmi8330_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+ if (!err)
+ isa_registered = 1;
err = pnp_register_card_driver(&cmi8330_pnpc_driver);
- if (err >= 0) {
+ if (!err)
pnp_registered = 1;
- cards += err;
- }
- if (!cards) {
-#ifdef MODULE
- snd_printk(KERN_ERR "CMI8330 not found or device busy\n");
+ if (isa_registered)
+ err = 0;
#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_cmi8330_unregister_all();
return err;
}
static void __exit alsa_card_cmi8330_exit(void)
{
- snd_cmi8330_unregister_all();
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&cmi8330_pnpc_driver);
+
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_cmi8330_driver);
}
module_init(alsa_card_cmi8330_init)
diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile
index d2afaea30cb..6d397e8d54a 100644
--- a/sound/isa/cs423x/Makefile
+++ b/sound/isa/cs423x/Makefile
@@ -1,25 +1,13 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-cs4231-lib-objs := cs4231_lib.o
-snd-cs4236-lib-objs := cs4236_lib.o
snd-cs4231-objs := cs4231.o
-snd-cs4232-objs := cs4232.o
-snd-cs4236-objs := cs4236.o
+snd-cs4236-objs := cs4236.o cs4236_lib.o
# Toplevel Module Dependency
-obj-$(CONFIG_SND_AZT2320) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_OPL3SA2) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_CS4231) += snd-cs4231.o snd-cs4231-lib.o
-obj-$(CONFIG_SND_CS4232) += snd-cs4232.o snd-cs4231-lib.o
-obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o snd-cs4231-lib.o
-obj-$(CONFIG_SND_GUSMAX) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_INTERWAVE) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_INTERWAVE_STB) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_WAVEFRONT) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_SSCAPE) += snd-cs4231-lib.o
+obj-$(CONFIG_SND_CS4231) += snd-cs4231.o
+obj-$(CONFIG_SND_CS4236) += snd-cs4236.o
+
-obj-m := $(sort $(obj-m))
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index ab67b5c2590..7dba07a4343 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -1,6 +1,6 @@
/*
* Generic driver for CS4231 chips
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Originally the CS4232/CS4232A driver, modified for use on CS4231 by
* Tugrul Galatali <galatalt@stuy.edu>
*
@@ -20,26 +20,28 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Generic CS4231");
+#define CRD_NAME "Generic CS4231"
+#define DEV_NAME "cs4231"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4231}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */
@@ -48,190 +50,152 @@ static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for CS4231 soundcard.");
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for CS4231 soundcard.");
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable CS4231 soundcard.");
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for CS4231 driver.");
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for CS4231 driver.");
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for CS4231 driver.");
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for CS4231 driver.");
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for CS4231 driver.");
+MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver.");
module_param_array(dma2, int, NULL, 0444);
-MODULE_PARM_DESC(dma2, "DMA2 # for CS4231 driver.");
+MODULE_PARM_DESC(dma2, "DMA2 # for " CRD_NAME " driver.");
-static struct platform_device *devices[SNDRV_CARDS];
+static int snd_cs4231_match(struct device *dev, unsigned int n)
+{
+ if (!enable[n])
+ return 0;
+ if (port[n] == SNDRV_AUTO_PORT) {
+ dev_err(dev, "please specify port\n");
+ return 0;
+ }
+ if (irq[n] == SNDRV_AUTO_IRQ) {
+ dev_err(dev, "please specify irq\n");
+ return 0;
+ }
+ if (dma1[n] == SNDRV_AUTO_DMA) {
+ dev_err(dev, "please specify dma1\n");
+ return 0;
+ }
+ return 1;
+}
-static int __init snd_cs4231_probe(struct platform_device *pdev)
+static int snd_cs4231_probe(struct device *dev, unsigned int n)
{
- int dev = pdev->id;
struct snd_card *card;
+ struct snd_wss *chip;
struct snd_pcm *pcm;
- struct snd_cs4231 *chip;
- int err;
+ int error;
+
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
+
+ error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
+ WSS_HW_DETECT, 0, &chip);
+ if (error < 0)
+ goto out;
- if (port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "specify port\n");
- return -EINVAL;
- }
- if (irq[dev] == SNDRV_AUTO_IRQ) {
- snd_printk(KERN_ERR "specify irq\n");
- return -EINVAL;
- }
- if (dma1[dev] == SNDRV_AUTO_DMA) {
- snd_printk(KERN_ERR "specify dma1\n");
- return -EINVAL;
- }
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
- if ((err = snd_cs4231_create(card, port[dev], -1,
- irq[dev],
- dma1[dev],
- dma2[dev],
- CS4231_HW_DETECT,
- 0, &chip)) < 0)
- goto _err;
card->private_data = chip;
- if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0)
- goto _err;
+ error = snd_wss_pcm(chip, 0, &pcm);
+ if (error < 0)
+ goto out;
strcpy(card->driver, "CS4231");
strcpy(card->shortname, pcm->name);
+
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
- pcm->name, chip->port, irq[dev], dma1[dev]);
- if (dma2[dev] >= 0)
- sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
-
- if ((err = snd_cs4231_mixer(chip)) < 0)
- goto _err;
- if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0)
- goto _err;
-
- if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
- if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
- mpu_irq[dev] = -1;
+ pcm->name, chip->port, irq[n], dma1[n]);
+ if (dma2[n] >= 0)
+ sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]);
+
+ error = snd_wss_mixer(chip);
+ if (error < 0)
+ goto out;
+
+ error = snd_wss_timer(chip, 0, NULL);
+ if (error < 0)
+ goto out;
+
+ if (mpu_port[n] > 0 && mpu_port[n] != SNDRV_AUTO_PORT) {
+ if (mpu_irq[n] == SNDRV_AUTO_IRQ)
+ mpu_irq[n] = -1;
if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232,
- mpu_port[dev], 0,
- mpu_irq[dev],
- mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0,
+ mpu_port[n], 0, mpu_irq[n],
NULL) < 0)
- printk(KERN_WARNING "cs4231: MPU401 not detected\n");
+ dev_warn(dev, "MPU401 not detected\n");
}
- snd_card_set_dev(card, &pdev->dev);
-
- if ((err = snd_card_register(card)) < 0)
- goto _err;
+ error = snd_card_register(card);
+ if (error < 0)
+ goto out;
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(dev, card);
return 0;
- _err:
- snd_card_free(card);
- return err;
+out: snd_card_free(card);
+ return error;
}
-static int __devexit snd_cs4231_remove(struct platform_device *devptr)
+static int snd_cs4231_remove(struct device *dev, unsigned int n)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(dev));
return 0;
}
#ifdef CONFIG_PM
-static int snd_cs4231_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t state)
{
- struct snd_card *card;
- struct snd_cs4231 *chip;
- card = platform_get_drvdata(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_wss *chip = card->private_data;
+
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- chip = card->private_data;
chip->suspend(chip);
return 0;
}
-static int snd_cs4231_resume(struct platform_device *dev)
+static int snd_cs4231_resume(struct device *dev, unsigned int n)
{
- struct snd_card *card;
- struct snd_cs4231 *chip;
- card = platform_get_drvdata(dev);
- chip = card->private_data;
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_wss *chip = card->private_data;
+
chip->resume(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif
-#define SND_CS4231_DRIVER "snd_cs4231"
-
-static struct platform_driver snd_cs4231_driver = {
+static struct isa_driver snd_cs4231_driver = {
+ .match = snd_cs4231_match,
.probe = snd_cs4231_probe,
- .remove = __devexit_p(snd_cs4231_remove),
+ .remove = snd_cs4231_remove,
#ifdef CONFIG_PM
.suspend = snd_cs4231_suspend,
.resume = snd_cs4231_resume,
#endif
.driver = {
- .name = SND_CS4231_DRIVER
- },
+ .name = DEV_NAME
+ }
};
-static void __init_or_module snd_cs4231_unregister_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_cs4231_driver);
-}
-
static int __init alsa_card_cs4231_init(void)
{
- int i, cards, err;
-
- err = platform_driver_register(&snd_cs4231_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(SND_CS4231_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
- }
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR "CS4231 soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_cs4231_unregister_all();
- return err;
+ return isa_register_driver(&snd_cs4231_driver, SNDRV_CARDS);
}
static void __exit alsa_card_cs4231_exit(void)
{
- snd_cs4231_unregister_all();
+ isa_unregister_driver(&snd_cs4231_driver);
}
-module_init(alsa_card_cs4231_init)
-module_exit(alsa_card_cs4231_exit)
+module_init(alsa_card_cs4231_init);
+module_exit(alsa_card_cs4231_exit);
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
deleted file mode 100644
index eab7eb59b5f..00000000000
--- a/sound/isa/cs423x/cs4231_lib.c
+++ /dev/null
@@ -1,1858 +0,0 @@
-/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips
- *
- * Bugs:
- * - sometimes record brokes playback with WSS portion of
- * Yamaha OPL3-SA3 chip
- * - CS4231 (GUS MAX) - still trouble with occasional noises
- * - broken initialization?
- *
- * 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 <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <sound/core.h>
-#include <sound/cs4231.h>
-#include <sound/pcm_params.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
-MODULE_LICENSE("GPL");
-
-#if 0
-#define SNDRV_DEBUG_MCE
-#endif
-
-/*
- * Some variables
- */
-
-static unsigned char freq_bits[14] = {
- /* 5510 */ 0x00 | CS4231_XTAL2,
- /* 6620 */ 0x0E | CS4231_XTAL2,
- /* 8000 */ 0x00 | CS4231_XTAL1,
- /* 9600 */ 0x0E | CS4231_XTAL1,
- /* 11025 */ 0x02 | CS4231_XTAL2,
- /* 16000 */ 0x02 | CS4231_XTAL1,
- /* 18900 */ 0x04 | CS4231_XTAL2,
- /* 22050 */ 0x06 | CS4231_XTAL2,
- /* 27042 */ 0x04 | CS4231_XTAL1,
- /* 32000 */ 0x06 | CS4231_XTAL1,
- /* 33075 */ 0x0C | CS4231_XTAL2,
- /* 37800 */ 0x08 | CS4231_XTAL2,
- /* 44100 */ 0x0A | CS4231_XTAL2,
- /* 48000 */ 0x0C | CS4231_XTAL1
-};
-
-static unsigned int rates[14] = {
- 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
- 27042, 32000, 33075, 37800, 44100, 48000
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
- .count = 14,
- .list = rates,
- .mask = 0,
-};
-
-static int snd_cs4231_xrate(struct snd_pcm_runtime *runtime)
-{
- return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-}
-
-static unsigned char snd_cs4231_original_image[32] =
-{
- 0x00, /* 00/00 - lic */
- 0x00, /* 01/01 - ric */
- 0x9f, /* 02/02 - la1ic */
- 0x9f, /* 03/03 - ra1ic */
- 0x9f, /* 04/04 - la2ic */
- 0x9f, /* 05/05 - ra2ic */
- 0xbf, /* 06/06 - loc */
- 0xbf, /* 07/07 - roc */
- 0x20, /* 08/08 - pdfr */
- CS4231_AUTOCALIB, /* 09/09 - ic */
- 0x00, /* 0a/10 - pc */
- 0x00, /* 0b/11 - ti */
- CS4231_MODE2, /* 0c/12 - mi */
- 0xfc, /* 0d/13 - lbc */
- 0x00, /* 0e/14 - pbru */
- 0x00, /* 0f/15 - pbrl */
- 0x80, /* 10/16 - afei */
- 0x01, /* 11/17 - afeii */
- 0x9f, /* 12/18 - llic */
- 0x9f, /* 13/19 - rlic */
- 0x00, /* 14/20 - tlb */
- 0x00, /* 15/21 - thb */
- 0x00, /* 16/22 - la3mic/reserved */
- 0x00, /* 17/23 - ra3mic/reserved */
- 0x00, /* 18/24 - afs */
- 0x00, /* 19/25 - lamoc/version */
- 0xcf, /* 1a/26 - mioc */
- 0x00, /* 1b/27 - ramoc/reserved */
- 0x20, /* 1c/28 - cdfr */
- 0x00, /* 1d/29 - res4 */
- 0x00, /* 1e/30 - cbru */
- 0x00, /* 1f/31 - cbrl */
-};
-
-/*
- * Basic I/O functions
- */
-
-static inline void cs4231_outb(struct snd_cs4231 *chip, u8 offset, u8 val)
-{
- outb(val, chip->port + offset);
-}
-
-static inline u8 cs4231_inb(struct snd_cs4231 *chip, u8 offset)
-{
- return inb(chip->port + offset);
-}
-
-static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg,
- unsigned char mask, unsigned char value)
-{
- int timeout;
- unsigned char tmp;
-
- for (timeout = 250;
- timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
- timeout--)
- udelay(100);
-#ifdef CONFIG_SND_DEBUG
- if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
- if (chip->calibrate_mute) {
- chip->image[reg] &= mask;
- chip->image[reg] |= value;
- } else {
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
- mb();
- tmp = (chip->image[reg] & mask) | value;
- cs4231_outb(chip, CS4231P(REG), tmp);
- chip->image[reg] = tmp;
- mb();
- }
-}
-
-static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned char value)
-{
- int timeout;
-
- for (timeout = 250;
- timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
- timeout--)
- udelay(10);
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
- cs4231_outb(chip, CS4231P(REG), value);
- mb();
-}
-
-void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value)
-{
- int timeout;
-
- for (timeout = 250;
- timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
- timeout--)
- udelay(100);
-#ifdef CONFIG_SND_DEBUG
- if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
- cs4231_outb(chip, CS4231P(REG), value);
- chip->image[reg] = value;
- mb();
-#if 0
- printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);
-#endif
-}
-
-unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg)
-{
- int timeout;
-
- for (timeout = 250;
- timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
- timeout--)
- udelay(100);
-#ifdef CONFIG_SND_DEBUG
- if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
-#endif
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
- mb();
- return cs4231_inb(chip, CS4231P(REG));
-}
-
-void snd_cs4236_ext_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val)
-{
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
- cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
- cs4231_outb(chip, CS4231P(REG), val);
- chip->eimage[CS4236_REG(reg)] = val;
-#if 0
- printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
-#endif
-}
-
-unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg)
-{
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
- cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
-#if 1
- return cs4231_inb(chip, CS4231P(REG));
-#else
- {
- unsigned char res;
- res = cs4231_inb(chip, CS4231P(REG));
- printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
- return res;
- }
-#endif
-}
-
-#if 0
-
-static void snd_cs4231_debug(struct snd_cs4231 *chip)
-{
- printk("CS4231 REGS: INDEX = 0x%02x ", cs4231_inb(chip, CS4231P(REGSEL)));
- printk(" STATUS = 0x%02x\n", cs4231_inb(chip, CS4231P(STATUS)));
- printk(" 0x00: left input = 0x%02x ", snd_cs4231_in(chip, 0x00));
- printk(" 0x10: alt 1 (CFIG 2) = 0x%02x\n", snd_cs4231_in(chip, 0x10));
- printk(" 0x01: right input = 0x%02x ", snd_cs4231_in(chip, 0x01));
- printk(" 0x11: alt 2 (CFIG 3) = 0x%02x\n", snd_cs4231_in(chip, 0x11));
- printk(" 0x02: GF1 left input = 0x%02x ", snd_cs4231_in(chip, 0x02));
- printk(" 0x12: left line in = 0x%02x\n", snd_cs4231_in(chip, 0x12));
- printk(" 0x03: GF1 right input = 0x%02x ", snd_cs4231_in(chip, 0x03));
- printk(" 0x13: right line in = 0x%02x\n", snd_cs4231_in(chip, 0x13));
- printk(" 0x04: CD left input = 0x%02x ", snd_cs4231_in(chip, 0x04));
- printk(" 0x14: timer low = 0x%02x\n", snd_cs4231_in(chip, 0x14));
- printk(" 0x05: CD right input = 0x%02x ", snd_cs4231_in(chip, 0x05));
- printk(" 0x15: timer high = 0x%02x\n", snd_cs4231_in(chip, 0x15));
- printk(" 0x06: left output = 0x%02x ", snd_cs4231_in(chip, 0x06));
- printk(" 0x16: left MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x16));
- printk(" 0x07: right output = 0x%02x ", snd_cs4231_in(chip, 0x07));
- printk(" 0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));
- printk(" 0x08: playback format = 0x%02x ", snd_cs4231_in(chip, 0x08));
- printk(" 0x18: IRQ status = 0x%02x\n", snd_cs4231_in(chip, 0x18));
- printk(" 0x09: iface (CFIG 1) = 0x%02x ", snd_cs4231_in(chip, 0x09));
- printk(" 0x19: left line out = 0x%02x\n", snd_cs4231_in(chip, 0x19));
- printk(" 0x0a: pin control = 0x%02x ", snd_cs4231_in(chip, 0x0a));
- printk(" 0x1a: mono control = 0x%02x\n", snd_cs4231_in(chip, 0x1a));
- printk(" 0x0b: init & status = 0x%02x ", snd_cs4231_in(chip, 0x0b));
- printk(" 0x1b: right line out = 0x%02x\n", snd_cs4231_in(chip, 0x1b));
- printk(" 0x0c: revision & mode = 0x%02x ", snd_cs4231_in(chip, 0x0c));
- printk(" 0x1c: record format = 0x%02x\n", snd_cs4231_in(chip, 0x1c));
- printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d));
- printk(" 0x1d: var freq (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x1d));
- printk(" 0x0e: ply upr count = 0x%02x ", snd_cs4231_in(chip, 0x0e));
- printk(" 0x1e: ply lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
- printk(" 0x0f: rec upr count = 0x%02x ", snd_cs4231_in(chip, 0x0f));
- printk(" 0x1f: rec lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1f));
-}
-
-#endif
-
-/*
- * CS4231 detection / MCE routines
- */
-
-static void snd_cs4231_busy_wait(struct snd_cs4231 *chip)
-{
- int timeout;
-
- /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
- for (timeout = 5; timeout > 0; timeout--)
- cs4231_inb(chip, CS4231P(REGSEL));
- /* end of cleanup sequence */
- for (timeout = 250;
- timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
- timeout--)
- udelay(10);
-}
-
-void snd_cs4231_mce_up(struct snd_cs4231 *chip)
-{
- unsigned long flags;
- int timeout;
-
- for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--)
- udelay(100);
-#ifdef CONFIG_SND_DEBUG
- if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("mce_up - auto calibration time out (0)\n");
-#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->mce_bit |= CS4231_MCE;
- timeout = cs4231_inb(chip, CS4231P(REGSEL));
- if (timeout == 0x80)
- snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
- if (!(timeout & CS4231_MCE))
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-void snd_cs4231_mce_down(struct snd_cs4231 *chip)
-{
- unsigned long flags;
- int timeout;
-
- snd_cs4231_busy_wait(chip);
-#if 0
- printk("(1) timeout = %i\n", timeout);
-#endif
-#ifdef CONFIG_SND_DEBUG
- if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
-#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->mce_bit &= ~CS4231_MCE;
- timeout = cs4231_inb(chip, CS4231P(REGSEL));
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (timeout == 0x80)
- snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
- if ((timeout & CS4231_MCE) == 0 ||
- !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
- return;
- }
- snd_cs4231_busy_wait(chip);
-
- /* calibration process */
-
- for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--)
- udelay(10);
- if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) {
- snd_printd("cs4231_mce_down - auto calibration time out (1)\n");
- return;
- }
-#if 0
- printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);
-#endif
- /* in 10 ms increments, check condition, up to 250 ms */
- timeout = 25;
- while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) {
- if (--timeout < 0) {
- snd_printk("mce_down - auto calibration time out (2)\n");
- return;
- }
- msleep(10);
- }
-#if 0
- printk("(3) jiffies = %li\n", jiffies);
-#endif
- /* in 10 ms increments, check condition, up to 100 ms */
- timeout = 10;
- while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
- if (--timeout < 0) {
- snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
- return;
- }
- msleep(10);
- }
-#if 0
- printk("(4) jiffies = %li\n", jiffies);
- snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL)));
-#endif
-}
-
-static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
-{
- switch (format & 0xe0) {
- case CS4231_LINEAR_16:
- case CS4231_LINEAR_16_BIG:
- size >>= 1;
- break;
- case CS4231_ADPCM_16:
- return size >> 2;
- }
- if (format & CS4231_STEREO)
- size >>= 1;
- return size;
-}
-
-static int snd_cs4231_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- int result = 0;
- unsigned int what;
- struct list_head *pos;
- struct snd_pcm_substream *s;
- int do_start;
-
-#if 0
- printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS)));
-#endif
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- do_start = 1; break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- do_start = 0; break;
- default:
- return -EINVAL;
- }
-
- what = 0;
- snd_pcm_group_for_each(pos, substream) {
- s = snd_pcm_group_substream_entry(pos);
- if (s == chip->playback_substream) {
- what |= CS4231_PLAYBACK_ENABLE;
- snd_pcm_trigger_done(s, substream);
- } else if (s == chip->capture_substream) {
- what |= CS4231_RECORD_ENABLE;
- snd_pcm_trigger_done(s, substream);
- }
- }
- spin_lock(&chip->reg_lock);
- if (do_start) {
- chip->image[CS4231_IFACE_CTRL] |= what;
- if (chip->trigger)
- chip->trigger(chip, what, 1);
- } else {
- chip->image[CS4231_IFACE_CTRL] &= ~what;
- if (chip->trigger)
- chip->trigger(chip, what, 0);
- }
- snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
- spin_unlock(&chip->reg_lock);
-#if 0
- snd_cs4231_debug(chip);
-#endif
- return result;
-}
-
-/*
- * CODEC I/O
- */
-
-static unsigned char snd_cs4231_get_rate(unsigned int rate)
-{
- int i;
-
- for (i = 0; i < 14; i++)
- if (rate == rates[i])
- return freq_bits[i];
- // snd_BUG();
- return freq_bits[13];
-}
-
-static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip,
- int format,
- int channels)
-{
- unsigned char rformat;
-
- rformat = CS4231_LINEAR_8;
- switch (format) {
- case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break;
- case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break;
- case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break;
- case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break;
- case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break;
- }
- if (channels > 1)
- rformat |= CS4231_STEREO;
-#if 0
- snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
-#endif
- return rformat;
-}
-
-static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute)
-{
- unsigned long flags;
-
- mute = mute ? 1 : 0;
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (chip->calibrate_mute == mute) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return;
- }
- if (!mute) {
- snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]);
- snd_cs4231_dout(chip, CS4231_RIGHT_INPUT, chip->image[CS4231_RIGHT_INPUT]);
- snd_cs4231_dout(chip, CS4231_LOOPBACK, chip->image[CS4231_LOOPBACK]);
- }
- snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
- snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
- snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
- snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
- snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
- snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
- snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN, mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
- snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN, mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
- snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
- if (chip->hardware == CS4231_HW_INTERWAVE) {
- snd_cs4231_dout(chip, CS4231_LEFT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]);
- snd_cs4231_dout(chip, CS4231_RIGHT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_MIC_INPUT]);
- snd_cs4231_dout(chip, CS4231_LINE_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_LEFT_OUTPUT]);
- snd_cs4231_dout(chip, CS4231_LINE_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_RIGHT_OUTPUT]);
- }
- chip->calibrate_mute = mute;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-static void snd_cs4231_playback_format(struct snd_cs4231 *chip,
- struct snd_pcm_hw_params *params,
- unsigned char pdfr)
-{
- unsigned long flags;
- int full_calib = 1;
-
- down(&chip->mce_mutex);
- snd_cs4231_calibrate_mute(chip, 1);
- if (chip->hardware == CS4231_HW_CS4231A ||
- (chip->hardware & CS4231_HW_CS4232_MASK)) {
- spin_lock_irqsave(&chip->reg_lock, flags);
- if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) { /* rate is same? */
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
- snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);
- udelay(100); /* Fixes audible clicks at least on GUS MAX */
- full_calib = 0;
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- }
- if (full_calib) {
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (chip->hardware != CS4231_HW_INTERWAVE && !chip->single_dma) {
- snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
- (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?
- (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :
- pdfr);
- } else {
- snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr);
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
- }
- snd_cs4231_calibrate_mute(chip, 0);
- up(&chip->mce_mutex);
-}
-
-static void snd_cs4231_capture_format(struct snd_cs4231 *chip,
- struct snd_pcm_hw_params *params,
- unsigned char cdfr)
-{
- unsigned long flags;
- int full_calib = 1;
-
- down(&chip->mce_mutex);
- snd_cs4231_calibrate_mute(chip, 1);
- if (chip->hardware == CS4231_HW_CS4231A ||
- (chip->hardware & CS4231_HW_CS4232_MASK)) {
- spin_lock_irqsave(&chip->reg_lock, flags);
- if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) || /* rate is same? */
- (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
- snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT] = cdfr);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
- full_calib = 0;
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- }
- if (full_calib) {
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (chip->hardware != CS4231_HW_INTERWAVE) {
- if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
- snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
- ((chip->single_dma ? cdfr : chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |
- (cdfr & 0x0f));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- }
- }
- snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
- }
- snd_cs4231_calibrate_mute(chip, 0);
- up(&chip->mce_mutex);
-}
-
-/*
- * Timer interface
- */
-
-static unsigned long snd_cs4231_timer_resolution(struct snd_timer * timer)
-{
- struct snd_cs4231 *chip = snd_timer_chip(timer);
- if (chip->hardware & CS4231_HW_CS4236B_MASK)
- return 14467;
- else
- return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
-}
-
-static int snd_cs4231_timer_start(struct snd_timer * timer)
-{
- unsigned long flags;
- unsigned int ticks;
- struct snd_cs4231 *chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->reg_lock, flags);
- ticks = timer->sticks;
- if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
- (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
- (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
- snd_cs4231_out(chip, CS4231_TIMER_HIGH, chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8));
- snd_cs4231_out(chip, CS4231_TIMER_LOW, chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE);
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
-}
-
-static int snd_cs4231_timer_stop(struct snd_timer * timer)
-{
- unsigned long flags;
- struct snd_cs4231 *chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
-}
-
-static void snd_cs4231_init(struct snd_cs4231 *chip)
-{
- unsigned long flags;
-
- snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (1)\n");
-#endif
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
- CS4231_RECORD_ENABLE | CS4231_RECORD_PIO |
- CS4231_CALIB_MODE);
- chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
- snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (2)\n");
-#endif
-
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
-#endif
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (4)\n");
-#endif
-
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
-
-#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (5)\n");
-#endif
-}
-
-static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode)
-{
- unsigned long flags;
-
- down(&chip->open_mutex);
- if ((chip->mode & mode) ||
- ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) {
- up(&chip->open_mutex);
- return -EAGAIN;
- }
- if (chip->mode & CS4231_MODE_OPEN) {
- chip->mode |= mode;
- up(&chip->open_mutex);
- return 0;
- }
- /* ok. now enable and ack CODEC IRQ */
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
- CS4231_RECORD_IRQ |
- CS4231_TIMER_IRQ);
- snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
- cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
- cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
- chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
- snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
- snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
- CS4231_RECORD_IRQ |
- CS4231_TIMER_IRQ);
- snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- chip->mode = mode;
- up(&chip->open_mutex);
- return 0;
-}
-
-static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode)
-{
- unsigned long flags;
-
- down(&chip->open_mutex);
- chip->mode &= ~mode;
- if (chip->mode & CS4231_MODE_OPEN) {
- up(&chip->open_mutex);
- return;
- }
- snd_cs4231_calibrate_mute(chip, 1);
-
- /* disable IRQ */
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
- cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
- cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
- chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
- snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
-
- /* now disable record & playback */
-
- if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
- CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
- CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
- snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- }
-
- /* clear IRQ again */
- snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
- cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
- cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- snd_cs4231_calibrate_mute(chip, 0);
-
- chip->mode = 0;
- up(&chip->open_mutex);
-}
-
-/*
- * timer open/close
- */
-
-static int snd_cs4231_timer_open(struct snd_timer * timer)
-{
- struct snd_cs4231 *chip = snd_timer_chip(timer);
- snd_cs4231_open(chip, CS4231_MODE_TIMER);
- return 0;
-}
-
-static int snd_cs4231_timer_close(struct snd_timer * timer)
-{
- struct snd_cs4231 *chip = snd_timer_chip(timer);
- snd_cs4231_close(chip, CS4231_MODE_TIMER);
- return 0;
-}
-
-static struct snd_timer_hardware snd_cs4231_timer_table =
-{
- .flags = SNDRV_TIMER_HW_AUTO,
- .resolution = 9945,
- .ticks = 65535,
- .open = snd_cs4231_timer_open,
- .close = snd_cs4231_timer_close,
- .c_resolution = snd_cs4231_timer_resolution,
- .start = snd_cs4231_timer_start,
- .stop = snd_cs4231_timer_stop,
-};
-
-/*
- * ok.. exported functions..
- */
-
-static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- unsigned char new_pdfr;
- int err;
-
- if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
- return err;
- new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
- snd_cs4231_get_rate(params_rate(hw_params));
- chip->set_playback_format(chip, hw_params, new_pdfr);
- return 0;
-}
-
-static int snd_cs4231_playback_hw_free(struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- unsigned int size = snd_pcm_lib_buffer_bytes(substream);
- unsigned int count = snd_pcm_lib_period_bytes(substream);
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->p_dma_size = size;
- chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
- snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
- count = snd_cs4231_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
- snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
- snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-#if 0
- snd_cs4231_debug(chip);
-#endif
- return 0;
-}
-
-static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- unsigned char new_cdfr;
- int err;
-
- if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
- return err;
- new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) |
- snd_cs4231_get_rate(params_rate(hw_params));
- chip->set_capture_format(chip, hw_params, new_cdfr);
- return 0;
-}
-
-static int snd_cs4231_capture_hw_free(struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- unsigned int size = snd_pcm_lib_buffer_bytes(substream);
- unsigned int count = snd_pcm_lib_period_bytes(substream);
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->c_dma_size = size;
- chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
- snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
- count = snd_cs4231_get_count(chip->image[CS4231_REC_FORMAT], count) - 1;
- if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
- snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
- snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
- } else {
- snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
- snd_cs4231_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8));
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
-}
-
-static void snd_cs4231_overrange(struct snd_cs4231 *chip)
-{
- unsigned long flags;
- unsigned char res;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- res = snd_cs4231_in(chip, CS4231_TEST_INIT);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */
- chip->capture_substream->runtime->overrange++;
-}
-
-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct snd_cs4231 *chip = dev_id;
- unsigned char status;
-
- status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
- if (status & CS4231_TIMER_IRQ) {
- if (chip->timer)
- snd_timer_interrupt(chip->timer, chip->timer->sticks);
- }
- if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) {
- if (status & CS4231_PLAYBACK_IRQ) {
- if (chip->mode & CS4231_MODE_PLAY) {
- if (chip->playback_substream)
- snd_pcm_period_elapsed(chip->playback_substream);
- }
- if (chip->mode & CS4231_MODE_RECORD) {
- if (chip->capture_substream) {
- snd_cs4231_overrange(chip);
- snd_pcm_period_elapsed(chip->capture_substream);
- }
- }
- }
- } else {
- if (status & CS4231_PLAYBACK_IRQ) {
- if (chip->playback_substream)
- snd_pcm_period_elapsed(chip->playback_substream);
- }
- if (status & CS4231_RECORD_IRQ) {
- if (chip->capture_substream) {
- snd_cs4231_overrange(chip);
- snd_pcm_period_elapsed(chip->capture_substream);
- }
- }
- }
-
- spin_lock(&chip->reg_lock);
- snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
- spin_unlock(&chip->reg_lock);
- return IRQ_HANDLED;
-}
-
-static snd_pcm_uframes_t snd_cs4231_playback_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- size_t ptr;
-
- if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
- return 0;
- ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
- return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_cs4231_capture_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- size_t ptr;
-
- if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
- return 0;
- ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
- return bytes_to_frames(substream->runtime, ptr);
-}
-
-/*
-
- */
-
-static int snd_cs4231_probe(struct snd_cs4231 *chip)
-{
- unsigned long flags;
- int i, id, rev;
- unsigned char *ptr;
- unsigned int hw;
-
-#if 0
- snd_cs4231_debug(chip);
-#endif
- id = 0;
- for (i = 0; i < 50; i++) {
- mb();
- if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- udelay(2000);
- else {
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
- id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (id == 0x0a)
- break; /* this is valid value */
- }
- }
- snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id);
- if (id != 0x0a)
- return -ENODEV; /* no valid device found */
-
- if (((hw = chip->hardware) & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
- rev = snd_cs4231_in(chip, CS4231_VERSION) & 0xe7;
- snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
- if (rev == 0x80) {
- unsigned char tmp = snd_cs4231_in(chip, 23);
- snd_cs4231_out(chip, 23, ~tmp);
- if (snd_cs4231_in(chip, 23) != tmp)
- chip->hardware = CS4231_HW_AD1845;
- else
- chip->hardware = CS4231_HW_CS4231;
- } else if (rev == 0xa0) {
- chip->hardware = CS4231_HW_CS4231A;
- } else if (rev == 0xa2) {
- chip->hardware = CS4231_HW_CS4232;
- } else if (rev == 0xb2) {
- chip->hardware = CS4231_HW_CS4232A;
- } else if (rev == 0x83) {
- chip->hardware = CS4231_HW_CS4236;
- } else if (rev == 0x03) {
- chip->hardware = CS4231_HW_CS4236B;
- } else {
- snd_printk("unknown CS chip with version 0x%x\n", rev);
- return -ENODEV; /* unknown CS4231 chip? */
- }
- }
- spin_lock_irqsave(&chip->reg_lock, flags);
- cs4231_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */
- cs4231_outb(chip, CS4231P(STATUS), 0);
- mb();
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
- switch (chip->hardware) {
- case CS4231_HW_INTERWAVE:
- chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
- break;
- case CS4231_HW_CS4235:
- case CS4231_HW_CS4236B:
- case CS4231_HW_CS4237B:
- case CS4231_HW_CS4238B:
- case CS4231_HW_CS4239:
- if (hw == CS4231_HW_DETECT3)
- chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;
- else
- chip->hardware = CS4231_HW_CS4236;
- break;
- }
-
- chip->image[CS4231_IFACE_CTRL] =
- (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
- (chip->single_dma ? CS4231_SINGLE_DMA : 0);
- chip->image[CS4231_ALT_FEATURE_1] = 0x80;
- chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01;
- ptr = (unsigned char *) &chip->image;
- snd_cs4231_mce_down(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */
- snd_cs4231_out(chip, i, *ptr++);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_up(chip);
- snd_cs4231_mce_down(chip);
-
- mdelay(2);
-
- /* ok.. try check hardware version for CS4236+ chips */
- if ((hw & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {
- if (chip->hardware == CS4231_HW_CS4236B) {
- rev = snd_cs4236_ext_in(chip, CS4236_VERSION);
- snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
- id = snd_cs4236_ext_in(chip, CS4236_VERSION);
- snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
- snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
- if ((id & 0x1f) == 0x1d) { /* CS4235 */
- chip->hardware = CS4231_HW_CS4235;
- switch (id >> 5) {
- case 4:
- case 5:
- case 6:
- break;
- default:
- snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
- }
- } else if ((id & 0x1f) == 0x0b) { /* CS4236/B */
- switch (id >> 5) {
- case 4:
- case 5:
- case 6:
- case 7:
- chip->hardware = CS4231_HW_CS4236B;
- break;
- default:
- snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
- }
- } else if ((id & 0x1f) == 0x08) { /* CS4237B */
- chip->hardware = CS4231_HW_CS4237B;
- switch (id >> 5) {
- case 4:
- case 5:
- case 6:
- case 7:
- break;
- default:
- snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
- }
- } else if ((id & 0x1f) == 0x09) { /* CS4238B */
- chip->hardware = CS4231_HW_CS4238B;
- switch (id >> 5) {
- case 5:
- case 6:
- case 7:
- break;
- default:
- snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
- }
- } else if ((id & 0x1f) == 0x1e) { /* CS4239 */
- chip->hardware = CS4231_HW_CS4239;
- switch (id >> 5) {
- case 4:
- case 5:
- case 6:
- break;
- default:
- snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
- }
- } else {
- snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
- }
- }
- }
- return 0; /* all things are ok.. */
-}
-
-/*
-
- */
-
-static struct snd_pcm_hardware snd_cs4231_playback =
-{
- .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_SYNC_START),
- .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
- SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
- .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 5510,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = (128*1024),
- .period_bytes_min = 64,
- .period_bytes_max = (128*1024),
- .periods_min = 1,
- .periods_max = 1024,
- .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware snd_cs4231_capture =
-{
- .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_SYNC_START),
- .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
- SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
- .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 5510,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = (128*1024),
- .period_bytes_min = 64,
- .period_bytes_max = (128*1024),
- .periods_min = 1,
- .periods_max = 1024,
- .fifo_size = 0,
-};
-
-/*
-
- */
-
-static int snd_cs4231_playback_open(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- runtime->hw = snd_cs4231_playback;
-
- /* hardware bug in InterWave chipset */
- if (chip->hardware == CS4231_HW_INTERWAVE && chip->dma1 > 3)
- runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
-
- /* hardware limitation of cheap chips */
- if (chip->hardware == CS4231_HW_CS4235 ||
- chip->hardware == CS4231_HW_CS4239)
- runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
-
- snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
- snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
-
- if (chip->claim_dma) {
- if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
- return err;
- }
-
- if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {
- if (chip->release_dma)
- chip->release_dma(chip, chip->dma_private_data, chip->dma1);
- snd_free_pages(runtime->dma_area, runtime->dma_bytes);
- return err;
- }
- chip->playback_substream = substream;
- snd_pcm_set_sync(substream);
- chip->rate_constraint(runtime);
- return 0;
-}
-
-static int snd_cs4231_capture_open(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- runtime->hw = snd_cs4231_capture;
-
- /* hardware limitation of cheap chips */
- if (chip->hardware == CS4231_HW_CS4235 ||
- chip->hardware == CS4231_HW_CS4239)
- runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
-
- snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
- snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
-
- if (chip->claim_dma) {
- if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
- return err;
- }
-
- if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {
- if (chip->release_dma)
- chip->release_dma(chip, chip->dma_private_data, chip->dma2);
- snd_free_pages(runtime->dma_area, runtime->dma_bytes);
- return err;
- }
- chip->capture_substream = substream;
- snd_pcm_set_sync(substream);
- chip->rate_constraint(runtime);
- return 0;
-}
-
-static int snd_cs4231_playback_close(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-
- chip->playback_substream = NULL;
- snd_cs4231_close(chip, CS4231_MODE_PLAY);
- return 0;
-}
-
-static int snd_cs4231_capture_close(struct snd_pcm_substream *substream)
-{
- struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
-
- chip->capture_substream = NULL;
- snd_cs4231_close(chip, CS4231_MODE_RECORD);
- return 0;
-}
-
-#ifdef CONFIG_PM
-
-/* lowlevel suspend callback for CS4231 */
-static void snd_cs4231_suspend(struct snd_cs4231 *chip)
-{
- int reg;
- unsigned long flags;
-
- snd_pcm_suspend_all(chip->pcm);
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (reg = 0; reg < 32; reg++)
- chip->image[reg] = snd_cs4231_in(chip, reg);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/* lowlevel resume callback for CS4231 */
-static void snd_cs4231_resume(struct snd_cs4231 *chip)
-{
- int reg;
- unsigned long flags;
- /* int timeout; */
-
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (reg = 0; reg < 32; reg++) {
- switch (reg) {
- case CS4231_VERSION:
- break;
- default:
- snd_cs4231_out(chip, reg, chip->image[reg]);
- break;
- }
- }
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-#if 1
- snd_cs4231_mce_down(chip);
-#else
- /* The following is a workaround to avoid freeze after resume on TP600E.
- This is the first half of copy of snd_cs4231_mce_down(), but doesn't
- include rescheduling. -- iwai
- */
- snd_cs4231_busy_wait(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->mce_bit &= ~CS4231_MCE;
- timeout = cs4231_inb(chip, CS4231P(REGSEL));
- cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (timeout == 0x80)
- snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
- if ((timeout & CS4231_MCE) == 0 ||
- !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
- return;
- }
- snd_cs4231_busy_wait(chip);
-#endif
-}
-#endif /* CONFIG_PM */
-
-static int snd_cs4231_free(struct snd_cs4231 *chip)
-{
- release_and_free_resource(chip->res_port);
- release_and_free_resource(chip->res_cport);
- if (chip->irq >= 0) {
- disable_irq(chip->irq);
- if (!(chip->hwshare & CS4231_HWSHARE_IRQ))
- free_irq(chip->irq, (void *) chip);
- }
- if (!(chip->hwshare & CS4231_HWSHARE_DMA1) && chip->dma1 >= 0) {
- snd_dma_disable(chip->dma1);
- free_dma(chip->dma1);
- }
- if (!(chip->hwshare & CS4231_HWSHARE_DMA2) && chip->dma2 >= 0 && chip->dma2 != chip->dma1) {
- snd_dma_disable(chip->dma2);
- free_dma(chip->dma2);
- }
- if (chip->timer)
- snd_device_free(chip->card, chip->timer);
- kfree(chip);
- return 0;
-}
-
-static int snd_cs4231_dev_free(struct snd_device *device)
-{
- struct snd_cs4231 *chip = device->device_data;
- return snd_cs4231_free(chip);
-}
-
-const char *snd_cs4231_chip_id(struct snd_cs4231 *chip)
-{
- switch (chip->hardware) {
- case CS4231_HW_CS4231: return "CS4231";
- case CS4231_HW_CS4231A: return "CS4231A";
- case CS4231_HW_CS4232: return "CS4232";
- case CS4231_HW_CS4232A: return "CS4232A";
- case CS4231_HW_CS4235: return "CS4235";
- case CS4231_HW_CS4236: return "CS4236";
- case CS4231_HW_CS4236B: return "CS4236B";
- case CS4231_HW_CS4237B: return "CS4237B";
- case CS4231_HW_CS4238B: return "CS4238B";
- case CS4231_HW_CS4239: return "CS4239";
- case CS4231_HW_INTERWAVE: return "AMD InterWave";
- case CS4231_HW_OPL3SA2: return chip->card->shortname;
- case CS4231_HW_AD1845: return "AD1845";
- default: return "???";
- }
-}
-
-static int snd_cs4231_new(struct snd_card *card,
- unsigned short hardware,
- unsigned short hwshare,
- struct snd_cs4231 ** rchip)
-{
- struct snd_cs4231 *chip;
-
- *rchip = NULL;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
- chip->hardware = hardware;
- chip->hwshare = hwshare;
-
- spin_lock_init(&chip->reg_lock);
- init_MUTEX(&chip->mce_mutex);
- init_MUTEX(&chip->open_mutex);
- chip->card = card;
- chip->rate_constraint = snd_cs4231_xrate;
- chip->set_playback_format = snd_cs4231_playback_format;
- chip->set_capture_format = snd_cs4231_capture_format;
- memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image));
-
- *rchip = chip;
- return 0;
-}
-
-int snd_cs4231_create(struct snd_card *card,
- unsigned long port,
- unsigned long cport,
- int irq, int dma1, int dma2,
- unsigned short hardware,
- unsigned short hwshare,
- struct snd_cs4231 ** rchip)
-{
- static struct snd_device_ops ops = {
- .dev_free = snd_cs4231_dev_free,
- };
- struct snd_cs4231 *chip;
- int err;
-
- err = snd_cs4231_new(card, hardware, hwshare, &chip);
- if (err < 0)
- return err;
-
- chip->irq = -1;
- chip->dma1 = -1;
- chip->dma2 = -1;
-
- if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) {
- snd_printk(KERN_ERR "cs4231: can't grab port 0x%lx\n", port);
- snd_cs4231_free(chip);
- return -EBUSY;
- }
- chip->port = port;
- if ((long)cport >= 0 && (chip->res_cport = request_region(cport, 8, "CS4232 Control")) == NULL) {
- snd_printk(KERN_ERR "cs4231: can't grab control port 0x%lx\n", cport);
- snd_cs4231_free(chip);
- return -ENODEV;
- }
- chip->cport = cport;
- if (!(hwshare & CS4231_HWSHARE_IRQ) && request_irq(irq, snd_cs4231_interrupt, SA_INTERRUPT, "CS4231", (void *) chip)) {
- snd_printk(KERN_ERR "cs4231: can't grab IRQ %d\n", irq);
- snd_cs4231_free(chip);
- return -EBUSY;
- }
- chip->irq = irq;
- if (!(hwshare & CS4231_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) {
- snd_printk(KERN_ERR "cs4231: can't grab DMA1 %d\n", dma1);
- snd_cs4231_free(chip);
- return -EBUSY;
- }
- chip->dma1 = dma1;
- if (!(hwshare & CS4231_HWSHARE_DMA2) && dma1 != dma2 && dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) {
- snd_printk(KERN_ERR "cs4231: can't grab DMA2 %d\n", dma2);
- snd_cs4231_free(chip);
- return -EBUSY;
- }
- if (dma1 == dma2 || dma2 < 0) {
- chip->single_dma = 1;
- chip->dma2 = chip->dma1;
- } else
- chip->dma2 = dma2;
-
- /* global setup */
- if (snd_cs4231_probe(chip) < 0) {
- snd_cs4231_free(chip);
- return -ENODEV;
- }
- snd_cs4231_init(chip);
-
-#if 0
- if (chip->hardware & CS4231_HW_CS4232_MASK) {
- if (chip->res_cport == NULL)
- snd_printk("CS4232 control port features are not accessible\n");
- }
-#endif
-
- /* Register device */
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
- snd_cs4231_free(chip);
- return err;
- }
-
-#ifdef CONFIG_PM
- /* Power Management */
- chip->suspend = snd_cs4231_suspend;
- chip->resume = snd_cs4231_resume;
-#endif
-
- *rchip = chip;
- return 0;
-}
-
-static struct snd_pcm_ops snd_cs4231_playback_ops = {
- .open = snd_cs4231_playback_open,
- .close = snd_cs4231_playback_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_cs4231_playback_hw_params,
- .hw_free = snd_cs4231_playback_hw_free,
- .prepare = snd_cs4231_playback_prepare,
- .trigger = snd_cs4231_trigger,
- .pointer = snd_cs4231_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_cs4231_capture_ops = {
- .open = snd_cs4231_capture_open,
- .close = snd_cs4231_capture_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_cs4231_capture_hw_params,
- .hw_free = snd_cs4231_capture_hw_free,
- .prepare = snd_cs4231_capture_prepare,
- .trigger = snd_cs4231_trigger,
- .pointer = snd_cs4231_capture_pointer,
-};
-
-int snd_cs4231_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
-{
- struct snd_pcm *pcm;
- int err;
-
- if ((err = snd_pcm_new(chip->card, "CS4231", device, 1, 1, &pcm)) < 0)
- return err;
-
- spin_lock_init(&chip->reg_lock);
- init_MUTEX(&chip->mce_mutex);
- init_MUTEX(&chip->open_mutex);
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
-
- /* global setup */
- pcm->private_data = chip;
- pcm->info_flags = 0;
- if (chip->single_dma)
- pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
- if (chip->hardware != CS4231_HW_INTERWAVE)
- pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
- strcpy(pcm->name, snd_cs4231_chip_id(chip));
-
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_isa_data(),
- 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
-
- chip->pcm = pcm;
- if (rpcm)
- *rpcm = pcm;
- return 0;
-}
-
-static void snd_cs4231_timer_free(struct snd_timer *timer)
-{
- struct snd_cs4231 *chip = timer->private_data;
- chip->timer = NULL;
-}
-
-int snd_cs4231_timer(struct snd_cs4231 *chip, int device, struct snd_timer **rtimer)
-{
- struct snd_timer *timer;
- struct snd_timer_id tid;
- int err;
-
- /* Timer initialization */
- tid.dev_class = SNDRV_TIMER_CLASS_CARD;
- tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
- tid.card = chip->card->number;
- tid.device = device;
- tid.subdevice = 0;
- if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
- return err;
- strcpy(timer->name, snd_cs4231_chip_id(chip));
- timer->private_data = chip;
- timer->private_free = snd_cs4231_timer_free;
- timer->hw = snd_cs4231_timer_table;
- chip->timer = timer;
- if (rtimer)
- *rtimer = timer;
- return 0;
-}
-
-/*
- * MIXER part
- */
-
-static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- static char *texts[4] = {
- "Line", "Aux", "Mic", "Mix"
- };
- static char *opl3sa_texts[4] = {
- "Line", "CD", "Mic", "Mix"
- };
- static char *gusmax_texts[4] = {
- "Line", "Synth", "Mic", "Mix"
- };
- char **ptexts = texts;
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
-
- snd_assert(chip->card != NULL, return -EINVAL);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- if (!strcmp(chip->card->driver, "GUS MAX"))
- ptexts = gusmax_texts;
- switch (chip->hardware) {
- case CS4231_HW_INTERWAVE: ptexts = gusmax_texts; break;
- case CS4231_HW_OPL3SA2: ptexts = opl3sa_texts; break;
- }
- strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
- return 0;
-}
-
-static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
- ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
-}
-
-static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- unsigned short left, right;
- int change;
-
- if (ucontrol->value.enumerated.item[0] > 3 ||
- ucontrol->value.enumerated.item[1] > 3)
- return -EINVAL;
- left = ucontrol->value.enumerated.item[0] << 6;
- right = ucontrol->value.enumerated.item[1] << 6;
- spin_lock_irqsave(&chip->reg_lock, flags);
- left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
- right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
- change = left != chip->image[CS4231_LEFT_INPUT] ||
- right != chip->image[CS4231_RIGHT_INPUT];
- snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);
- snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return change;
-}
-
-int snd_cs4231_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 16) & 0xff;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int reg = kcontrol->private_value & 0xff;
- int shift = (kcontrol->private_value >> 8) & 0xff;
- int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (invert)
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- return 0;
-}
-
-int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int reg = kcontrol->private_value & 0xff;
- int shift = (kcontrol->private_value >> 8) & 0xff;
- int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
- int change;
- unsigned short val;
-
- val = (ucontrol->value.integer.value[0] & mask);
- if (invert)
- val = mask - val;
- val <<= shift;
- spin_lock_irqsave(&chip->reg_lock, flags);
- val = (chip->image[reg] & ~(mask << shift)) | val;
- change = val != chip->image[reg];
- snd_cs4231_out(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return change;
-}
-
-int snd_cs4231_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 24) & 0xff;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
- int mask = (kcontrol->private_value >> 24) & 0xff;
- int invert = (kcontrol->private_value >> 22) & 1;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
- ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (invert) {
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
- }
- return 0;
-}
-
-int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
- int mask = (kcontrol->private_value >> 24) & 0xff;
- int invert = (kcontrol->private_value >> 22) & 1;
- int change;
- unsigned short val1, val2;
-
- val1 = ucontrol->value.integer.value[0] & mask;
- val2 = ucontrol->value.integer.value[1] & mask;
- if (invert) {
- val1 = mask - val1;
- val2 = mask - val2;
- }
- val1 <<= shift_left;
- val2 <<= shift_right;
- spin_lock_irqsave(&chip->reg_lock, flags);
- val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
- val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
- change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
- snd_cs4231_out(chip, left_reg, val1);
- snd_cs4231_out(chip, right_reg, val2);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return change;
-}
-
-static struct snd_kcontrol_new snd_cs4231_controls[] = {
-CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
-CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),
-CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),
-CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
-CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = snd_cs4231_info_mux,
- .get = snd_cs4231_get_mux,
- .put = snd_cs4231_put_mux,
-},
-CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1)
-};
-
-int snd_cs4231_mixer(struct snd_cs4231 *chip)
-{
- struct snd_card *card;
- unsigned int idx;
- int err;
-
- snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
-
- card = chip->card;
-
- strcpy(card->mixername, chip->pcm->name);
-
- for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
- if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip))) < 0)
- return err;
- }
- return 0;
-}
-
-EXPORT_SYMBOL(snd_cs4231_out);
-EXPORT_SYMBOL(snd_cs4231_in);
-EXPORT_SYMBOL(snd_cs4236_ext_out);
-EXPORT_SYMBOL(snd_cs4236_ext_in);
-EXPORT_SYMBOL(snd_cs4231_mce_up);
-EXPORT_SYMBOL(snd_cs4231_mce_down);
-EXPORT_SYMBOL(snd_cs4231_interrupt);
-EXPORT_SYMBOL(snd_cs4231_chip_id);
-EXPORT_SYMBOL(snd_cs4231_create);
-EXPORT_SYMBOL(snd_cs4231_pcm);
-EXPORT_SYMBOL(snd_cs4231_mixer);
-EXPORT_SYMBOL(snd_cs4231_timer);
-EXPORT_SYMBOL(snd_cs4231_info_single);
-EXPORT_SYMBOL(snd_cs4231_get_single);
-EXPORT_SYMBOL(snd_cs4231_put_single);
-EXPORT_SYMBOL(snd_cs4231_info_double);
-EXPORT_SYMBOL(snd_cs4231_get_double);
-EXPORT_SYMBOL(snd_cs4231_put_double);
-
-/*
- * INIT part
- */
-
-static int __init alsa_cs4231_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_cs4231_exit(void)
-{
-}
-
-module_init(alsa_cs4231_init)
-module_exit(alsa_cs4231_exit)
diff --git a/sound/isa/cs423x/cs4232.c b/sound/isa/cs423x/cs4232.c
deleted file mode 100644
index 9fad2e6c0c2..00000000000
--- a/sound/isa/cs423x/cs4232.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define CS4232
-#include "cs4236.c"
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index e1683337e6c..750f51c904f 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -1,6 +1,6 @@
/*
* Driver for generic CS4232/CS4235/CS4236/CS4236B/CS4237B/CS4238B/CS4239 chips
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,32 +19,27 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <linux/isa.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
-#ifdef CS4232
-MODULE_DESCRIPTION("Cirrus Logic CS4232");
+MODULE_DESCRIPTION("Cirrus Logic CS4232-9");
MODULE_SUPPORTED_DEVICE("{{Turtle Beach,TBS-2000},"
"{Turtle Beach,Tropez Plus},"
"{SIC CrystalWave 32},"
"{Hewlett Packard,Omnibook 5500},"
"{TerraTec,Maestro 32/96},"
- "{Philips,PCA70PS}}");
-#else
-MODULE_DESCRIPTION("Cirrus Logic CS4235-9");
-MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
+ "{Philips,PCA70PS}},"
+ "{{Crystal Semiconductors,CS4235},"
"{Crystal Semiconductors,CS4236},"
"{Crystal Semiconductors,CS4237},"
"{Crystal Semiconductors,CS4238},"
@@ -71,19 +66,17 @@ MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
"{Typhoon Soundsystem,CS4236B},"
"{Turtle Beach,Malibu},"
"{Unknown,Digital PC 5000 Onboard}}");
-#endif
-#ifdef CS4232
-#define IDENT "CS4232"
-#else
-#define IDENT "CS4236+"
-#endif
+MODULE_ALIAS("snd_cs4232");
+
+#define IDENT "CS4232+"
+#define DEV_NAME "cs4232+"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
#ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#endif
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long cport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
@@ -124,14 +117,14 @@ MODULE_PARM_DESC(dma1, "DMA1 # for " IDENT " driver.");
module_param_array(dma2, int, NULL, 0444);
MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
-static struct platform_device *platform_devices[SNDRV_CARDS];
+#ifdef CONFIG_PNP
+static int isa_registered;
static int pnpc_registered;
-#ifdef CS4232
static int pnp_registered;
-#endif
+#endif /* CONFIG_PNP */
struct snd_card_cs4236 {
- struct snd_cs4231 *chip;
+ struct snd_wss *chip;
struct resource *res_sb_port;
#ifdef CONFIG_PNP
struct pnp_dev *wss;
@@ -142,11 +135,10 @@ struct snd_card_cs4236 {
#ifdef CONFIG_PNP
-#ifdef CS4232
/*
* PNP BIOS
*/
-static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
+static const struct pnp_device_id snd_cs423x_pnpbiosids[] = {
{ .id = "CSC0100" },
{ .id = "CSC0000" },
/* Guillemot Turtlebeach something appears to be cs4232 compatible
@@ -154,11 +146,8 @@ static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
{ .id = "GIM0100" },
{ .id = "" }
};
-MODULE_DEVICE_TABLE(pnp, snd_cs4232_pnpbiosids);
-#endif /* CS4232 */
+MODULE_DEVICE_TABLE(pnp, snd_cs423x_pnpbiosids);
-#ifdef CS4232
-#define CS423X_DRIVER "snd_cs4232"
#define CS423X_ISAPNP_DRIVER "cs4232_isapnp"
static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* Philips PCA70PS */
@@ -175,13 +164,8 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
{ .id = "CSC7632", .devs = { { "CSC0000" }, { "CSC0010" }, { "PNPb006" } } },
/* SIC CrystalWave 32 (CS4232) */
{ .id = "CSCf032", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
- /* --- */
- { .id = "" } /* end */
-};
-#else /* CS4236 */
-#define CS423X_DRIVER "snd_cs4236"
-#define CS423X_ISAPNP_DRIVER "cs4236_isapnp"
-static struct pnp_card_device_id snd_cs423x_pnpids[] = {
+ /* Netfinity 3000 on-board soundcard */
+ { .id = "CSCe825", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC010f" } } },
/* Intel Marlin Spike Motherboard - CS4235 */
{ .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Intel Marlin Spike Motherboard (#2) - CS4235 */
@@ -192,7 +176,7 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
{ .id = "CSC0437", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Digital PC 5000 Onboard - CS4236B */
{ .id = "CSC0735", .devs = { { "CSC0000" }, { "CSC0010" } } },
- /* some uknown CS4236B */
+ /* some unknown CS4236B */
{ .id = "CSC0b35", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Intel PR440FX Onboard sound */
{ .id = "CSC0b36", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
@@ -236,6 +220,8 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
{ .id = "CSC9836", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Gallant SC-70P */
{ .id = "CSC9837", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
+ /* Techmakers MF-4236PW */
+ { .id = "CSCa736", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* TerraTec AudioSystem EWS64XL - CS4236B */
{ .id = "CSCa836", .devs = { { "CSCa800" }, { "CSCa810" }, { "CSCa803" } } },
/* TerraTec AudioSystem EWS64XL - CS4236B */
@@ -261,34 +247,13 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* --- */
{ .id = "" } /* end */
};
-#endif
MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
/* WSS initialization */
-static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev,
- struct pnp_resource_table *cfg)
+static int snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev)
{
- int err;
-
- pnp_init_resource_table(cfg);
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port[dev], 4);
- if (fm_port[dev] != SNDRV_AUTO_PORT && fm_port[dev] > 0)
- pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
- if (sb_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[2], sb_port[dev], 16);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- if (dma1[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
- if (dma2[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2[dev] < 0 ? 4 : dma2[dev], 1);
- err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
- snd_printk(KERN_ERR IDENT " WSS PnP manual resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
+ if (pnp_activate_dev(pdev) < 0) {
printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n");
return -EBUSY;
}
@@ -307,19 +272,9 @@ static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev,
}
/* CTRL initialization */
-static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev,
- struct pnp_resource_table *cfg)
+static int snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev)
{
- int err;
-
- pnp_init_resource_table(cfg);
- if (cport[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], cport[dev], 8);
- err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
- snd_printk(KERN_ERR IDENT " CTRL PnP manual resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
+ if (pnp_activate_dev(pdev) < 0) {
printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n");
return -EBUSY;
}
@@ -329,21 +284,9 @@ static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev,
}
/* MPU initialization */
-static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev,
- struct pnp_resource_table *cfg)
+static int snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
{
- int err;
-
- pnp_init_resource_table(cfg);
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
- if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0)
- pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
- err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
- snd_printk(KERN_ERR IDENT " MPU401 PnP manual resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
+ if (pnp_activate_dev(pdev) < 0) {
printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n");
mpu_port[dev] = SNDRV_AUTO_PORT;
mpu_irq[dev] = SNDRV_AUTO_IRQ;
@@ -360,65 +303,51 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev,
return 0;
}
-#ifdef CS4232
-static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard,
- struct pnp_dev *pdev)
+static int snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard,
+ struct pnp_dev *pdev,
+ struct pnp_dev *cdev)
{
- struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
-
- if (!cfg)
- return -ENOMEM;
- if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0) {
- kfree(cfg);
+ acard->wss = pdev;
+ if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
return -EBUSY;
- }
- kfree(cfg);
- cport[dev] = -1;
+ if (cdev)
+ cport[dev] = pnp_port_start(cdev, 0);
+ else
+ cport[dev] = -1;
return 0;
}
-#endif
-static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
- struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
-
- if (!cfg)
- return -ENOMEM;
-
acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL);
if (acard->wss == NULL)
- goto error;
+ return -EBUSY;
acard->ctrl = pnp_request_card_device(card, id->devs[1].id, NULL);
if (acard->ctrl == NULL)
- goto error;
+ return -EBUSY;
if (id->devs[2].id[0]) {
acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
if (acard->mpu == NULL)
- goto error;
+ return -EBUSY;
}
/* WSS initialization */
- if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0)
- goto error;
+ if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
+ return -EBUSY;
/* CTRL initialization */
if (acard->ctrl && cport[dev] > 0) {
- if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl, cfg) < 0)
- goto error;
+ if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl) < 0)
+ return -EBUSY;
}
/* MPU initialization */
if (acard->mpu && mpu_port[dev] > 0) {
- if (snd_cs423x_pnp_init_mpu(dev, acard->ctrl, cfg) < 0)
- goto error;
+ if (snd_cs423x_pnp_init_mpu(dev, acard->mpu) < 0)
+ return -EBUSY;
}
- kfree(cfg);
return 0;
-
- error:
- kfree(cfg);
- return -EBUSY;
}
#endif /* CONFIG_PNP */
@@ -435,23 +364,26 @@ static void snd_card_cs4236_free(struct snd_card *card)
release_and_free_resource(acard->res_sb_port);
}
-static struct snd_card *snd_cs423x_card_new(int dev)
+static int snd_cs423x_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_cs4236));
- if (card == NULL)
- return NULL;
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_cs4236), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_card_cs4236_free;
- return card;
+ *cardp = card;
+ return 0;
}
-static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
+static int snd_cs423x_probe(struct snd_card *card, int dev)
{
struct snd_card_cs4236 *acard;
struct snd_pcm *pcm;
- struct snd_cs4231 *chip;
+ struct snd_wss *chip;
struct snd_opl3 *opl3;
int err;
@@ -462,44 +394,32 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
return -EBUSY;
}
-#ifdef CS4232
- if ((err = snd_cs4231_create(card,
- port[dev],
- cport[dev],
- irq[dev],
- dma1[dev],
- dma2[dev],
- CS4231_HW_DETECT,
- 0,
- &chip)) < 0)
- return err;
- acard->chip = chip;
-
- if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0)
- return err;
-
- if ((err = snd_cs4231_mixer(chip)) < 0)
+ err = snd_cs4236_create(card, port[dev], cport[dev],
+ irq[dev],
+ dma1[dev], dma2[dev],
+ WSS_HW_DETECT3, 0, &chip);
+ if (err < 0)
return err;
-#else /* CS4236 */
- if ((err = snd_cs4236_create(card,
- port[dev],
- cport[dev],
- irq[dev],
- dma1[dev],
- dma2[dev],
- CS4231_HW_DETECT,
- 0,
- &chip)) < 0)
- return err;
acard->chip = chip;
+ if (chip->hardware & WSS_HW_CS4236B_MASK) {
- if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0)
- return err;
+ err = snd_cs4236_pcm(chip, 0, &pcm);
+ if (err < 0)
+ return err;
- if ((err = snd_cs4236_mixer(chip)) < 0)
- return err;
-#endif
+ err = snd_cs4236_mixer(chip);
+ if (err < 0)
+ return err;
+ } else {
+ err = snd_wss_pcm(chip, 0, &pcm);
+ if (err < 0)
+ return err;
+
+ err = snd_wss_mixer(chip);
+ if (err < 0)
+ return err;
+ }
strcpy(card->driver, pcm->name);
strcpy(card->shortname, pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i",
@@ -510,7 +430,8 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
if (dma2[dev] >= 0)
sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
- if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0)
+ err = snd_wss_timer(chip, 0, NULL);
+ if (err < 0)
return err;
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
@@ -529,46 +450,60 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
mpu_irq[dev] = -1;
if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232,
mpu_port[dev], 0,
- mpu_irq[dev],
- mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0)
+ mpu_irq[dev], NULL) < 0)
printk(KERN_WARNING IDENT ": MPU401 not detected\n");
}
return snd_card_register(card);
}
-static int __init snd_cs423x_nonpnp_probe(struct platform_device *pdev)
+static int snd_cs423x_isa_match(struct device *pdev,
+ unsigned int dev)
{
- int dev = pdev->id;
- struct snd_card *card;
- int err;
+ if (!enable[dev] || is_isapnp_selected(dev))
+ return 0;
if (port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "specify port\n");
- return -EINVAL;
+ dev_err(pdev, "please specify port\n");
+ return 0;
}
if (cport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "specify cport\n");
- return -EINVAL;
+ dev_err(pdev, "please specify cport\n");
+ return 0;
}
+ if (irq[dev] == SNDRV_AUTO_IRQ) {
+ dev_err(pdev, "please specify irq\n");
+ return 0;
+ }
+ if (dma1[dev] == SNDRV_AUTO_DMA) {
+ dev_err(pdev, "please specify dma1\n");
+ return 0;
+ }
+ return 1;
+}
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
- snd_card_set_dev(card, &pdev->dev);
+static int snd_cs423x_isa_probe(struct device *pdev,
+ unsigned int dev)
+{
+ struct snd_card *card;
+ int err;
+
+ err = snd_cs423x_card_new(pdev, dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
}
-
- platform_set_drvdata(pdev, card);
+
+ dev_set_drvdata(pdev, card);
return 0;
}
-static int __devexit snd_cs423x_nonpnp_remove(struct platform_device *devptr)
+static int snd_cs423x_isa_remove(struct device *pdev,
+ unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(pdev));
return 0;
}
@@ -589,38 +524,41 @@ static int snd_cs423x_resume(struct snd_card *card)
return 0;
}
-static int snd_cs423x_nonpnp_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_cs423x_isa_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
{
- return snd_cs423x_suspend(platform_get_drvdata(dev));
+ return snd_cs423x_suspend(dev_get_drvdata(dev));
}
-static int snd_cs423x_nonpnp_resume(struct platform_device *dev)
+static int snd_cs423x_isa_resume(struct device *dev, unsigned int n)
{
- return snd_cs423x_resume(platform_get_drvdata(dev));
+ return snd_cs423x_resume(dev_get_drvdata(dev));
}
#endif
-static struct platform_driver cs423x_nonpnp_driver = {
- .probe = snd_cs423x_nonpnp_probe,
- .remove = __devexit_p(snd_cs423x_nonpnp_remove),
+static struct isa_driver cs423x_isa_driver = {
+ .match = snd_cs423x_isa_match,
+ .probe = snd_cs423x_isa_probe,
+ .remove = snd_cs423x_isa_remove,
#ifdef CONFIG_PM
- .suspend = snd_cs423x_nonpnp_suspend,
- .resume = snd_cs423x_nonpnp_resume,
+ .suspend = snd_cs423x_isa_suspend,
+ .resume = snd_cs423x_isa_resume,
#endif
.driver = {
- .name = CS423X_DRIVER
+ .name = DEV_NAME
},
};
#ifdef CONFIG_PNP
-#ifdef CS4232
-static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
- const struct pnp_device_id *id)
+static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
+ const struct pnp_device_id *id)
{
static int dev;
int err;
struct snd_card *card;
+ struct pnp_dev *cdev;
+ char cid[PNP_ID_LEN];
if (pnp_device_is_isapnp(pdev))
return -ENOENT; /* we have another procedure - card */
@@ -631,15 +569,23 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
- if ((err = snd_card_cs4232_pnp(dev, card->private_data, pdev)) < 0) {
+ /* prepare second id */
+ strcpy(cid, pdev->id[0].id);
+ cid[5] = '1';
+ cdev = NULL;
+ list_for_each_entry(cdev, &(pdev->protocol->devices), protocol_list) {
+ if (!strcmp(cdev->id[0].id, cid))
+ break;
+ }
+ err = snd_cs423x_card_new(&pdev->dev, dev, &card);
+ if (err < 0)
+ return err;
+ err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
+ if (err < 0) {
printk(KERN_ERR "PnP BIOS detection failed for " IDENT "\n");
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
if ((err = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -649,38 +595,36 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
return 0;
}
-static void __devexit snd_cs4232_pnp_remove(struct pnp_dev * pdev)
+static void snd_cs423x_pnp_remove(struct pnp_dev *pdev)
{
snd_card_free(pnp_get_drvdata(pdev));
- pnp_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM
-static int snd_cs4232_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
+static int snd_cs423x_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
{
return snd_cs423x_suspend(pnp_get_drvdata(pdev));
}
-static int snd_cs4232_pnp_resume(struct pnp_dev *pdev)
+static int snd_cs423x_pnp_resume(struct pnp_dev *pdev)
{
return snd_cs423x_resume(pnp_get_drvdata(pdev));
}
#endif
-static struct pnp_driver cs4232_pnp_driver = {
- .name = "cs4232-pnpbios",
- .id_table = snd_cs4232_pnpbiosids,
- .probe = snd_cs4232_pnpbios_detect,
- .remove = __devexit_p(snd_cs4232_pnp_remove),
+static struct pnp_driver cs423x_pnp_driver = {
+ .name = "cs423x-pnpbios",
+ .id_table = snd_cs423x_pnpbiosids,
+ .probe = snd_cs423x_pnpbios_detect,
+ .remove = snd_cs423x_pnp_remove,
#ifdef CONFIG_PM
- .suspend = snd_cs4232_pnp_suspend,
- .resume = snd_cs4232_pnp_resume,
+ .suspend = snd_cs423x_pnp_suspend,
+ .resume = snd_cs423x_pnp_resume,
#endif
};
-#endif /* CS4232 */
-static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
static int dev;
struct snd_card *card;
@@ -693,16 +637,15 @@ static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_cs423x_card_new(&pcard->card->dev, dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) {
printk(KERN_ERR "isapnp detection failed and probing for " IDENT
" is not supported\n");
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
@@ -712,12 +655,12 @@ static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
return 0;
}
-static void __devexit snd_cs423x_pnpc_remove(struct pnp_card_link * pcard)
+static void snd_cs423x_pnpc_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
}
-
+
#ifdef CONFIG_PM
static int snd_cs423x_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
{
@@ -735,7 +678,7 @@ static struct pnp_card_driver cs423x_pnpc_driver = {
.name = CS423X_ISAPNP_DRIVER,
.id_table = snd_cs423x_pnpids,
.probe = snd_cs423x_pnpc_detect,
- .remove = __devexit_p(snd_cs423x_pnpc_remove),
+ .remove = snd_cs423x_pnpc_remove,
#ifdef CONFIG_PM
.suspend = snd_cs423x_pnpc_suspend,
.resume = snd_cs423x_pnpc_resume,
@@ -743,70 +686,38 @@ static struct pnp_card_driver cs423x_pnpc_driver = {
};
#endif /* CONFIG_PNP */
-static void __init_or_module snd_cs423x_unregister_all(void)
-{
- int i;
-
- if (pnpc_registered)
- pnp_unregister_card_driver(&cs423x_pnpc_driver);
-#ifdef CS4232
- if (pnp_registered)
- pnp_unregister_driver(&cs4232_pnp_driver);
-#endif
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&cs423x_nonpnp_driver);
-}
-
static int __init alsa_card_cs423x_init(void)
{
- int i, err, cards = 0;
-
- if ((err = platform_driver_register(&cs423x_nonpnp_driver)) < 0)
- return err;
+ int err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- if (is_isapnp_selected(i))
- continue;
- device = platform_device_register_simple(CS423X_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- cards++;
- }
-#ifdef CS4232
- i = pnp_register_driver(&cs4232_pnp_driver);
- if (i >= 0) {
+ err = isa_register_driver(&cs423x_isa_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+ if (!err)
+ isa_registered = 1;
+ err = pnp_register_driver(&cs423x_pnp_driver);
+ if (!err)
pnp_registered = 1;
- cards += i;
- }
-#endif
- i = pnp_register_card_driver(&cs423x_pnpc_driver);
- if (i >= 0) {
+ err = pnp_register_card_driver(&cs423x_pnpc_driver);
+ if (!err)
pnpc_registered = 1;
- cards += i;
- }
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR IDENT " soundcard not found or device busy\n");
+ if (pnp_registered)
+ err = 0;
+ if (isa_registered)
+ err = 0;
#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_cs423x_unregister_all();
return err;
}
static void __exit alsa_card_cs423x_exit(void)
{
- snd_cs423x_unregister_all();
+#ifdef CONFIG_PNP
+ if (pnpc_registered)
+ pnp_unregister_card_driver(&cs423x_pnpc_driver);
+ if (pnp_registered)
+ pnp_unregister_driver(&cs423x_pnp_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&cs423x_isa_driver);
}
module_init(alsa_card_cs423x_init)
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index e36981d64ec..c5adca30063 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of CS4235/4236B/4237B/4238B/4239 chips
*
* Note:
@@ -79,19 +79,16 @@
*
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#include <sound/asoundef.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Routines for control of CS4235/4236B/4237B/4238B/4239 chips");
-MODULE_LICENSE("GPL");
+#include <sound/initval.h>
+#include <sound/tlv.h>
/*
*
@@ -122,13 +119,14 @@ static unsigned char snd_cs4236_ext_map[18] = {
*
*/
-static void snd_cs4236_ctrl_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val)
+static void snd_cs4236_ctrl_out(struct snd_wss *chip,
+ unsigned char reg, unsigned char val)
{
outb(reg, chip->cport + 3);
outb(chip->cimage[reg] = val, chip->cport + 4);
}
-static unsigned char snd_cs4236_ctrl_in(struct snd_cs4231 *chip, unsigned char reg)
+static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg)
{
outb(reg, chip->cport + 3);
return inb(chip->cport + 4);
@@ -181,44 +179,52 @@ static unsigned char divisor_to_rate_register(unsigned int divisor)
}
}
-static void snd_cs4236_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char pdfr)
+static void snd_cs4236_playback_format(struct snd_wss *chip,
+ struct snd_pcm_hw_params *params,
+ unsigned char pdfr)
{
unsigned long flags;
unsigned char rate = divisor_to_rate_register(params->rate_den);
spin_lock_irqsave(&chip->reg_lock, flags);
/* set fast playback format change and clean playback FIFO */
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
- snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] | 0x10);
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static void snd_cs4236_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char cdfr)
+static void snd_cs4236_capture_format(struct snd_wss *chip,
+ struct snd_pcm_hw_params *params,
+ unsigned char cdfr)
{
unsigned long flags;
unsigned char rate = divisor_to_rate_register(params->rate_den);
spin_lock_irqsave(&chip->reg_lock, flags);
/* set fast capture format change and clean capture FIFO */
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
- snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] | 0x20);
+ snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
#ifdef CONFIG_PM
-static void snd_cs4236_suspend(struct snd_cs4231 *chip)
+static void snd_cs4236_suspend(struct snd_wss *chip)
{
int reg;
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
for (reg = 0; reg < 32; reg++)
- chip->image[reg] = snd_cs4231_in(chip, reg);
+ chip->image[reg] = snd_wss_in(chip, reg);
for (reg = 0; reg < 18; reg++)
chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
for (reg = 2; reg < 9; reg++)
@@ -226,12 +232,12 @@ static void snd_cs4236_suspend(struct snd_cs4231 *chip)
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static void snd_cs4236_resume(struct snd_cs4231 *chip)
+static void snd_cs4236_resume(struct snd_wss *chip)
{
int reg;
unsigned long flags;
- snd_cs4231_mce_up(chip);
+ snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
for (reg = 0; reg < 32; reg++) {
switch (reg) {
@@ -241,7 +247,7 @@ static void snd_cs4236_resume(struct snd_cs4231 *chip)
case 29: /* why? CS4235 - master right */
break;
default:
- snd_cs4231_out(chip, reg, chip->image[reg]);
+ snd_wss_out(chip, reg, chip->image[reg]);
break;
}
}
@@ -256,53 +262,66 @@ static void snd_cs4236_resume(struct snd_cs4231 *chip)
}
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
+ snd_wss_mce_down(chip);
}
#endif /* CONFIG_PM */
-
+/*
+ * This function does no fail if the chip is not CS4236B or compatible.
+ * It just an equivalent to the snd_wss_create() then.
+ */
int snd_cs4236_create(struct snd_card *card,
unsigned long port,
unsigned long cport,
int irq, int dma1, int dma2,
unsigned short hardware,
unsigned short hwshare,
- struct snd_cs4231 ** rchip)
+ struct snd_wss **rchip)
{
- struct snd_cs4231 *chip;
+ struct snd_wss *chip;
unsigned char ver1, ver2;
unsigned int reg;
int err;
*rchip = NULL;
- if (hardware == CS4231_HW_DETECT)
- hardware = CS4231_HW_DETECT3;
- if (cport < 0x100) {
- snd_printk("please, specify control port for CS4236+ chips\n");
- return -ENODEV;
- }
- if ((err = snd_cs4231_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip)) < 0)
+ if (hardware == WSS_HW_DETECT)
+ hardware = WSS_HW_DETECT3;
+
+ err = snd_wss_create(card, port, cport,
+ irq, dma1, dma2, hardware, hwshare, &chip);
+ if (err < 0)
return err;
- if (!(chip->hardware & CS4231_HW_CS4236B_MASK)) {
- snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware);
- snd_device_free(card, chip);
- return -ENODEV;
+ if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
+ snd_printd("chip is not CS4236+, hardware=0x%x\n",
+ chip->hardware);
+ *rchip = chip;
+ return 0;
}
#if 0
{
int idx;
for (idx = 0; idx < 8; idx++)
- snd_printk("CD%i = 0x%x\n", idx, inb(chip->cport + idx));
+ snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
+ idx, inb(chip->cport + idx));
for (idx = 0; idx < 9; idx++)
- snd_printk("C%i = 0x%x\n", idx, snd_cs4236_ctrl_in(chip, idx));
+ snd_printk(KERN_DEBUG "C%i = 0x%x\n",
+ idx, snd_cs4236_ctrl_in(chip, idx));
}
#endif
+ if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
+ snd_printk(KERN_ERR "please, specify control port "
+ "for CS4236+ chips\n");
+ snd_device_free(card, chip);
+ return -ENODEV;
+ }
ver1 = snd_cs4236_ctrl_in(chip, 1);
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
- snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
+ snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
+ cport, ver1, ver2);
if (ver1 != ver2) {
- snd_printk("CS4236+ chip detected, but control port 0x%lx is not valid\n", cport);
+ snd_printk(KERN_ERR "CS4236+ chip detected, but "
+ "control port 0x%lx is not valid\n", cport);
snd_device_free(card, chip);
return -ENODEV;
}
@@ -310,13 +329,17 @@ int snd_cs4236_create(struct snd_card *card,
snd_cs4236_ctrl_out(chip, 2, 0xff);
snd_cs4236_ctrl_out(chip, 3, 0x00);
snd_cs4236_ctrl_out(chip, 4, 0x80);
- snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE);
+ reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
+ IEC958_AES0_CON_EMPHASIS_NONE;
+ snd_cs4236_ctrl_out(chip, 5, reg);
snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
snd_cs4236_ctrl_out(chip, 7, 0x00);
- /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */
- /* is working with this setup, other hardware should have */
- /* different signal paths and this value should be selectable */
- /* in the future */
+ /*
+ * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
+ * output is working with this setup, other hardware should
+ * have different signal paths and this value should be
+ * selectable in the future
+ */
snd_cs4236_ctrl_out(chip, 8, 0x8c);
chip->rate_constraint = snd_cs4236_xrate;
chip->set_playback_format = snd_cs4236_playback_format;
@@ -328,23 +351,24 @@ int snd_cs4236_create(struct snd_card *card,
/* initialize extended registers */
for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
- snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]);
-
- /* initialize compatible but more featured registers */
- snd_cs4231_out(chip, CS4231_LEFT_INPUT, 0x40);
- snd_cs4231_out(chip, CS4231_RIGHT_INPUT, 0x40);
- snd_cs4231_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
- snd_cs4231_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
- snd_cs4231_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
- snd_cs4231_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
- snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
- snd_cs4231_out(chip, CS4231_LEFT_LINE_IN, 0xff);
- snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
+ snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
+ snd_cs4236_ext_map[reg]);
+
+ /* initialize compatible but more featured registers */
+ snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
+ snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
+ snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
+ snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
+ snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
+ snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
+ snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
+ snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff);
+ snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
switch (chip->hardware) {
- case CS4231_HW_CS4235:
- case CS4231_HW_CS4239:
- snd_cs4231_out(chip, CS4235_LEFT_MASTER, 0xff);
- snd_cs4231_out(chip, CS4235_RIGHT_MASTER, 0xff);
+ case WSS_HW_CS4235:
+ case WSS_HW_CS4239:
+ snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff);
+ snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff);
break;
}
@@ -352,12 +376,13 @@ int snd_cs4236_create(struct snd_card *card,
return 0;
}
-int snd_cs4236_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
+int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
{
struct snd_pcm *pcm;
int err;
- if ((err = snd_cs4231_pcm(chip, device, &pcm)) < 0)
+ err = snd_wss_pcm(chip, device, &pcm);
+ if (err < 0)
return err;
pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
if (rpcm)
@@ -375,6 +400,14 @@ int snd_cs4236_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_cs4236_info_single, \
+ .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
+ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
+ .tlv = { .p = (xtlv) } }
+
static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -388,7 +421,7 @@ static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -405,7 +438,7 @@ static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -434,7 +467,7 @@ static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -451,7 +484,7 @@ static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
@@ -478,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
+#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \
+ shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_cs4236_info_double, \
+ .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+ (shift_right << 19) | (mask << 24) | (invert << 22), \
+ .tlv = { .p = (xtlv) } }
+
static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
int mask = (kcontrol->private_value >> 24) & 0xff;
@@ -491,7 +534,7 @@ static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -513,7 +556,7 @@ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -548,15 +591,26 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return change;
}
-#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \
+ shift_right, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_cs4236_info_double, \
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
+#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \
+ shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_cs4236_info_double, \
+ .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
+ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
+ (shift_right << 19) | (mask << 24) | (invert << 22), \
+ .tlv = { .p = (xtlv) } }
+
static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -578,7 +632,7 @@ static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
@@ -601,26 +655,28 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
- snd_cs4231_out(chip, left_reg, val1);
+ snd_wss_out(chip, left_reg, val1);
snd_cs4236_ext_out(chip, right_reg, val2);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
-#define CS4236_MASTER_DIGITAL(xname, xindex) \
+#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
.info = snd_cs4236_info_double, \
.get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
- .private_value = 71 << 24 }
+ .private_value = 71 << 24, \
+ .tlv = { .p = (xtlv) } }
static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
{
return (vol < 64) ? 63 - vol : 64 + (71 - vol);
-}
+}
static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -632,7 +688,7 @@ static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct s
static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int change;
unsigned short val1, val2;
@@ -644,16 +700,18 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s
val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
- snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val1);
+ snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
-#define CS4235_OUTPUT_ACCU(xname, xindex) \
+#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
.info = snd_cs4236_info_double, \
.get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
- .private_value = 3 << 24 }
+ .private_value = 3 << 24, \
+ .tlv = { .p = (xtlv) } }
static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
{
@@ -679,7 +737,7 @@ static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -691,7 +749,7 @@ static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_
static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int change;
unsigned short val1, val2;
@@ -702,108 +760,183 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_
val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
- snd_cs4231_out(chip, CS4235_LEFT_MASTER, val1);
- snd_cs4231_out(chip, CS4235_RIGHT_MASTER, val2);
+ snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
+ snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
-static struct snd_kcontrol_new snd_cs4236_controls[] = {
-
-CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
-CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
-CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
-
-CS4236_DOUBLE("Capture Boost Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
-
-CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
-
-CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
-CS4236_DOUBLE("DSP Playback Volume", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
-
-CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
-CS4236_DOUBLE("FM Playback Volume", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
+static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
-CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
-CS4236_DOUBLE("Wavetable Playback Volume", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
-
-CS4231_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Synth Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-CS4231_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
-CS4231_DOUBLE("Synth Capture Bypass", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
-
-CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
-CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
-CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
-CS4236_DOUBLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
-
-CS4231_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Line Capture Bypass", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
-
-CS4231_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("CD Volume", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
-
-CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
-CS4236_DOUBLE1("Mono Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-CS4231_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
-
-CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-CS4231_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
+static struct snd_kcontrol_new snd_cs4236_controls[] = {
-CS4231_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
+CS4236_DOUBLE("Master Digital Playback Switch", 0,
+ CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
+CS4236_DOUBLE("Master Digital Capture Switch", 0,
+ CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
+CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit),
+
+CS4236_DOUBLE_TLV("Capture Boost Volume", 0,
+ CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
+ db_scale_2bit),
+
+WSS_DOUBLE("PCM Playback Switch", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+ db_scale_6bit),
+
+CS4236_DOUBLE("DSP Playback Switch", 0,
+ CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
+CS4236_DOUBLE_TLV("DSP Playback Volume", 0,
+ CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1,
+ db_scale_6bit),
+
+CS4236_DOUBLE("FM Playback Switch", 0,
+ CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
+CS4236_DOUBLE_TLV("FM Playback Volume", 0,
+ CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1,
+ db_scale_6bit),
+
+CS4236_DOUBLE("Wavetable Playback Switch", 0,
+ CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
+CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0,
+ CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1,
+ db_scale_6bit_12db_max),
+
+WSS_DOUBLE("Synth Playback Switch", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Synth Volume", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_DOUBLE("Synth Capture Switch", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
+WSS_DOUBLE("Synth Capture Bypass", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
+
+CS4236_DOUBLE("Mic Playback Switch", 0,
+ CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
+CS4236_DOUBLE("Mic Capture Switch", 0,
+ CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
+CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC,
+ 0, 0, 31, 1, db_scale_5bit_22db_max),
+CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
+ CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
+
+WSS_DOUBLE("Line Playback Switch", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Line Volume", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_DOUBLE("Line Capture Switch", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE("Line Capture Bypass", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
+
+WSS_DOUBLE("CD Playback Switch", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("CD Volume", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_DOUBLE("CD Capture Switch", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
+
+CS4236_DOUBLE1("Mono Output Playback Switch", 0,
+ CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
+CS4236_DOUBLE1("Beep Playback Switch", 0,
+ CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
+WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1,
+ db_scale_4bit),
+WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
+
+WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
+ 0, 0, 15, 0, db_scale_rec_gain),
+WSS_DOUBLE("Analog Loopback Capture Switch", 0,
+ CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
+
+WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0,
+ CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1,
+ db_scale_6bit),
};
-static struct snd_kcontrol_new snd_cs4235_controls[] = {
-
-CS4231_DOUBLE("Master Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Volume", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
-
-CS4235_OUTPUT_ACCU("Playback Volume", 0),
-
-CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
-CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
-CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
-
-CS4231_DOUBLE("Master Digital Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Digital Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
-CS4231_DOUBLE("Master Digital Volume", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0);
-CS4236_DOUBLE("Capture Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
+static struct snd_kcontrol_new snd_cs4235_controls[] = {
-CS4231_DOUBLE("PCM Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("PCM Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Master Playback Switch", 0,
+ CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Master Playback Volume", 0,
+ CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1,
+ db_scale_5bit_6db_max),
+
+CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max),
+
+WSS_DOUBLE("Synth Playback Switch", 1,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE("Synth Capture Switch", 1,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
+WSS_DOUBLE_TLV("Synth Volume", 1,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+
+CS4236_DOUBLE_TLV("Capture Volume", 0,
+ CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
+ db_scale_2bit),
+
+WSS_DOUBLE("PCM Playback Switch", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("PCM Capture Switch", 0,
+ CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
+WSS_DOUBLE_TLV("PCM Volume", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+ db_scale_6bit),
CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
-CS4236_DOUBLE("Wavetable Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
-
-CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
-CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
-CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
-CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0),
-
-CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Aux Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-
-CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Aux Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
-CS4231_DOUBLE("Aux Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
-
-CS4236_DOUBLE1("Master Mono Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
-
-CS4236_DOUBLE1("Mono Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
-CS4231_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
-
-CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
+CS4236_DOUBLE("Wavetable Switch", 0,
+ CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
+
+CS4236_DOUBLE("Mic Capture Switch", 0,
+ CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
+CS4236_DOUBLE("Mic Playback Switch", 0,
+ CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
+CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1,
+ db_scale_5bit_22db_max),
+CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
+
+WSS_DOUBLE("Line Playback Switch", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Line Capture Switch", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE_TLV("Line Volume", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+
+WSS_DOUBLE("CD Playback Switch", 1,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("CD Capture Switch", 1,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
+WSS_DOUBLE_TLV("CD Volume", 1,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+
+CS4236_DOUBLE1("Beep Playback Switch", 0,
+ CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
+WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
+
+WSS_DOUBLE("Analog Loopback Switch", 0,
+ CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
};
#define CS4236_IEC958_ENABLE(xname, xindex) \
@@ -814,14 +947,15 @@ CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT
static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
#if 0
- printk("get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
- snd_cs4231_in(chip, CS4231_ALT_FEATURE_1),
+ printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+ "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ snd_wss_in(chip, CS4231_ALT_FEATURE_1),
snd_cs4236_ctrl_in(chip, 3),
snd_cs4236_ctrl_in(chip, 4),
snd_cs4236_ctrl_in(chip, 5),
@@ -834,31 +968,32 @@ static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
int change;
unsigned short enable, val;
enable = ucontrol->value.integer.value[0] & 1;
- down(&chip->mce_mutex);
- snd_cs4231_mce_up(chip);
+ mutex_lock(&chip->mce_mutex);
+ snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
change = val != chip->image[CS4231_ALT_FEATURE_1];
- snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, val);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
snd_cs4236_ctrl_out(chip, 4, val);
udelay(100);
val &= ~0x40;
snd_cs4236_ctrl_out(chip, 4, val);
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
- up(&chip->mce_mutex);
+ snd_wss_mce_down(chip);
+ mutex_unlock(&chip->mce_mutex);
#if 0
- printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
- snd_cs4231_in(chip, CS4231_ALT_FEATURE_1),
+ printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+ "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ snd_wss_in(chip, CS4231_ALT_FEATURE_1),
snd_cs4236_ctrl_in(chip, 3),
snd_cs4236_ctrl_in(chip, 4),
snd_cs4236_ctrl_in(chip, 5),
@@ -897,19 +1032,20 @@ CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1),
CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
};
-int snd_cs4236_mixer(struct snd_cs4231 *chip)
+int snd_cs4236_mixer(struct snd_wss *chip)
{
struct snd_card *card;
unsigned int idx, count;
int err;
struct snd_kcontrol_new *kcontrol;
- snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!chip || !chip->card))
+ return -EINVAL;
card = chip->card;
- strcpy(card->mixername, snd_cs4231_chip_id(chip));
+ strcpy(card->mixername, snd_wss_chip_id(chip));
- if (chip->hardware == CS4231_HW_CS4235 ||
- chip->hardware == CS4231_HW_CS4239) {
+ if (chip->hardware == WSS_HW_CS4235 ||
+ chip->hardware == WSS_HW_CS4239) {
for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0)
return err;
@@ -921,16 +1057,16 @@ int snd_cs4236_mixer(struct snd_cs4231 *chip)
}
}
switch (chip->hardware) {
- case CS4231_HW_CS4235:
- case CS4231_HW_CS4239:
+ case WSS_HW_CS4235:
+ case WSS_HW_CS4239:
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
kcontrol = snd_cs4236_3d_controls_cs4235;
break;
- case CS4231_HW_CS4237B:
+ case WSS_HW_CS4237B:
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
kcontrol = snd_cs4236_3d_controls_cs4237;
break;
- case CS4231_HW_CS4238B:
+ case WSS_HW_CS4238B:
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
kcontrol = snd_cs4236_3d_controls_cs4238;
break;
@@ -942,8 +1078,8 @@ int snd_cs4236_mixer(struct snd_cs4231 *chip)
if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0)
return err;
}
- if (chip->hardware == CS4231_HW_CS4237B ||
- chip->hardware == CS4231_HW_CS4238B) {
+ if (chip->hardware == WSS_HW_CS4237B ||
+ chip->hardware == WSS_HW_CS4238B) {
for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0)
return err;
@@ -951,23 +1087,3 @@ int snd_cs4236_mixer(struct snd_cs4231 *chip)
}
return 0;
}
-
-EXPORT_SYMBOL(snd_cs4236_create);
-EXPORT_SYMBOL(snd_cs4236_pcm);
-EXPORT_SYMBOL(snd_cs4236_mixer);
-
-/*
- * INIT part
- */
-
-static int __init alsa_cs4236_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_cs4236_exit(void)
-{
-}
-
-module_init(alsa_cs4236_init)
-module_exit(alsa_cs4236_exit)
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c
deleted file mode 100644
index 50e7bc5ef56..00000000000
--- a/sound/isa/dt019x.c
+++ /dev/null
@@ -1,358 +0,0 @@
-
-/*
- dt019x.c - driver for Diamond Technologies DT-0197H based soundcards.
- Copyright (C) 1999, 2002 by Massimo Piccioni <dafastidio@libero.it>
-
- Generalised for soundcards based on DT-0196 and ALS-007 chips
- by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
-
- 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 <linux/init.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/pnp.h>
-#include <linux/moduleparam.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/mpu401.h>
-#include <sound/opl3.h>
-#include <sound/sb.h>
-
-#define PFX "dt019x: "
-
-MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
-MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
- "{Avance Logic ALS-007}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
-static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
-static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
-static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
-static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
-static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard.");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for dt019x driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for dt019x driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for dt019x driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for dt019x driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for dt019x driver.");
-module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for dt019x driver.");
-
-struct snd_card_dt019x {
- struct pnp_dev *dev;
- struct pnp_dev *devmpu;
- struct pnp_dev *devopl;
- struct snd_sb *chip;
-};
-
-static struct pnp_card_device_id snd_dt019x_pnpids[] = {
- /* DT197A30 */
- { .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
- /* DT0196 / ALS-007 */
- { .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
- { .id = "", }
-};
-
-MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids);
-
-
-#define DRIVER_NAME "snd-card-dt019x"
-
-
-static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *pid)
-{
- struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
- int err;
-
- if (!cfg)
- return -ENOMEM;
-
- acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
- if (acard->dev == NULL) {
- kfree (cfg);
- return -ENODEV;
- }
- acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
- acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL);
-
- pdev = acard->dev;
- pnp_init_resource_table(cfg);
-
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
- if (dma8[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "DT-019X AUDIO the requested resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
- snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n");
- kfree(cfg);
- return err;
- }
-
- port[dev] = pnp_port_start(pdev, 0);
- dma8[dev] = pnp_dma(pdev, 0);
- irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n",
- port[dev],irq[dev],dma8[dev]);
-
- pdev = acard->devmpu;
-
- if (pdev != NULL) {
- pnp_init_resource_table(cfg);
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
- if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "DT-019X MPU401 the requested resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
- pnp_release_card_device(pdev);
- snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n");
- goto __mpu_error;
- }
- mpu_port[dev] = pnp_port_start(pdev, 0);
- mpu_irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n",
- mpu_port[dev],mpu_irq[dev]);
- } else {
- __mpu_error:
- acard->devmpu = NULL;
- mpu_port[dev] = -1;
- }
-
- pdev = acard->devopl;
- if (pdev != NULL) {
- pnp_init_resource_table(cfg);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], fm_port[dev], 4);
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "DT-019X OPL3 the requested resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
- pnp_release_card_device(pdev);
- snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n");
- goto __fm_error;
- }
- fm_port[dev] = pnp_port_start(pdev, 0);
- snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]);
- } else {
- __fm_error:
- acard->devopl = NULL;
- fm_port[dev] = -1;
- }
-
- kfree(cfg);
- return 0;
-}
-
-static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid)
-{
- int error;
- struct snd_sb *chip;
- struct snd_card *card;
- struct snd_card_dt019x *acard;
- struct snd_opl3 *opl3;
-
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_dt019x))) == NULL)
- return -ENOMEM;
- acard = card->private_data;
-
- snd_card_set_dev(card, &pcard->card->dev);
- if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) {
- snd_card_free(card);
- return error;
- }
-
- if ((error = snd_sbdsp_create(card, port[dev],
- irq[dev],
- snd_sb16dsp_interrupt,
- dma8[dev],
- -1,
- SB_HW_DT019X,
- &chip)) < 0) {
- snd_card_free(card);
- return error;
- }
- acard->chip = chip;
-
- strcpy(card->driver, "DT-019X");
- strcpy(card->shortname, "Diamond Tech. DT-019X");
- sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
- card->shortname, chip->name, chip->port,
- irq[dev], dma8[dev]);
-
- if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
- snd_card_free(card);
- return error;
- }
- if ((error = snd_sbmixer_new(chip)) < 0) {
- snd_card_free(card);
- return error;
- }
-
- if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
- if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
- mpu_irq[dev] = -1;
- if (snd_mpu401_uart_new(card, 0,
-/* MPU401_HW_SB,*/
- MPU401_HW_MPU401,
- mpu_port[dev], 0,
- mpu_irq[dev],
- mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0,
- NULL) < 0)
- snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]);
- }
-
- if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
- if (snd_opl3_create(card,
- fm_port[dev],
- fm_port[dev] + 2,
- OPL3_HW_AUTO, 0, &opl3) < 0) {
- snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n",
- fm_port[dev], fm_port[dev] + 2);
- } else {
- if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
- snd_card_free(card);
- return error;
- }
- if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
- snd_card_free(card);
- return error;
- }
- }
- }
-
- if ((error = snd_card_register(card)) < 0) {
- snd_card_free(card);
- return error;
- }
- pnp_set_card_drvdata(pcard, card);
- return 0;
-}
-
-static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card,
- const struct pnp_card_device_id *pid)
-{
- static int dev;
- int res;
-
- for ( ; dev < SNDRV_CARDS; dev++) {
- if (!enable[dev])
- continue;
- res = snd_card_dt019x_probe(dev, card, pid);
- if (res < 0)
- return res;
- dev++;
- return 0;
- }
- return -ENODEV;
-}
-
-static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard)
-{
- snd_card_free(pnp_get_card_drvdata(pcard));
- pnp_set_card_drvdata(pcard, NULL);
-}
-
-#ifdef CONFIG_PM
-static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
-{
- struct snd_card *card = pnp_get_card_drvdata(pcard);
- struct snd_card_dt019x *acard = card->private_data;
- struct snd_sb *chip = acard->chip;
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- snd_pcm_suspend_all(chip->pcm);
- snd_sbmixer_suspend(chip);
- return 0;
-}
-
-static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard)
-{
- struct snd_card *card = pnp_get_card_drvdata(pcard);
- struct snd_card_dt019x *acard = card->private_data;
- struct snd_sb *chip = acard->chip;
-
- snd_sbdsp_reset(chip);
- snd_sbmixer_resume(chip);
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-#endif
-
-static struct pnp_card_driver dt019x_pnpc_driver = {
- .flags = PNP_DRIVER_RES_DISABLE,
- .name = "dt019x",
- .id_table = snd_dt019x_pnpids,
- .probe = snd_dt019x_pnp_probe,
- .remove = __devexit_p(snd_dt019x_pnp_remove),
-#ifdef CONFIG_PM
- .suspend = snd_dt019x_pnp_suspend,
- .resume = snd_dt019x_pnp_resume,
-#endif
-};
-
-static int __init alsa_card_dt019x_init(void)
-{
- int cards = 0;
-
- cards = pnp_register_card_driver(&dt019x_pnpc_driver);
- if (cards <= 0) {
- pnp_unregister_card_driver(&dt019x_pnpc_driver);
-#ifdef MODULE
- snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
-#endif
- return -ENODEV;
- }
- return 0;
-}
-
-static void __exit alsa_card_dt019x_exit(void)
-{
- pnp_unregister_card_driver(&dt019x_pnpc_driver);
-}
-
-module_init(alsa_card_dt019x_init)
-module_exit(alsa_card_dt019x_exit)
diff --git a/sound/isa/es1688/Makefile b/sound/isa/es1688/Makefile
index 501c8bf903a..aee1e4ddb22 100644
--- a/sound/isa/es1688/Makefile
+++ b/sound/isa/es1688/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
snd-es1688-lib-objs := es1688_lib.o
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index 50d23cf3d7c..76001fe0579 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -1,6 +1,6 @@
/*
* Driver for generic ESS AudioDrive ESx688 soundcards
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,13 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
+#include <linux/isapnp.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/es1688.h>
@@ -35,207 +35,335 @@
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("ESS ESx688 AudioDrive");
+#define CRD_NAME "Generic ESS ES1688/ES688 AudioDrive"
+#define DEV_NAME "es1688"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{ESS,ES688 PnP AudioDrive,pnp:ESS0100},"
"{ESS,ES1688 PnP AudioDrive,pnp:ESS0102},"
"{ESS,ES688 AudioDrive,pnp:ESS6881},"
"{ESS,ES1688 AudioDrive,pnp:ESS1681}}");
+MODULE_ALIAS("snd_es968");
+
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+#ifdef CONFIG_PNP
+static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
+#endif
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* Usually 0x388 */
static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for ESx688 soundcard.");
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for ESx688 soundcard.");
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable ESx688 soundcard.");
+#ifdef CONFIG_PNP
+module_param_array(isapnp, bool, NULL, 0444);
+MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
+#endif
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for ESx688 driver.");
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ESx688 driver.");
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for ESx688 driver.");
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for ES1688 driver.");
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ESx688 driver.");
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for ESx688 driver.");
+MODULE_PARM_DESC(dma8, "8-bit DMA # for " CRD_NAME " driver.");
-static struct platform_device *devices[SNDRV_CARDS];
+#ifdef CONFIG_PNP
+#define is_isapnp_selected(dev) isapnp[dev]
+#else
+#define is_isapnp_selected(dev) 0
+#endif
-#define PFX "es1688: "
+static int snd_es1688_match(struct device *dev, unsigned int n)
+{
+ return enable[n] && !is_isapnp_selected(n);
+}
-static int __init snd_es1688_probe(struct platform_device *pdev)
+static int snd_es1688_legacy_create(struct snd_card *card,
+ struct device *dev, unsigned int n)
{
- int dev = pdev->id;
+ struct snd_es1688 *chip = card->private_data;
+ static long possible_ports[] = {0x220, 0x240, 0x260};
static int possible_irqs[] = {5, 9, 10, 7, -1};
static int possible_dmas[] = {1, 3, 0, -1};
- int xirq, xdma, xmpu_irq;
- struct snd_card *card;
- struct snd_es1688 *chip;
- struct snd_opl3 *opl3;
- struct snd_pcm *pcm;
- int err;
-
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
-
- xirq = irq[dev];
- if (xirq == SNDRV_AUTO_IRQ) {
- if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
- err = -EBUSY;
- goto _err;
+
+ int i, error;
+
+ if (irq[n] == SNDRV_AUTO_IRQ) {
+ irq[n] = snd_legacy_find_free_irq(possible_irqs);
+ if (irq[n] < 0) {
+ dev_err(dev, "unable to find a free IRQ\n");
+ return -EBUSY;
}
}
- xmpu_irq = mpu_irq[dev];
- xdma = dma8[dev];
- if (xdma == SNDRV_AUTO_DMA) {
- if ((xdma = snd_legacy_find_free_dma(possible_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
- err = -EBUSY;
- goto _err;
+ if (dma8[n] == SNDRV_AUTO_DMA) {
+ dma8[n] = snd_legacy_find_free_dma(possible_dmas);
+ if (dma8[n] < 0) {
+ dev_err(dev, "unable to find a free DMA\n");
+ return -EBUSY;
}
}
- if (port[dev] != SNDRV_AUTO_PORT) {
- if ((err = snd_es1688_create(card, port[dev], mpu_port[dev],
- xirq, xmpu_irq, xdma,
- ES1688_HW_AUTO, &chip)) < 0)
- goto _err;
- } else {
- /* auto-probe legacy ports */
- static unsigned long possible_ports[] = {
- 0x220, 0x240, 0x260,
- };
- int i;
- for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
- err = snd_es1688_create(card, possible_ports[i],
- mpu_port[dev],
- xirq, xmpu_irq, xdma,
- ES1688_HW_AUTO, &chip);
- if (err >= 0) {
- port[dev] = possible_ports[i];
- break;
- }
- }
- if (i >= ARRAY_SIZE(possible_ports))
- goto _err;
- }
+ if (port[n] != SNDRV_AUTO_PORT)
+ return snd_es1688_create(card, chip, port[n], mpu_port[n],
+ irq[n], mpu_irq[n], dma8[n], ES1688_HW_AUTO);
- if ((err = snd_es1688_pcm(chip, 0, &pcm)) < 0)
- goto _err;
+ i = 0;
+ do {
+ port[n] = possible_ports[i];
+ error = snd_es1688_create(card, chip, port[n], mpu_port[n],
+ irq[n], mpu_irq[n], dma8[n], ES1688_HW_AUTO);
+ } while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
- if ((err = snd_es1688_mixer(chip)) < 0)
- goto _err;
+ return error;
+}
- strcpy(card->driver, "ES1688");
- strcpy(card->shortname, pcm->name);
- sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port, xirq, xdma);
+static int snd_es1688_probe(struct snd_card *card, unsigned int n)
+{
+ struct snd_es1688 *chip = card->private_data;
+ struct snd_opl3 *opl3;
+ struct snd_pcm *pcm;
+ int error;
- if ((snd_opl3_create(card, chip->port, chip->port + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) {
- printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->port);
- } else {
- if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
- goto _err;
+ error = snd_es1688_pcm(card, chip, 0, &pcm);
+ if (error < 0)
+ return error;
+
+ error = snd_es1688_mixer(card, chip);
+ if (error < 0)
+ return error;
+
+ strlcpy(card->driver, "ES1688", sizeof(card->driver));
+ strlcpy(card->shortname, pcm->name, sizeof(card->shortname));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port,
+ chip->irq, chip->dma8);
+
+ if (fm_port[n] == SNDRV_AUTO_PORT)
+ fm_port[n] = port[n]; /* share the same port */
+
+ if (fm_port[n] > 0) {
+ if (snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+ OPL3_HW_OPL3, 0, &opl3) < 0)
+ dev_warn(card->dev,
+ "opl3 not detected at 0x%lx\n", fm_port[n]);
+ else {
+ error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (error < 0)
+ return error;
+ }
}
- if (xmpu_irq >= 0 && xmpu_irq != SNDRV_AUTO_IRQ && chip->mpu_port > 0) {
- if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
- chip->mpu_port, 0,
- xmpu_irq,
- SA_INTERRUPT,
- NULL)) < 0)
- goto _err;
+ if (mpu_irq[n] >= 0 && mpu_irq[n] != SNDRV_AUTO_IRQ &&
+ chip->mpu_port > 0) {
+ error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
+ chip->mpu_port, 0,
+ mpu_irq[n], NULL);
+ if (error < 0)
+ return error;
}
- snd_card_set_dev(card, &pdev->dev);
+ return snd_card_register(card);
+}
- if ((err = snd_card_register(card)) < 0)
- goto _err;
+static int snd_es1688_isa_probe(struct device *dev, unsigned int n)
+{
+ struct snd_card *card;
+ int error;
- platform_set_drvdata(pdev, card);
- return 0;
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
+ if (error < 0)
+ return error;
- _err:
+ error = snd_es1688_legacy_create(card, dev, n);
+ if (error < 0)
+ goto out;
+
+ error = snd_es1688_probe(card, n);
+ if (error < 0)
+ goto out;
+
+ dev_set_drvdata(dev, card);
+
+ return 0;
+out:
snd_card_free(card);
- return err;
+ return error;
}
-static int snd_es1688_remove(struct platform_device *devptr)
+static int snd_es1688_isa_remove(struct device *dev, unsigned int n)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(dev));
return 0;
}
-#define ES1688_DRIVER "snd_es1688"
-
-static struct platform_driver snd_es1688_driver = {
- .probe = snd_es1688_probe,
- .remove = snd_es1688_remove,
- /* FIXME: suspend/resume */
+static struct isa_driver snd_es1688_driver = {
+ .match = snd_es1688_match,
+ .probe = snd_es1688_isa_probe,
+ .remove = snd_es1688_isa_remove,
+#if 0 /* FIXME */
+ .suspend = snd_es1688_suspend,
+ .resume = snd_es1688_resume,
+#endif
.driver = {
- .name = ES1688_DRIVER
- },
+ .name = DEV_NAME
+ }
};
-static void __init_or_module snd_es1688_unregister_all(void)
+static int snd_es968_pnp_is_probed;
+
+#ifdef CONFIG_PNP
+static int snd_card_es968_pnp(struct snd_card *card, unsigned int n,
+ struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
- int i;
+ struct snd_es1688 *chip = card->private_data;
+ struct pnp_dev *pdev;
+ int error;
+
+ pdev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
+ if (pdev == NULL)
+ return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_es1688_driver);
+ error = pnp_activate_dev(pdev);
+ if (error < 0) {
+ snd_printk(KERN_ERR "ES968 pnp configure failure\n");
+ return error;
+ }
+ port[n] = pnp_port_start(pdev, 0);
+ dma8[n] = pnp_dma(pdev, 0);
+ irq[n] = pnp_irq(pdev, 0);
+
+ return snd_es1688_create(card, chip, port[n], mpu_port[n], irq[n],
+ mpu_irq[n], dma8[n], ES1688_HW_AUTO);
}
-static int __init alsa_card_es1688_init(void)
+static int snd_es968_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
- int i, cards, err;
-
- err = platform_driver_register(&snd_es1688_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(ES1688_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
+ struct snd_card *card;
+ static unsigned int dev;
+ int error;
+ struct snd_es1688 *chip;
+
+ if (snd_es968_pnp_is_probed)
+ return -EBUSY;
+ for ( ; dev < SNDRV_CARDS; dev++) {
+ if (enable[dev] && isapnp[dev])
+ break;
}
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR "ESS AudioDrive ES1688 soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
+ if (dev == SNDRV_CARDS)
+ return -ENODEV;
+
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
+ if (error < 0)
+ return error;
+ chip = card->private_data;
+
+ error = snd_card_es968_pnp(card, dev, pcard, pid);
+ if (error < 0) {
+ snd_card_free(card);
+ return error;
}
+ error = snd_es1688_probe(card, dev);
+ if (error < 0)
+ return error;
+ pnp_set_card_drvdata(pcard, card);
+ snd_es968_pnp_is_probed = 1;
return 0;
+}
- errout:
- snd_es1688_unregister_all();
- return err;
+static void snd_es968_pnp_remove(struct pnp_card_link *pcard)
+{
+ snd_card_free(pnp_get_card_drvdata(pcard));
+ pnp_set_card_drvdata(pcard, NULL);
+ snd_es968_pnp_is_probed = 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_es968_pnp_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+ struct snd_es1688 *chip = card->private_data;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ return 0;
+}
+
+static int snd_es968_pnp_resume(struct pnp_card_link *pcard)
+{
+ struct snd_card *card = pnp_get_card_drvdata(pcard);
+ struct snd_es1688 *chip = card->private_data;
+
+ snd_es1688_reset(chip);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
+static struct pnp_card_device_id snd_es968_pnpids[] = {
+ { .id = "ESS0968", .devs = { { "@@@0968" }, } },
+ { .id = "ESS0968", .devs = { { "ESS0968" }, } },
+ { .id = "", } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids);
+
+static struct pnp_card_driver es968_pnpc_driver = {
+ .flags = PNP_DRIVER_RES_DISABLE,
+ .name = DEV_NAME " PnP",
+ .id_table = snd_es968_pnpids,
+ .probe = snd_es968_pnp_detect,
+ .remove = snd_es968_pnp_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_es968_pnp_suspend,
+ .resume = snd_es968_pnp_resume,
+#endif
+};
+#endif
+
+static int __init alsa_card_es1688_init(void)
+{
+#ifdef CONFIG_PNP
+ pnp_register_card_driver(&es968_pnpc_driver);
+ if (snd_es968_pnp_is_probed)
+ return 0;
+ pnp_unregister_card_driver(&es968_pnpc_driver);
+#endif
+ return isa_register_driver(&snd_es1688_driver, SNDRV_CARDS);
}
static void __exit alsa_card_es1688_exit(void)
{
- snd_es1688_unregister_all();
+ if (!snd_es968_pnp_is_probed) {
+ isa_unregister_driver(&snd_es1688_driver);
+ return;
+ }
+#ifdef CONFIG_PNP
+ pnp_unregister_card_driver(&es968_pnpc_driver);
+#endif
}
-module_init(alsa_card_es1688_init)
-module_exit(alsa_card_es1688_exit)
+module_init(alsa_card_es1688_init);
+module_exit(alsa_card_es1688_exit);
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 702ad51ee9d..b3b4f15e45b 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of ESS ES1688/688/488 chip
*
*
@@ -19,12 +19,12 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ioport.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/es1688.h>
#include <sound/initval.h>
@@ -32,7 +32,7 @@
#include <asm/io.h>
#include <asm/dma.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("ESS ESx688 lowlevel module");
MODULE_LICENSE("GPL");
@@ -46,7 +46,7 @@ static int snd_es1688_dsp_command(struct snd_es1688 *chip, unsigned char val)
return 1;
}
#ifdef CONFIG_SND_DEBUG
- printk("snd_es1688_dsp_command: timeout (0x%x)\n", val);
+ printk(KERN_DEBUG "snd_es1688_dsp_command: timeout (0x%x)\n", val);
#endif
return 0;
}
@@ -100,7 +100,7 @@ static unsigned char snd_es1688_mixer_read(struct snd_es1688 *chip, unsigned cha
return result;
}
-static int snd_es1688_reset(struct snd_es1688 *chip)
+int snd_es1688_reset(struct snd_es1688 *chip)
{
int i;
@@ -116,6 +116,7 @@ static int snd_es1688_reset(struct snd_es1688 *chip)
snd_es1688_dsp_command(chip, 0xc6); /* enable extended mode */
return 0;
}
+EXPORT_SYMBOL(snd_es1688_reset);
static int snd_es1688_probe(struct snd_es1688 *chip)
{
@@ -168,13 +169,16 @@ static int snd_es1688_probe(struct snd_es1688 *chip)
hw = ES1688_HW_AUTO;
switch (chip->version & 0xfff0) {
case 0x4880:
- snd_printk("[0x%lx] ESS: AudioDrive ES488 detected, but driver is in another place\n", chip->port);
+ snd_printk(KERN_ERR "[0x%lx] ESS: AudioDrive ES488 detected, "
+ "but driver is in another place\n", chip->port);
return -ENODEV;
case 0x6880:
hw = (chip->version & 0x0f) >= 8 ? ES1688_HW_1688 : ES1688_HW_688;
break;
default:
- snd_printk("[0x%lx] ESS: unknown AudioDrive chip with version 0x%x (Jazz16 soundcard?)\n", chip->port, chip->version);
+ snd_printk(KERN_ERR "[0x%lx] ESS: unknown AudioDrive chip "
+ "with version 0x%x (Jazz16 soundcard?)\n",
+ chip->port, chip->version);
return -ENODEV;
}
@@ -224,7 +228,7 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
}
}
#if 0
- snd_printk("mpu cfg = 0x%x\n", cfg);
+ snd_printk(KERN_DEBUG "mpu cfg = 0x%x\n", cfg);
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
snd_es1688_mixer_write(chip, 0x40, cfg);
@@ -238,7 +242,9 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
cfg = 0xf0; /* enable only DMA counter interrupt */
irq_bits = irqs[chip->irq & 0x0f];
if (irq_bits < 0) {
- snd_printk("[0x%lx] ESS: bad IRQ %d for ES1688 chip!!\n", chip->port, chip->irq);
+ snd_printk(KERN_ERR "[0x%lx] ESS: bad IRQ %d "
+ "for ES1688 chip!!\n",
+ chip->port, chip->irq);
#if 0
irq_bits = 0;
cfg = 0x10;
@@ -251,7 +257,8 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
cfg = 0xf0; /* extended mode DMA enable */
dma = chip->dma8;
if (dma > 3 || dma == 2) {
- snd_printk("[0x%lx] ESS: bad DMA channel %d for ES1688 chip!!\n", chip->port, dma);
+ snd_printk(KERN_ERR "[0x%lx] ESS: bad DMA channel %d "
+ "for ES1688 chip!!\n", chip->port, dma);
#if 0
dma_bits = 0;
cfg = 0x00; /* disable all DMA */
@@ -342,8 +349,9 @@ static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char va
return -EINVAL; /* something is wrong */
}
#if 0
- printk("trigger: val = 0x%x, value = 0x%x\n", val, value);
- printk("trigger: pointer = 0x%x\n", snd_dma_pointer(chip->dma8, chip->dma_size));
+ printk(KERN_DEBUG "trigger: val = 0x%x, value = 0x%x\n", val, value);
+ printk(KERN_DEBUG "trigger: pointer = 0x%x\n",
+ snd_dma_pointer(chip->dma8, chip->dma_size));
#endif
snd_es1688_write(chip, 0xb8, (val & 0xf0) | value);
spin_unlock(&chip->reg_lock);
@@ -479,7 +487,7 @@ static int snd_es1688_capture_trigger(struct snd_pcm_substream *substream,
return snd_es1688_trigger(chip, cmd, 0x0f);
}
-static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id)
{
struct snd_es1688 *chip = dev_id;
@@ -604,17 +612,16 @@ static int snd_es1688_capture_close(struct snd_pcm_substream *substream)
static int snd_es1688_free(struct snd_es1688 *chip)
{
- if (chip->res_port) {
+ if (chip->hardware != ES1688_HW_UNDEF)
snd_es1688_init(chip, 0);
+ if (chip->res_port)
release_and_free_resource(chip->res_port);
- }
if (chip->irq >= 0)
free_irq(chip->irq, (void *) chip);
if (chip->dma8 >= 0) {
disable_dma(chip->dma8);
free_dma(chip->dma8);
}
- kfree(chip);
return 0;
}
@@ -632,49 +639,50 @@ static const char *snd_es1688_chip_id(struct snd_es1688 *chip)
}
int snd_es1688_create(struct snd_card *card,
+ struct snd_es1688 *chip,
unsigned long port,
unsigned long mpu_port,
int irq,
int mpu_irq,
int dma8,
- unsigned short hardware,
- struct snd_es1688 **rchip)
+ unsigned short hardware)
{
static struct snd_device_ops ops = {
.dev_free = snd_es1688_dev_free,
};
- struct snd_es1688 *chip;
int err;
- *rchip = NULL;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->irq = -1;
chip->dma8 = -1;
+ chip->hardware = ES1688_HW_UNDEF;
- if ((chip->res_port = request_region(port + 4, 12, "ES1688")) == NULL) {
+ chip->res_port = request_region(port + 4, 12, "ES1688");
+ if (chip->res_port == NULL) {
snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4);
- snd_es1688_free(chip);
- return -EBUSY;
+ err = -EBUSY;
+ goto exit;
}
- if (request_irq(irq, snd_es1688_interrupt, SA_INTERRUPT, "ES1688", (void *) chip)) {
+
+ err = request_irq(irq, snd_es1688_interrupt, 0, "ES1688", (void *) chip);
+ if (err < 0) {
snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq);
- snd_es1688_free(chip);
- return -EBUSY;
+ goto exit;
}
+
chip->irq = irq;
- if (request_dma(dma8, "ES1688")) {
+ err = request_dma(dma8, "ES1688");
+
+ if (err < 0) {
snd_printk(KERN_ERR "es1688: can't grab DMA8 %d\n", dma8);
- snd_es1688_free(chip);
- return -EBUSY;
+ goto exit;
}
chip->dma8 = dma8;
spin_lock_init(&chip->reg_lock);
spin_lock_init(&chip->mixer_lock);
- chip->card = card;
chip->port = port;
mpu_port &= ~0x000f;
if (mpu_port < 0x300 || mpu_port > 0x330)
@@ -683,23 +691,20 @@ int snd_es1688_create(struct snd_card *card,
chip->mpu_irq = mpu_irq;
chip->hardware = hardware;
- if ((err = snd_es1688_probe(chip)) < 0) {
- snd_es1688_free(chip);
- return err;
- }
- if ((err = snd_es1688_init(chip, 1)) < 0) {
- snd_es1688_free(chip);
- return err;
- }
+ err = snd_es1688_probe(chip);
+ if (err < 0)
+ goto exit;
+
+ err = snd_es1688_init(chip, 1);
+ if (err < 0)
+ goto exit;
/* Register device */
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+exit:
+ if (err)
snd_es1688_free(chip);
- return err;
- }
-
- *rchip = chip;
- return 0;
+ return err;
}
static struct snd_pcm_ops snd_es1688_playback_ops = {
@@ -724,12 +729,14 @@ static struct snd_pcm_ops snd_es1688_capture_ops = {
.pointer = snd_es1688_capture_pointer,
};
-int snd_es1688_pcm(struct snd_es1688 * chip, int device, struct snd_pcm ** rpcm)
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
+ int device, struct snd_pcm **rpcm)
{
struct snd_pcm *pcm;
int err;
- if ((err = snd_pcm_new(chip->card, "ESx688", device, 1, 1, &pcm)) < 0)
+ err = snd_pcm_new(card, "ESx688", device, 1, 1, &pcm);
+ if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1688_playback_ops);
@@ -976,7 +983,7 @@ ES1688_DOUBLE("CD Playback Volume", 0, ES1688_CD_DEV, ES1688_CD_DEV, 4, 0, 15, 0
ES1688_DOUBLE("FM Playback Volume", 0, ES1688_FM_DEV, ES1688_FM_DEV, 4, 0, 15, 0),
ES1688_DOUBLE("Mic Playback Volume", 0, ES1688_MIC_DEV, ES1688_MIC_DEV, 4, 0, 15, 0),
ES1688_DOUBLE("Aux Playback Volume", 0, ES1688_AUX_DEV, ES1688_AUX_DEV, 4, 0, 15, 0),
-ES1688_SINGLE("PC Speaker Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),
+ES1688_SINGLE("Beep Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),
ES1688_DOUBLE("Capture Volume", 0, ES1688_RECLEV_DEV, ES1688_RECLEV_DEV, 4, 0, 15, 0),
ES1688_SINGLE("Capture Switch", 0, ES1688_REC_DEV, 4, 1, 1),
{
@@ -1003,16 +1010,14 @@ static unsigned char snd_es1688_init_table[][2] = {
{ ES1688_REC_DEV, 0x17 }
};
-int snd_es1688_mixer(struct snd_es1688 *chip)
+int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip)
{
- struct snd_card *card;
unsigned int idx;
int err;
unsigned char reg, val;
- snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
-
- card = chip->card;
+ if (snd_BUG_ON(!chip || !card))
+ return -EINVAL;
strcpy(card->mixername, snd_es1688_chip_id(chip));
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index bf5de0782eb..6faaac60161 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -49,6 +49,10 @@
* - contrarily to some pages in DS_1869.PDF the rates can be set
* independently.
*
+ * - Zoom Video is implemented by sharing the FM DAC, thus the user can
+ * have either FM playback or Video playback but not both simultaneously.
+ * The Video Playback Switch mixer control toggles this choice.
+ *
* BUGS:
*
* - There is a major trouble I noted:
@@ -63,15 +67,24 @@
*
*/
-
-#include <sound/driver.h>
+/*
+ * ES1879 NOTES:
+ * - When Zoom Video is enabled (reg 0x71 bit 6 toggled on) the PCM playback
+ * seems to be effected (speaker_test plays a lower frequency). Can't find
+ * anything in the datasheet to account for this, so a Video Playback Switch
+ * control has been included to allow ZV to be enabled only when necessary.
+ * Then again on at least one test system the 0x71 bit 6 enable bit is not
+ * needed for ZV, so maybe the datasheet is entirely wrong here.
+ */
+
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <linux/isa.h>
#include <linux/pnp.h>
#include <linux/isapnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
#include <asm/io.h>
#include <asm/dma.h>
#include <sound/core.h>
@@ -88,8 +101,6 @@
struct snd_es18xx {
unsigned long port; /* port of ESS chip */
- unsigned long mpu_port; /* MPU-401 port of ESS chip */
- unsigned long fm_port; /* FM port */
unsigned long ctrl_port; /* Control port of ESS chip */
struct resource *res_port;
struct resource *res_mpu_port;
@@ -102,12 +113,9 @@ struct snd_es18xx {
unsigned short audio2_vol; /* volume level of audio2 */
unsigned short active; /* active channel mask */
- unsigned int dma1_size;
- unsigned int dma2_size;
unsigned int dma1_shift;
unsigned int dma2_shift;
- struct snd_card *card;
struct snd_pcm *pcm;
struct snd_pcm_substream *playback_a_substream;
struct snd_pcm_substream *capture_a_substream;
@@ -122,14 +130,9 @@ struct snd_es18xx {
spinlock_t reg_lock;
spinlock_t mixer_lock;
- spinlock_t ctrl_lock;
#ifdef CONFIG_PM
unsigned char pm_reg;
#endif
-};
-
-struct snd_audiodrive {
- struct snd_es18xx *chip;
#ifdef CONFIG_PNP
struct pnp_dev *dev;
struct pnp_dev *devc;
@@ -148,7 +151,7 @@ struct snd_audiodrive {
#define ES18XX_DUPLEX_SAME 0x0010 /* Playback and record must share the same rate */
#define ES18XX_NEW_RATE 0x0020 /* More precise rate setting */
#define ES18XX_AUXB 0x0040 /* AuxB mixer control */
-#define ES18XX_HWV 0x0080 /* Has hardware volume */
+#define ES18XX_HWV 0x0080 /* Has separate hardware volume mixer controls*/
#define ES18XX_MONO 0x0100 /* Mono_in mixer control */
#define ES18XX_I2S 0x0200 /* I2S mixer control */
#define ES18XX_MUTEREC 0x0400 /* Record source can be muted */
@@ -481,8 +484,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip,
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
- chip->dma2_size = size;
-
snd_es18xx_rate_set(chip, substream, DAC2);
/* Transfer Count Reload */
@@ -519,7 +520,7 @@ static int snd_es18xx_playback1_trigger(struct snd_es18xx *chip,
snd_es18xx_mixer_write(chip, 0x78, 0x93);
#ifdef AVOID_POPS
/* Avoid pops */
- udelay(100000);
+ mdelay(100);
if (chip->caps & ES18XX_PCM2)
/* Restore Audio 2 volume */
snd_es18xx_mixer_write(chip, 0x7C, chip->audio2_vol);
@@ -536,7 +537,7 @@ static int snd_es18xx_playback1_trigger(struct snd_es18xx *chip,
/* Stop DMA */
snd_es18xx_mixer_write(chip, 0x78, 0x00);
#ifdef AVOID_POPS
- udelay(25000);
+ mdelay(25);
if (chip->caps & ES18XX_PCM2)
/* Set Audio 2 volume to 0 */
snd_es18xx_mixer_write(chip, 0x7C, 0);
@@ -582,8 +583,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
- chip->dma1_size = size;
-
snd_es18xx_reset_fifo(chip);
/* Set stereo/mono */
@@ -597,7 +596,7 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
snd_es18xx_write(chip, 0xA5, count >> 8);
#ifdef AVOID_POPS
- udelay(100000);
+ mdelay(100);
#endif
/* Set format */
@@ -608,7 +607,7 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
(snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) |
(snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20));
- /* Set DMA controler */
+ /* Set DMA controller */
snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
return 0;
@@ -650,8 +649,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip,
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
- chip->dma1_size = size;
-
snd_es18xx_reset_fifo(chip);
/* Set stereo/mono */
@@ -674,7 +671,7 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip,
(snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) |
(snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20));
- /* Set DMA controler */
+ /* Set DMA controller */
snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
return 0;
@@ -694,7 +691,7 @@ static int snd_es18xx_playback2_trigger(struct snd_es18xx *chip,
snd_es18xx_write(chip, 0xB8, 0x05);
#ifdef AVOID_POPS
/* Avoid pops */
- udelay(100000);
+ mdelay(100);
/* Enable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD1);
#endif
@@ -708,7 +705,7 @@ static int snd_es18xx_playback2_trigger(struct snd_es18xx *chip,
snd_es18xx_write(chip, 0xB8, 0x00);
#ifdef AVOID_POPS
/* Avoid pops */
- udelay(25000);
+ mdelay(25);
/* Disable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD3);
#endif
@@ -739,9 +736,10 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream,
return snd_es18xx_playback2_trigger(chip, substream, cmd);
}
-static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
{
- struct snd_es18xx *chip = dev_id;
+ struct snd_card *card = dev_id;
+ struct snd_es18xx *chip = card->private_data;
unsigned char status;
if (chip->caps & ES18XX_CONTROL) {
@@ -784,16 +782,23 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *r
/* MPU */
if ((status & MPU_IRQ) && chip->rmidi)
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
/* Hardware volume */
if (status & HWV_IRQ) {
- int split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
+ int split = 0;
+ if (chip->caps & ES18XX_HWV) {
+ split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->hw_switch->id);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->hw_volume->id);
+ }
if (!split) {
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_switch->id);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_volume->id);
}
/* ack interrupt */
snd_es18xx_mixer_write(chip, 0x66, 0x00);
@@ -804,17 +809,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *r
static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream)
{
struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
+ unsigned int size = snd_pcm_lib_buffer_bytes(substream);
int pos;
if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
if (!(chip->active & DAC2))
return 0;
- pos = snd_dma_pointer(chip->dma2, chip->dma2_size);
+ pos = snd_dma_pointer(chip->dma2, size);
return pos >> chip->dma2_shift;
} else {
if (!(chip->active & DAC1))
return 0;
- pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
+ pos = snd_dma_pointer(chip->dma1, size);
return pos >> chip->dma1_shift;
}
}
@@ -822,11 +828,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s
static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream)
{
struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
+ unsigned int size = snd_pcm_lib_buffer_bytes(substream);
int pos;
if (!(chip->active & ADC1))
return 0;
- pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
+ pos = snd_dma_pointer(chip->dma1, size);
return pos >> chip->dma1_shift;
}
@@ -939,47 +946,119 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
* MIXER part
*/
+/* Record source mux routines:
+ * Depending on the chipset this mux switches between 4, 5, or 8 possible inputs.
+ * bit table for the 4/5 source mux:
+ * reg 1C:
+ * b2 b1 b0 muxSource
+ * x 0 x microphone
+ * 0 1 x CD
+ * 1 1 0 line
+ * 1 1 1 mixer
+ * if it's "mixer" and it's a 5 source mux chipset then reg 7A bit 3 determines
+ * either the play mixer or the capture mixer.
+ *
+ * "map4Source" translates from source number to reg bit pattern
+ * "invMap4Source" translates from reg bit pattern to source number
+ */
+
static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[8] = {
+ static char *texts5Source[5] = {
+ "Mic", "CD", "Line", "Master", "Mix"
+ };
+ static char *texts8Source[8] = {
"Mic", "Mic Master", "CD", "AOUT",
"Mic1", "Mix", "Line", "Master"
};
+ struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ switch (chip->version) {
+ case 0x1868:
+ case 0x1878:
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item > 3)
+ uinfo->value.enumerated.item = 3;
+ strcpy(uinfo->value.enumerated.name,
+ texts5Source[uinfo->value.enumerated.item]);
+ break;
+ case 0x1887:
+ case 0x1888:
+ uinfo->value.enumerated.items = 5;
+ if (uinfo->value.enumerated.item > 4)
+ uinfo->value.enumerated.item = 4;
+ strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]);
+ break;
+ case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */
+ case 0x1879:
+ uinfo->value.enumerated.items = 8;
+ if (uinfo->value.enumerated.item > 7)
+ uinfo->value.enumerated.item = 7;
+ strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]);
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
+ static unsigned char invMap4Source[8] = {0, 0, 1, 1, 0, 0, 2, 3};
struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
- ucontrol->value.enumerated.item[0] = snd_es18xx_mixer_read(chip, 0x1c) & 0x07;
+ int muxSource = snd_es18xx_mixer_read(chip, 0x1c) & 0x07;
+ if (!(chip->version == 0x1869 || chip->version == 0x1879)) {
+ muxSource = invMap4Source[muxSource];
+ if (muxSource==3 &&
+ (chip->version == 0x1887 || chip->version == 0x1888) &&
+ (snd_es18xx_mixer_read(chip, 0x7a) & 0x08)
+ )
+ muxSource = 4;
+ }
+ ucontrol->value.enumerated.item[0] = muxSource;
return 0;
}
static int snd_es18xx_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
+ static unsigned char map4Source[4] = {0, 2, 6, 7};
struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
unsigned char val = ucontrol->value.enumerated.item[0];
-
- if (val > 7)
+ unsigned char retVal = 0;
+
+ switch (chip->version) {
+ /* 5 source chips */
+ case 0x1887:
+ case 0x1888:
+ if (val > 4)
+ return -EINVAL;
+ if (val == 4) {
+ retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x08) != 0x08;
+ val = 3;
+ } else
+ retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x00) != 0x00;
+ /* 4 source chips */
+ case 0x1868:
+ case 0x1878:
+ if (val > 3)
+ return -EINVAL;
+ val = map4Source[val];
+ break;
+ /* 8 source chips */
+ case 0x1869:
+ case 0x1879:
+ if (val > 7)
+ return -EINVAL;
+ break;
+ default:
return -EINVAL;
- return snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val;
+ }
+ return (snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val) || retVal;
}
-static int snd_es18xx_info_spatializer_enable(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;
-}
+#define snd_es18xx_info_spatializer_enable snd_ctl_boolean_mono_info
static int snd_es18xx_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -1021,14 +1100,7 @@ static int snd_es18xx_get_hw_volume(struct snd_kcontrol *kcontrol, struct snd_ct
return 0;
}
-static int snd_es18xx_info_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_es18xx_info_hw_switch snd_ctl_boolean_stereo_info
static int snd_es18xx_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -1191,19 +1263,22 @@ static int snd_es18xx_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return change;
}
+/* Mixer controls
+ * These arrays contain setup data for mixer controls.
+ *
+ * The controls that are universal to all chipsets are fully initialized
+ * here.
+ */
static struct snd_kcontrol_new snd_es18xx_base_controls[] = {
ES18XX_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),
ES18XX_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
ES18XX_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0),
ES18XX_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),
ES18XX_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0),
-ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
ES18XX_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0),
ES18XX_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0),
-ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0),
ES18XX_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
ES18XX_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0),
-ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
@@ -1213,19 +1288,37 @@ ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
}
};
-static struct snd_kcontrol_new snd_es18xx_mono_in_control =
-ES18XX_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0);
-
static struct snd_kcontrol_new snd_es18xx_recmix_controls[] = {
ES18XX_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0),
ES18XX_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0),
ES18XX_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0),
ES18XX_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0),
-ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0),
ES18XX_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0),
ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0)
};
+/*
+ * The chipset specific mixer controls
+ */
+static struct snd_kcontrol_new snd_es18xx_opt_speaker =
+ ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
+
+static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
+ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
+ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
+ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
+};
+
+static struct snd_kcontrol_new snd_es18xx_opt_1878 =
+ ES18XX_DOUBLE("Video Playback Volume", 0, 0x68, 0x68, 4, 0, 15, 0);
+
+static struct snd_kcontrol_new snd_es18xx_opt_1879[] = {
+ES18XX_SINGLE("Video Playback Switch", 0, 0x71, 6, 1, 0),
+ES18XX_DOUBLE("Video Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+ES18XX_DOUBLE("Video Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
+};
+
static struct snd_kcontrol_new snd_es18xx_pcm1_controls[] = {
ES18XX_DOUBLE("PCM Playback Volume", 0, 0x14, 0x14, 4, 0, 15, 0),
};
@@ -1270,21 +1363,17 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = {
ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
};
-#if 0
-static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
+static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
{
int data;
- unsigned long flags;
- spin_lock_irqsave(&chip->ctrl_lock, flags);
+
outb(reg, chip->ctrl_port);
data = inb(chip->ctrl_port + 1);
- spin_unlock_irqrestore(&chip->ctrl_lock, flags);
return data;
}
-#endif
-static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip,
- unsigned char reg, unsigned char data)
+static void snd_es18xx_config_write(struct snd_es18xx *chip,
+ unsigned char reg, unsigned char data)
{
/* No need for spinlocks, this function is used only in
otherwise protected init code */
@@ -1295,7 +1384,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip,
#endif
}
-static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
+static int snd_es18xx_initialize(struct snd_es18xx *chip,
+ unsigned long mpu_port,
+ unsigned long fm_port)
{
int mask = 0;
@@ -1309,15 +1400,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
if (chip->caps & ES18XX_CONTROL) {
/* Hardware volume IRQ */
snd_es18xx_config_write(chip, 0x27, chip->irq);
- if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
+ if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
/* FM I/O */
- snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8);
- snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff);
+ snd_es18xx_config_write(chip, 0x62, fm_port >> 8);
+ snd_es18xx_config_write(chip, 0x63, fm_port & 0xff);
}
- if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
+ if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
/* MPU-401 I/O */
- snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8);
- snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff);
+ snd_es18xx_config_write(chip, 0x64, mpu_port >> 8);
+ snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff);
/* MPU-401 IRQ */
snd_es18xx_config_write(chip, 0x28, chip->irq);
}
@@ -1338,6 +1429,8 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
snd_es18xx_write(chip, 0xB2, 0x50);
/* Enable MPU and hardware volume interrupt */
snd_es18xx_mixer_write(chip, 0x64, 0x42);
+ /* Enable ESS wavetable input */
+ snd_es18xx_mixer_bits(chip, 0x48, 0x10, 0x10);
}
else {
int irqmask, dma1mask, dma2mask;
@@ -1402,11 +1495,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
snd_es18xx_mixer_write(chip, 0x7A, 0x68);
/* Enable and set hardware volume interrupt */
snd_es18xx_mixer_write(chip, 0x64, 0x06);
- if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
+ if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
/* MPU401 share irq with audio
Joystick enabled
FM enabled */
- snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1);
+ snd_es18xx_mixer_write(chip, 0x40,
+ 0x43 | (mpu_port & 0xf0) >> 1);
}
snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01);
}
@@ -1427,6 +1521,17 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
snd_es18xx_mixer_write(chip, 0x58, 0x94);
snd_es18xx_mixer_write(chip, 0x5a, 0x80);
}
+ /* Flip the "enable I2S" bits for those chipsets that need it */
+ switch (chip->version) {
+ case 0x1879:
+ //Leaving I2S enabled on the 1879 screws up the PCM playback (rate effected somehow)
+ //so a Switch control has been added to toggle this 0x71 bit on/off:
+ //snd_es18xx_mixer_bits(chip, 0x71, 0x40, 0x40);
+ /* Note: we fall through on purpose here. */
+ case 0x1878:
+ snd_es18xx_config_write(chip, 0x29, snd_es18xx_config_read(chip, 0x29) | 0x40);
+ break;
+ }
/* Mute input source */
if (chip->caps & ES18XX_MUTEREC)
mask = 0x10;
@@ -1444,7 +1549,7 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
return 0;
}
-static int __devinit snd_es18xx_identify(struct snd_es18xx *chip)
+static int snd_es18xx_identify(struct snd_es18xx *chip)
{
int hi,lo;
@@ -1476,11 +1581,14 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip)
}
outb(0x40, chip->port + 0x04);
+ udelay(10);
hi = inb(chip->port + 0x05);
+ udelay(10);
lo = inb(chip->port + 0x05);
if (hi != lo) {
chip->version = hi << 8 | lo;
chip->ctrl_port = inb(chip->port + 0x05) << 8;
+ udelay(10);
chip->ctrl_port += inb(chip->port + 0x05);
if ((chip->res_ctrl_port = request_region(chip->ctrl_port, 8, "ES18xx - CTRL")) == NULL) {
@@ -1510,7 +1618,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip)
return 0;
}
-static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
+static int snd_es18xx_probe(struct snd_es18xx *chip,
+ unsigned long mpu_port,
+ unsigned long fm_port)
{
if (snd_es18xx_identify(chip) < 0) {
snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port);
@@ -1519,22 +1629,20 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
switch (chip->version) {
case 0x1868:
- chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_HWV;
+ chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL;
break;
case 0x1869:
chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV;
break;
case 0x1878:
- chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
+ chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
break;
case 0x1879:
chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
break;
case 0x1887:
- chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_HWV;
- break;
case 0x1888:
- chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_HWV;
+ chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
break;
default:
snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
@@ -1547,7 +1655,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
if (chip->dma1 == chip->dma2)
chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME);
- return snd_es18xx_initialize(chip);
+ return snd_es18xx_initialize(chip, mpu_port, fm_port);
}
static struct snd_pcm_ops snd_es18xx_playback_ops = {
@@ -1572,8 +1680,10 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = {
.pointer = snd_es18xx_capture_pointer,
};
-static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct snd_pcm ** rpcm)
+static int snd_es18xx_pcm(struct snd_card *card, int device,
+ struct snd_pcm **rpcm)
{
+ struct snd_es18xx *chip = card->private_data;
struct snd_pcm *pcm;
char str[16];
int err;
@@ -1582,9 +1692,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
*rpcm = NULL;
sprintf(str, "ES%x", chip->version);
if (chip->caps & ES18XX_PCM2)
- err = snd_pcm_new(chip->card, str, device, 2, 1, &pcm);
+ err = snd_pcm_new(card, str, device, 2, 1, &pcm);
else
- err = snd_pcm_new(chip->card, str, device, 1, 1, &pcm);
+ err = snd_pcm_new(card, str, device, 1, 1, &pcm);
if (err < 0)
return err;
@@ -1615,10 +1725,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
#ifdef CONFIG_PM
static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
{
- struct snd_audiodrive *acard = card->private_data;
- struct snd_es18xx *chip = acard->chip;
+ struct snd_es18xx *chip = card->private_data;
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
@@ -1633,24 +1742,25 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
static int snd_es18xx_resume(struct snd_card *card)
{
- struct snd_audiodrive *acard = card->private_data;
- struct snd_es18xx *chip = acard->chip;
+ struct snd_es18xx *chip = card->private_data;
/* restore PM register, we won't wake till (not 0x07) i/o activity though */
snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM);
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif /* CONFIG_PM */
-static int snd_es18xx_free(struct snd_es18xx *chip)
+static int snd_es18xx_free(struct snd_card *card)
{
+ struct snd_es18xx *chip = card->private_data;
+
release_and_free_resource(chip->res_port);
release_and_free_resource(chip->res_ctrl_port);
release_and_free_resource(chip->res_mpu_port);
if (chip->irq >= 0)
- free_irq(chip->irq, (void *) chip);
+ free_irq(chip->irq, (void *) card);
if (chip->dma1 >= 0) {
disable_dma(chip->dma1);
free_dma(chip->dma1);
@@ -1659,93 +1769,82 @@ static int snd_es18xx_free(struct snd_es18xx *chip)
disable_dma(chip->dma2);
free_dma(chip->dma2);
}
- kfree(chip);
return 0;
}
static int snd_es18xx_dev_free(struct snd_device *device)
{
- struct snd_es18xx *chip = device->device_data;
- return snd_es18xx_free(chip);
+ return snd_es18xx_free(device->card);
}
-static int __devinit snd_es18xx_new_device(struct snd_card *card,
- unsigned long port,
- unsigned long mpu_port,
- unsigned long fm_port,
- int irq, int dma1, int dma2,
- struct snd_es18xx ** rchip)
+static int snd_es18xx_new_device(struct snd_card *card,
+ unsigned long port,
+ unsigned long mpu_port,
+ unsigned long fm_port,
+ int irq, int dma1, int dma2)
{
- struct snd_es18xx *chip;
+ struct snd_es18xx *chip = card->private_data;
static struct snd_device_ops ops = {
.dev_free = snd_es18xx_dev_free,
};
int err;
- *rchip = NULL;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
spin_lock_init(&chip->reg_lock);
spin_lock_init(&chip->mixer_lock);
- spin_lock_init(&chip->ctrl_lock);
- chip->card = card;
chip->port = port;
- chip->mpu_port = mpu_port;
- chip->fm_port = fm_port;
chip->irq = -1;
chip->dma1 = -1;
chip->dma2 = -1;
chip->audio2_vol = 0x00;
chip->active = 0;
- if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) {
- snd_es18xx_free(chip);
+ chip->res_port = request_region(port, 16, "ES18xx");
+ if (chip->res_port == NULL) {
+ snd_es18xx_free(card);
snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1);
return -EBUSY;
}
- if (request_irq(irq, snd_es18xx_interrupt, SA_INTERRUPT, "ES18xx", (void *) chip)) {
- snd_es18xx_free(chip);
+ if (request_irq(irq, snd_es18xx_interrupt, 0, "ES18xx",
+ (void *) card)) {
+ snd_es18xx_free(card);
snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq);
return -EBUSY;
}
chip->irq = irq;
if (request_dma(dma1, "ES18xx DMA 1")) {
- snd_es18xx_free(chip);
+ snd_es18xx_free(card);
snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1);
return -EBUSY;
}
chip->dma1 = dma1;
if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) {
- snd_es18xx_free(chip);
+ snd_es18xx_free(card);
snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2);
return -EBUSY;
}
chip->dma2 = dma2;
- if (snd_es18xx_probe(chip) < 0) {
- snd_es18xx_free(chip);
- return -ENODEV;
- }
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
- snd_es18xx_free(chip);
+ if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) {
+ snd_es18xx_free(card);
+ return -ENODEV;
+ }
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0) {
+ snd_es18xx_free(card);
return err;
}
- *rchip = chip;
return 0;
}
-static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip)
+static int snd_es18xx_mixer(struct snd_card *card)
{
- struct snd_card *card;
+ struct snd_es18xx *chip = card->private_data;
int err;
unsigned int idx;
- card = chip->card;
-
strcpy(card->mixername, chip->pcm->name);
for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) {
@@ -1778,10 +1877,6 @@ static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip)
}
}
- if (chip->caps & ES18XX_MONO) {
- if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_mono_in_control, chip))) < 0)
- return err;
- }
if (chip->caps & ES18XX_RECMIX) {
for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_recmix_controls); idx++) {
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_recmix_controls[idx], chip))) < 0)
@@ -1819,6 +1914,36 @@ static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip)
}
}
+ /* finish initializing other chipset specific controls
+ */
+ if (chip->version != 0x1868) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_speaker,
+ chip));
+ if (err < 0)
+ return err;
+ }
+ if (chip->version == 0x1869) {
+ for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1869); idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_es18xx_opt_1869[idx],
+ chip));
+ if (err < 0)
+ return err;
+ }
+ } else if (chip->version == 0x1878) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_1878,
+ chip));
+ if (err < 0)
+ return err;
+ } else if (chip->version == 0x1879) {
+ for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1879); idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_es18xx_opt_1879[idx],
+ chip));
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
@@ -1839,9 +1964,9 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1868 PnP AudioDrive},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
#ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
#endif
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */
#ifndef CONFIG_PNP
@@ -1877,10 +2002,55 @@ MODULE_PARM_DESC(dma1, "DMA 1 # for ES18xx driver.");
module_param_array(dma2, int, NULL, 0444);
MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver.");
-static struct platform_device *platform_devices[SNDRV_CARDS];
+#ifdef CONFIG_PNP
+static int isa_registered;
static int pnp_registered;
+static int pnpc_registered;
-#ifdef CONFIG_PNP
+static struct pnp_device_id snd_audiodrive_pnpbiosids[] = {
+ { .id = "ESS1869" },
+ { .id = "ESS1879" },
+ { .id = "" } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids);
+
+/* PnP main device initialization */
+static int snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev)
+{
+ if (pnp_activate_dev(pdev) < 0) {
+ snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
+ return -EBUSY;
+ }
+ /* ok. hack using Vendor-Defined Card-Level registers */
+ /* skip csn and logdev initialization - already done in isapnp_configure */
+ if (pnp_device_is_isapnp(pdev)) {
+ isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
+ isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */
+ if (mpu_port[dev] != SNDRV_AUTO_PORT)
+ isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
+ isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */
+ isapnp_cfg_end();
+ }
+ port[dev] = pnp_port_start(pdev, 0);
+ fm_port[dev] = pnp_port_start(pdev, 1);
+ mpu_port[dev] = pnp_port_start(pdev, 2);
+ dma1[dev] = pnp_dma(pdev, 0);
+ dma2[dev] = pnp_dma(pdev, 1);
+ irq[dev] = pnp_irq(pdev, 0);
+ snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
+ snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
+ return 0;
+}
+
+static int snd_audiodrive_pnp(int dev, struct snd_es18xx *chip,
+ struct pnp_dev *pdev)
+{
+ chip->dev = pdev;
+ if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
+ return -EBUSY;
+ return 0;
+}
static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
/* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */
@@ -1903,78 +2073,28 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);
-static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
- struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
- int err;
-
- if (!cfg)
- return -ENOMEM;
- acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->dev == NULL) {
- kfree(cfg);
+ chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+ if (chip->dev == NULL)
return -EBUSY;
- }
- acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
- if (acard->devc == NULL) {
- kfree(cfg);
+
+ chip->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
+ if (chip->devc == NULL)
return -EBUSY;
- }
+
/* Control port initialization */
- err = pnp_activate_dev(acard->devc);
- if (err < 0) {
+ if (pnp_activate_dev(chip->devc) < 0) {
snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
return -EAGAIN;
}
- snd_printdd("pnp: port=0x%lx\n", pnp_port_start(acard->devc, 0));
- /* PnP initialization */
- pdev = acard->dev;
- pnp_init_resource_table(cfg);
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2);
- if (dma1[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
- if (dma2[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
- snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
- snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
- kfree(cfg);
+ snd_printdd("pnp: port=0x%llx\n",
+ (unsigned long long)pnp_port_start(chip->devc, 0));
+ if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
return -EBUSY;
- }
- /* ok. hack using Vendor-Defined Card-Level registers */
- /* skip csn and logdev initialization - already done in isapnp_configure */
- if (pnp_device_is_isapnp(pdev)) {
- isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
- isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
- isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */
- isapnp_cfg_end();
- } else {
- snd_printk(KERN_ERR PFX "unable to install ISA PnP hack, expect malfunction\n");
- }
- port[dev] = pnp_port_start(pdev, 0);
- fm_port[dev] = pnp_port_start(pdev, 1);
- mpu_port[dev] = pnp_port_start(pdev, 2);
- dma1[dev] = pnp_dma(pdev, 0);
- dma2[dev] = pnp_dma(pdev, 1);
- irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
- snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
- kfree(cfg);
+
return 0;
}
#endif /* CONFIG_PNP */
@@ -1985,27 +2105,24 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
#define is_isapnp_selected(dev) 0
#endif
-static struct snd_card *snd_es18xx_card_new(int dev)
+static int snd_es18xx_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
- return snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_audiodrive));
+ return snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_es18xx), cardp);
}
-static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
+static int snd_audiodrive_probe(struct snd_card *card, int dev)
{
- struct snd_audiodrive *acard = card->private_data;
- struct snd_es18xx *chip;
+ struct snd_es18xx *chip = card->private_data;
struct snd_opl3 *opl3;
int err;
- if ((err = snd_es18xx_new_device(card,
- port[dev],
- mpu_port[dev],
- fm_port[dev],
- irq[dev], dma1[dev], dma2[dev],
- &chip)) < 0)
+ err = snd_es18xx_new_device(card,
+ port[dev], mpu_port[dev], fm_port[dev],
+ irq[dev], dma1[dev], dma2[dev]);
+ if (err < 0)
return err;
- acard->chip = chip;
sprintf(card->driver, "ES%x", chip->version);
@@ -2021,52 +2138,61 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
chip->port,
irq[dev], dma1[dev]);
- if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0)
+ err = snd_es18xx_pcm(card, 0, NULL);
+ if (err < 0)
return err;
- if ((err = snd_es18xx_mixer(chip)) < 0)
+ err = snd_es18xx_mixer(card);
+ if (err < 0)
return err;
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
- if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) {
- snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port);
+ if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
+ OPL3_HW_OPL3, 0, &opl3) < 0) {
+ snd_printk(KERN_WARNING PFX
+ "opl3 not detected at 0x%lx\n",
+ fm_port[dev]);
} else {
- if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
return err;
}
}
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
- if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
- chip->mpu_port, 0,
- irq[dev], 0,
- &chip->rmidi)) < 0)
+ err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
+ mpu_port[dev], MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rmidi);
+ if (err < 0)
return err;
}
return snd_card_register(card);
}
-static int __init snd_es18xx_nonpnp_probe1(int dev, struct platform_device *devptr)
+static int snd_es18xx_isa_match(struct device *pdev, unsigned int dev)
+{
+ return enable[dev] && !is_isapnp_selected(dev);
+}
+
+static int snd_es18xx_isa_probe1(int dev, struct device *devptr)
{
struct snd_card *card;
int err;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
- snd_card_set_dev(card, &devptr->dev);
+ err = snd_es18xx_card_new(devptr, dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_audiodrive_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
}
- platform_set_drvdata(devptr, card);
+ dev_set_drvdata(devptr, card);
return 0;
}
-static int __init snd_es18xx_nonpnp_probe(struct platform_device *pdev)
+static int snd_es18xx_isa_probe(struct device *pdev, unsigned int dev)
{
- int dev = pdev->id;
int err;
static int possible_irqs[] = {5, 9, 10, 7, 11, 12, -1};
static int possible_dmas[] = {1, 0, 3, 5, -1};
@@ -2091,13 +2217,13 @@ static int __init snd_es18xx_nonpnp_probe(struct platform_device *pdev)
}
if (port[dev] != SNDRV_AUTO_PORT) {
- return snd_es18xx_nonpnp_probe1(dev, pdev);
+ return snd_es18xx_isa_probe1(dev, pdev);
} else {
static unsigned long possible_ports[] = {0x220, 0x240, 0x260, 0x280};
int i;
for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
port[dev] = possible_ports[i];
- err = snd_es18xx_nonpnp_probe1(dev, pdev);
+ err = snd_es18xx_isa_probe1(dev, pdev);
if (! err)
return 0;
}
@@ -2105,43 +2231,104 @@ static int __init snd_es18xx_nonpnp_probe(struct platform_device *pdev)
}
}
-static int __devexit snd_es18xx_nonpnp_remove(struct platform_device *devptr)
+static int snd_es18xx_isa_remove(struct device *devptr,
+ unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
return 0;
}
#ifdef CONFIG_PM
-static int snd_es18xx_nonpnp_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_es18xx_isa_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
{
- return snd_es18xx_suspend(platform_get_drvdata(dev), state);
+ return snd_es18xx_suspend(dev_get_drvdata(dev), state);
}
-static int snd_es18xx_nonpnp_resume(struct platform_device *dev)
+static int snd_es18xx_isa_resume(struct device *dev, unsigned int n)
{
- return snd_es18xx_resume(platform_get_drvdata(dev));
+ return snd_es18xx_resume(dev_get_drvdata(dev));
}
#endif
-#define ES18XX_DRIVER "snd_es18xx"
+#define DEV_NAME "es18xx"
-static struct platform_driver snd_es18xx_nonpnp_driver = {
- .probe = snd_es18xx_nonpnp_probe,
- .remove = __devexit_p(snd_es18xx_nonpnp_remove),
+static struct isa_driver snd_es18xx_isa_driver = {
+ .match = snd_es18xx_isa_match,
+ .probe = snd_es18xx_isa_probe,
+ .remove = snd_es18xx_isa_remove,
#ifdef CONFIG_PM
- .suspend = snd_es18xx_nonpnp_suspend,
- .resume = snd_es18xx_nonpnp_resume,
+ .suspend = snd_es18xx_isa_suspend,
+ .resume = snd_es18xx_isa_resume,
#endif
.driver = {
- .name = ES18XX_DRIVER
+ .name = DEV_NAME
},
};
#ifdef CONFIG_PNP
-static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
+ const struct pnp_device_id *id)
+{
+ static int dev;
+ int err;
+ struct snd_card *card;
+
+ if (pnp_device_is_isapnp(pdev))
+ return -ENOENT; /* we have another procedure - card */
+ for (; dev < SNDRV_CARDS; dev++) {
+ if (enable[dev] && isapnp[dev])
+ break;
+ }
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+
+ err = snd_es18xx_card_new(&pdev->dev, dev, &card);
+ if (err < 0)
+ return err;
+ if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ if ((err = snd_audiodrive_probe(card, dev)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ pnp_set_drvdata(pdev, card);
+ dev++;
+ return 0;
+}
+
+static void snd_audiodrive_pnp_remove(struct pnp_dev *pdev)
+{
+ snd_card_free(pnp_get_drvdata(pdev));
+}
+
+#ifdef CONFIG_PM
+static int snd_audiodrive_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+ return snd_es18xx_suspend(pnp_get_drvdata(pdev), state);
+}
+static int snd_audiodrive_pnp_resume(struct pnp_dev *pdev)
+{
+ return snd_es18xx_resume(pnp_get_drvdata(pdev));
+}
+#endif
+
+static struct pnp_driver es18xx_pnp_driver = {
+ .name = "es18xx-pnpbios",
+ .id_table = snd_audiodrive_pnpbiosids,
+ .probe = snd_audiodrive_pnp_detect,
+ .remove = snd_audiodrive_pnp_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_audiodrive_pnp_suspend,
+ .resume = snd_audiodrive_pnp_resume,
+#endif
+};
+
+static int snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
static int dev;
struct snd_card *card;
@@ -2154,15 +2341,14 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_es18xx_card_new(&pcard->card->dev, dev, &card);
+ if (res < 0)
+ return res;
- if ((res = snd_audiodrive_pnp(dev, card->private_data, pcard, pid)) < 0) {
+ if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) {
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_audiodrive_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
@@ -2173,19 +2359,19 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
return 0;
}
-static void __devexit snd_audiodrive_pnp_remove(struct pnp_card_link * pcard)
+static void snd_audiodrive_pnpc_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
}
#ifdef CONFIG_PM
-static int snd_audiodrive_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
+static int snd_audiodrive_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
{
return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state);
}
-static int snd_audiodrive_pnp_resume(struct pnp_card_link *pcard)
+static int snd_audiodrive_pnpc_resume(struct pnp_card_link *pcard)
{
return snd_es18xx_resume(pnp_get_card_drvdata(pcard));
}
@@ -2196,70 +2382,48 @@ static struct pnp_card_driver es18xx_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "es18xx",
.id_table = snd_audiodrive_pnpids,
- .probe = snd_audiodrive_pnp_detect,
- .remove = __devexit_p(snd_audiodrive_pnp_remove),
+ .probe = snd_audiodrive_pnpc_detect,
+ .remove = snd_audiodrive_pnpc_remove,
#ifdef CONFIG_PM
- .suspend = snd_audiodrive_pnp_suspend,
- .resume = snd_audiodrive_pnp_resume,
+ .suspend = snd_audiodrive_pnpc_suspend,
+ .resume = snd_audiodrive_pnpc_resume,
#endif
};
#endif /* CONFIG_PNP */
-static void __init_or_module snd_es18xx_unregister_all(void)
-{
- int i;
-
- if (pnp_registered)
- pnp_unregister_card_driver(&es18xx_pnpc_driver);
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&snd_es18xx_nonpnp_driver);
-}
-
static int __init alsa_card_es18xx_init(void)
{
- int i, err, cards = 0;
-
- if ((err = platform_driver_register(&snd_es18xx_nonpnp_driver)) < 0)
- return err;
+ int err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- if (is_isapnp_selected(i))
- continue;
- device = platform_device_register_simple(ES18XX_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- cards++;
- }
+ err = isa_register_driver(&snd_es18xx_isa_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+ if (!err)
+ isa_registered = 1;
- i = pnp_register_card_driver(&es18xx_pnpc_driver);
- if (i >= 0) {
+ err = pnp_register_driver(&es18xx_pnp_driver);
+ if (!err)
pnp_registered = 1;
- cards += i;
- }
- if(!cards) {
-#ifdef MODULE
- snd_printk(KERN_ERR "ESS AudioDrive ES18xx soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
+ err = pnp_register_card_driver(&es18xx_pnpc_driver);
+ if (!err)
+ pnpc_registered = 1;
- errout:
- snd_es18xx_unregister_all();
+ if (isa_registered || pnp_registered)
+ err = 0;
+#endif
return err;
}
static void __exit alsa_card_es18xx_exit(void)
{
- snd_es18xx_unregister_all();
+#ifdef CONFIG_PNP
+ if (pnpc_registered)
+ pnp_unregister_card_driver(&es18xx_pnpc_driver);
+ if (pnp_registered)
+ pnp_unregister_driver(&es18xx_pnp_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_es18xx_isa_driver);
}
module_init(alsa_card_es18xx_init)
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile
new file mode 100644
index 00000000000..e307066d431
--- /dev/null
+++ b/sound/isa/galaxy/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-azt1605-objs := azt1605.o
+snd-azt2316-objs := azt2316.o
+
+obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
+obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c
new file mode 100644
index 00000000000..9a97643cb71
--- /dev/null
+++ b/sound/isa/galaxy/azt1605.c
@@ -0,0 +1,91 @@
+/*
+ * Aztech AZT1605 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT1605
+
+#define CRD_NAME "Aztech AZT1605"
+#define DRV_NAME "AZT1605"
+#define DEV_NAME "azt1605"
+
+#define GALAXY_DSP_MAJOR 2
+#define GALAXY_DSP_MINOR 1
+
+#define GALAXY_CONFIG_SIZE 3
+
+/*
+ * 24-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220 (0 << 0)
+#define GALAXY_CONFIG_SBA_240 (1 << 0)
+#define GALAXY_CONFIG_SBA_260 (2 << 0)
+#define GALAXY_CONFIG_SBA_280 (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_MPUA_300 (0 << 2)
+#define GALAXY_CONFIG_MPUA_330 (1 << 2)
+
+#define GALAXY_CONFIG_MPU_ENABLE (1 << 3)
+
+#define GALAXY_CONFIG_GAME_ENABLE (1 << 4)
+
+#define GALAXY_CONFIG_CD_PANASONIC (1 << 5)
+#define GALAXY_CONFIG_CD_MITSUMI (1 << 6)
+#define GALAXY_CONFIG_CD_MASK (\
+ GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
+
+#define GALAXY_CONFIG_UNUSED (1 << 7)
+#define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED
+
+#define GALAXY_CONFIG_SBIRQ_2 (1 << 8)
+#define GALAXY_CONFIG_SBIRQ_3 (1 << 9)
+#define GALAXY_CONFIG_SBIRQ_5 (1 << 10)
+#define GALAXY_CONFIG_SBIRQ_7 (1 << 11)
+
+#define GALAXY_CONFIG_MPUIRQ_2 (1 << 12)
+#define GALAXY_CONFIG_MPUIRQ_3 (1 << 13)
+#define GALAXY_CONFIG_MPUIRQ_5 (1 << 14)
+#define GALAXY_CONFIG_MPUIRQ_7 (1 << 15)
+
+#define GALAXY_CONFIG_WSSA_530 (0 << 16)
+#define GALAXY_CONFIG_WSSA_604 (1 << 16)
+#define GALAXY_CONFIG_WSSA_E80 (2 << 16)
+#define GALAXY_CONFIG_WSSA_F40 (3 << 16)
+
+#define GALAXY_CONFIG_WSS_ENABLE (1 << 18)
+
+#define GALAXY_CONFIG_CDIRQ_11 (1 << 19)
+#define GALAXY_CONFIG_CDIRQ_12 (1 << 20)
+#define GALAXY_CONFIG_CDIRQ_15 (1 << 21)
+#define GALAXY_CONFIG_CDIRQ_MASK (\
+ GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
+ GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22)
+#define GALAXY_CONFIG_CDDMA_0 (1 << 22)
+#define GALAXY_CONFIG_CDDMA_1 (2 << 22)
+#define GALAXY_CONFIG_CDDMA_3 (3 << 22)
+#define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3
+
+#define GALAXY_CONFIG_MASK (\
+ GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
+ GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
+ GALAXY_CONFIG_CDDMA_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c
new file mode 100644
index 00000000000..189441141df
--- /dev/null
+++ b/sound/isa/galaxy/azt2316.c
@@ -0,0 +1,111 @@
+/*
+ * Aztech AZT2316 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT2316
+
+#define CRD_NAME "Aztech AZT2316"
+#define DRV_NAME "AZT2316"
+#define DEV_NAME "azt2316"
+
+#define GALAXY_DSP_MAJOR 3
+#define GALAXY_DSP_MINOR 1
+
+#define GALAXY_CONFIG_SIZE 4
+
+/*
+ * 32-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220 (0 << 0)
+#define GALAXY_CONFIG_SBA_240 (1 << 0)
+#define GALAXY_CONFIG_SBA_260 (2 << 0)
+#define GALAXY_CONFIG_SBA_280 (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_SBIRQ_2 (1 << 2)
+#define GALAXY_CONFIG_SBIRQ_5 (1 << 3)
+#define GALAXY_CONFIG_SBIRQ_7 (1 << 4)
+#define GALAXY_CONFIG_SBIRQ_10 (1 << 5)
+
+#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6)
+#define GALAXY_CONFIG_SBDMA_0 (1 << 6)
+#define GALAXY_CONFIG_SBDMA_1 (2 << 6)
+#define GALAXY_CONFIG_SBDMA_3 (3 << 6)
+
+#define GALAXY_CONFIG_WSSA_530 (0 << 8)
+#define GALAXY_CONFIG_WSSA_604 (1 << 8)
+#define GALAXY_CONFIG_WSSA_E80 (2 << 8)
+#define GALAXY_CONFIG_WSSA_F40 (3 << 8)
+
+#define GALAXY_CONFIG_WSS_ENABLE (1 << 10)
+
+#define GALAXY_CONFIG_GAME_ENABLE (1 << 11)
+
+#define GALAXY_CONFIG_MPUA_300 (0 << 12)
+#define GALAXY_CONFIG_MPUA_330 (1 << 12)
+
+#define GALAXY_CONFIG_MPU_ENABLE (1 << 13)
+
+#define GALAXY_CONFIG_CDA_310 (0 << 14)
+#define GALAXY_CONFIG_CDA_320 (1 << 14)
+#define GALAXY_CONFIG_CDA_340 (2 << 14)
+#define GALAXY_CONFIG_CDA_350 (3 << 14)
+#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350
+
+#define GALAXY_CONFIG_CD_DISABLE (0 << 16)
+#define GALAXY_CONFIG_CD_PANASONIC (1 << 16)
+#define GALAXY_CONFIG_CD_SONY (2 << 16)
+#define GALAXY_CONFIG_CD_MITSUMI (3 << 16)
+#define GALAXY_CONFIG_CD_AZTECH (4 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16)
+#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7
+
+#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20)
+#define GALAXY_CONFIG_CDDMA8_0 (1 << 20)
+#define GALAXY_CONFIG_CDDMA8_1 (2 << 20)
+#define GALAXY_CONFIG_CDDMA8_3 (3 << 20)
+#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3
+
+#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22)
+#define GALAXY_CONFIG_CDDMA16_5 (1 << 22)
+#define GALAXY_CONFIG_CDDMA16_6 (2 << 22)
+#define GALAXY_CONFIG_CDDMA16_7 (3 << 22)
+#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7
+
+#define GALAXY_CONFIG_MPUIRQ_2 (1 << 24)
+#define GALAXY_CONFIG_MPUIRQ_5 (1 << 25)
+#define GALAXY_CONFIG_MPUIRQ_7 (1 << 26)
+#define GALAXY_CONFIG_MPUIRQ_10 (1 << 27)
+
+#define GALAXY_CONFIG_CDIRQ_5 (1 << 28)
+#define GALAXY_CONFIG_CDIRQ_11 (1 << 29)
+#define GALAXY_CONFIG_CDIRQ_12 (1 << 30)
+#define GALAXY_CONFIG_CDIRQ_15 (1 << 31)
+#define GALAXY_CONFIG_CDIRQ_MASK (\
+ GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
+ GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_MASK (\
+ GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
+ GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
+ GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
new file mode 100644
index 00000000000..1eb2b1ec0fd
--- /dev/null
+++ b/sound/isa/galaxy/galaxy.c
@@ -0,0 +1,648 @@
+/*
+ * Aztech AZT1605/AZT2316 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/wss.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+module_param_array(wss_port, long, NULL, 0444);
+MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
+
+/*
+ * Generic SB DSP support routines
+ */
+
+#define DSP_PORT_RESET 0x6
+#define DSP_PORT_READ 0xa
+#define DSP_PORT_COMMAND 0xc
+#define DSP_PORT_STATUS 0xc
+#define DSP_PORT_DATA_AVAIL 0xe
+
+#define DSP_SIGNATURE 0xaa
+
+#define DSP_COMMAND_GET_VERSION 0xe1
+
+static int dsp_get_byte(void __iomem *port, u8 *val)
+{
+ int loops = 1000;
+
+ while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
+ if (!loops--)
+ return -EIO;
+ cpu_relax();
+ }
+ *val = ioread8(port + DSP_PORT_READ);
+ return 0;
+}
+
+static int dsp_reset(void __iomem *port)
+{
+ u8 val;
+
+ iowrite8(1, port + DSP_PORT_RESET);
+ udelay(10);
+ iowrite8(0, port + DSP_PORT_RESET);
+
+ if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int dsp_command(void __iomem *port, u8 cmd)
+{
+ int loops = 1000;
+
+ while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
+ if (!loops--)
+ return -EIO;
+ cpu_relax();
+ }
+ iowrite8(cmd, port + DSP_PORT_COMMAND);
+ return 0;
+}
+
+static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
+{
+ int err;
+
+ err = dsp_command(port, DSP_COMMAND_GET_VERSION);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(port, major);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(port, minor);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * Generic WSS support routines
+ */
+
+#define WSS_CONFIG_DMA_0 (1 << 0)
+#define WSS_CONFIG_DMA_1 (2 << 0)
+#define WSS_CONFIG_DMA_3 (3 << 0)
+#define WSS_CONFIG_DUPLEX (1 << 2)
+#define WSS_CONFIG_IRQ_7 (1 << 3)
+#define WSS_CONFIG_IRQ_9 (2 << 3)
+#define WSS_CONFIG_IRQ_10 (3 << 3)
+#define WSS_CONFIG_IRQ_11 (4 << 3)
+
+#define WSS_PORT_CONFIG 0
+#define WSS_PORT_SIGNATURE 3
+
+#define WSS_SIGNATURE 4
+
+static int wss_detect(void __iomem *wss_port)
+{
+ if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void wss_set_config(void __iomem *wss_port, u8 wss_config)
+{
+ iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
+}
+
+/*
+ * Aztech Sound Galaxy specifics
+ */
+
+#define GALAXY_PORT_CONFIG 1024
+#define CONFIG_PORT_SET 4
+
+#define DSP_COMMAND_GALAXY_8 8
+#define GALAXY_COMMAND_GET_TYPE 5
+
+#define DSP_COMMAND_GALAXY_9 9
+#define GALAXY_COMMAND_WSSMODE 0
+#define GALAXY_COMMAND_SB8MODE 1
+
+#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE
+#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE
+
+struct snd_galaxy {
+ void __iomem *port;
+ void __iomem *config_port;
+ void __iomem *wss_port;
+ u32 config;
+ struct resource *res_port;
+ struct resource *res_config_port;
+ struct resource *res_wss_port;
+};
+
+static u32 config[SNDRV_CARDS];
+static u8 wss_config[SNDRV_CARDS];
+
+static int snd_galaxy_match(struct device *dev, unsigned int n)
+{
+ if (!enable[n])
+ return 0;
+
+ switch (port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_err(dev, "please specify port\n");
+ return 0;
+ case 0x220:
+ config[n] |= GALAXY_CONFIG_SBA_220;
+ break;
+ case 0x240:
+ config[n] |= GALAXY_CONFIG_SBA_240;
+ break;
+ case 0x260:
+ config[n] |= GALAXY_CONFIG_SBA_260;
+ break;
+ case 0x280:
+ config[n] |= GALAXY_CONFIG_SBA_280;
+ break;
+ default:
+ dev_err(dev, "invalid port %#lx\n", port[n]);
+ return 0;
+ }
+
+ switch (wss_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_err(dev, "please specify wss_port\n");
+ return 0;
+ case 0x530:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
+ break;
+ case 0x604:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
+ break;
+ case 0xe80:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
+ break;
+ case 0xf40:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
+ break;
+ default:
+ dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
+ return 0;
+ }
+
+ switch (irq[n]) {
+ case SNDRV_AUTO_IRQ:
+ dev_err(dev, "please specify irq\n");
+ return 0;
+ case 7:
+ wss_config[n] |= WSS_CONFIG_IRQ_7;
+ break;
+ case 2:
+ irq[n] = 9;
+ case 9:
+ wss_config[n] |= WSS_CONFIG_IRQ_9;
+ break;
+ case 10:
+ wss_config[n] |= WSS_CONFIG_IRQ_10;
+ break;
+ case 11:
+ wss_config[n] |= WSS_CONFIG_IRQ_11;
+ break;
+ default:
+ dev_err(dev, "invalid IRQ %d\n", irq[n]);
+ return 0;
+ }
+
+ switch (dma1[n]) {
+ case SNDRV_AUTO_DMA:
+ dev_err(dev, "please specify dma1\n");
+ return 0;
+ case 0:
+ wss_config[n] |= WSS_CONFIG_DMA_0;
+ break;
+ case 1:
+ wss_config[n] |= WSS_CONFIG_DMA_1;
+ break;
+ case 3:
+ wss_config[n] |= WSS_CONFIG_DMA_3;
+ break;
+ default:
+ dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
+ return 0;
+ }
+
+ if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
+ dma2[n] = -1;
+ goto mpu;
+ }
+
+ wss_config[n] |= WSS_CONFIG_DUPLEX;
+ switch (dma2[n]) {
+ case 0:
+ break;
+ case 1:
+ if (dma1[n] == 0)
+ break;
+ default:
+ dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
+ return 0;
+ }
+
+mpu:
+ switch (mpu_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
+ mpu_port[n] = -1;
+ goto fm;
+ case 0x300:
+ config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
+ break;
+ case 0x330:
+ config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
+ break;
+ default:
+ dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
+ return 0;
+ }
+
+ switch (mpu_irq[n]) {
+ case SNDRV_AUTO_IRQ:
+ dev_warn(dev, "mpu_irq not specified: using polling mode\n");
+ mpu_irq[n] = -1;
+ break;
+ case 2:
+ mpu_irq[n] = 9;
+ case 9:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_2;
+ break;
+#ifdef AZT1605
+ case 3:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_3;
+ break;
+#endif
+ case 5:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_5;
+ break;
+ case 7:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_7;
+ break;
+#ifdef AZT2316
+ case 10:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_10;
+ break;
+#endif
+ default:
+ dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
+ return 0;
+ }
+
+ if (mpu_irq[n] == irq[n]) {
+ dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
+ return 0;
+ }
+
+fm:
+ switch (fm_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_warn(dev, "fm_port not specified: not using OPL3\n");
+ fm_port[n] = -1;
+ break;
+ case 0x388:
+ break;
+ default:
+ dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
+ return 0;
+ }
+
+ config[n] |= GALAXY_CONFIG_GAME_ENABLE;
+ return 1;
+}
+
+static int galaxy_init(struct snd_galaxy *galaxy, u8 *type)
+{
+ u8 major;
+ u8 minor;
+ int err;
+
+ err = dsp_reset(galaxy->port);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_version(galaxy->port, &major, &minor);
+ if (err < 0)
+ return err;
+
+ if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
+ return -ENODEV;
+
+ err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
+ if (err < 0)
+ return err;
+
+ err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(galaxy->port, type);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
+{
+ int err;
+
+ err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
+ if (err < 0)
+ return err;
+
+ err = dsp_command(galaxy->port, mode);
+ if (err < 0)
+ return err;
+
+#ifdef AZT1605
+ /*
+ * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
+ */
+ err = dsp_reset(galaxy->port);
+ if (err < 0)
+ return err;
+#endif
+
+ return 0;
+}
+
+static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
+{
+ u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
+ int i;
+
+ iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
+ for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
+ iowrite8(config, galaxy->config_port + i);
+ config >>= 8;
+ }
+ iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
+ msleep(10);
+}
+
+static void galaxy_config(struct snd_galaxy *galaxy, u32 config)
+{
+ int i;
+
+ for (i = GALAXY_CONFIG_SIZE; i; i--) {
+ u8 tmp = ioread8(galaxy->config_port + i - 1);
+ galaxy->config = (galaxy->config << 8) | tmp;
+ }
+ config |= galaxy->config & GALAXY_CONFIG_MASK;
+ galaxy_set_config(galaxy, config);
+}
+
+static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
+{
+ int err;
+
+ err = wss_detect(galaxy->wss_port);
+ if (err < 0)
+ return err;
+
+ wss_set_config(galaxy->wss_port, wss_config);
+
+ err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void snd_galaxy_free(struct snd_card *card)
+{
+ struct snd_galaxy *galaxy = card->private_data;
+
+ if (galaxy->wss_port) {
+ wss_set_config(galaxy->wss_port, 0);
+ ioport_unmap(galaxy->wss_port);
+ release_and_free_resource(galaxy->res_wss_port);
+ }
+ if (galaxy->config_port) {
+ galaxy_set_config(galaxy, galaxy->config);
+ ioport_unmap(galaxy->config_port);
+ release_and_free_resource(galaxy->res_config_port);
+ }
+ if (galaxy->port) {
+ ioport_unmap(galaxy->port);
+ release_and_free_resource(galaxy->res_port);
+ }
+}
+
+static int snd_galaxy_probe(struct device *dev, unsigned int n)
+{
+ struct snd_galaxy *galaxy;
+ struct snd_wss *chip;
+ struct snd_card *card;
+ u8 type;
+ int err;
+
+ err = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+ sizeof(*galaxy), &card);
+ if (err < 0)
+ return err;
+
+ card->private_free = snd_galaxy_free;
+ galaxy = card->private_data;
+
+ galaxy->res_port = request_region(port[n], 16, DRV_NAME);
+ if (!galaxy->res_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
+ port[n] + 15);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->port = ioport_map(port[n], 16);
+
+ err = galaxy_init(galaxy, &type);
+ if (err < 0) {
+ dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
+ goto error;
+ }
+ dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
+
+ galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
+ 16, DRV_NAME);
+ if (!galaxy->res_config_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n",
+ port[n] + GALAXY_PORT_CONFIG,
+ port[n] + GALAXY_PORT_CONFIG + 15);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
+
+ galaxy_config(galaxy, config[n]);
+
+ galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
+ if (!galaxy->res_wss_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
+ wss_port[n] + 3);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->wss_port = ioport_map(wss_port[n], 4);
+
+ err = galaxy_wss_config(galaxy, wss_config[n]);
+ if (err < 0) {
+ dev_err(dev, "could not configure WSS\n");
+ goto error;
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, DRV_NAME);
+ sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
+ card->shortname, port[n], wss_port[n], irq[n], dma1[n],
+ dma2[n]);
+
+ err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
+ dma2[n], WSS_HW_DETECT, 0, &chip);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_pcm(chip, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_mixer(chip);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_timer(chip, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ if (mpu_port[n] >= 0) {
+ err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_port[n], 0, mpu_irq[n], NULL);
+ if (err < 0)
+ goto error;
+ }
+
+ if (fm_port[n] >= 0) {
+ struct snd_opl3 *opl3;
+
+ err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+ OPL3_HW_AUTO, 0, &opl3);
+ if (err < 0) {
+ dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
+ goto error;
+ }
+ err = snd_opl3_timer_new(opl3, 1, 2);
+ if (err < 0)
+ goto error;
+
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ goto error;
+ }
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+
+ dev_set_drvdata(dev, card);
+ return 0;
+
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static int snd_galaxy_remove(struct device *dev, unsigned int n)
+{
+ snd_card_free(dev_get_drvdata(dev));
+ return 0;
+}
+
+static struct isa_driver snd_galaxy_driver = {
+ .match = snd_galaxy_match,
+ .probe = snd_galaxy_probe,
+ .remove = snd_galaxy_remove,
+
+ .driver = {
+ .name = DEV_NAME
+ }
+};
+
+static int __init alsa_card_galaxy_init(void)
+{
+ return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_galaxy_exit(void)
+{
+ isa_unregister_driver(&snd_galaxy_driver);
+}
+
+module_init(alsa_card_galaxy_init);
+module_exit(alsa_card_galaxy_exit);
diff --git a/sound/isa/gus/Makefile b/sound/isa/gus/Makefile
index bae5dbd6c8e..6cd4ee03754 100644
--- a/sound/isa/gus/Makefile
+++ b/sound/isa/gus/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
snd-gus-lib-objs := gus_main.o \
@@ -9,7 +9,6 @@ snd-gus-lib-objs := gus_main.o \
gus_pcm.o gus_mixer.o \
gus_uart.o \
gus_reset.o
-snd-gus-synth-objs := gus_synth.o gus_sample.o gus_simple.o gus_instr.o
snd-gusclassic-objs := gusclassic.o
snd-gusextreme-objs := gusextreme.o
@@ -17,20 +16,9 @@ snd-gusmax-objs := gusmax.o
snd-interwave-objs := interwave.o
snd-interwave-stb-objs := interwave-stb.o
-#
-# this function returns:
-# "m" - CONFIG_SND_SEQUENCER is m
-# <empty string> - CONFIG_SND_SEQUENCER is undefined
-# otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
# Toplevel Module Dependency
obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o
obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o
obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o
obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-gus-synth.o
-
-obj-m := $(sort $(obj-m))
diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c
index 930f4bc56f3..36c27c83236 100644
--- a/sound/isa/gus/gus_dma.c
+++ b/sound/isa/gus/gus_dma.c
@@ -1,6 +1,6 @@
/*
* Routines for GF1 DMA control
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <asm/dma.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -46,7 +45,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
unsigned char dma_cmd;
unsigned int address_high;
- // snd_printk("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n", addr, (long) buf, count);
+ snd_printdd("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n",
+ addr, buf_addr, count);
if (gus->gf1.dma1 > 3) {
if (gus->gf1.enh_mode) {
@@ -78,7 +78,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
snd_gf1_dma_ack(gus);
snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE);
#if 0
- snd_printk("address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", address << 1, count, dma_cmd);
+ snd_printk(KERN_DEBUG "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n",
+ address << 1, count, dma_cmd);
#endif
spin_lock_irqsave(&gus->reg_lock, flags);
if (gus->gf1.enh_mode) {
@@ -143,16 +144,18 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus)
snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
kfree(block);
#if 0
- printk("program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", addr, (long) buffer, count, cmd);
+ snd_printd(KERN_DEBUG "program dma (IRQ) - "
+ "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, block->buf_addr, block->count, block->cmd);
#endif
}
int snd_gf1_dma_init(struct snd_gus_card * gus)
{
- down(&gus->dma_mutex);
+ mutex_lock(&gus->dma_mutex);
gus->gf1.dma_shared++;
if (gus->gf1.dma_shared > 1) {
- up(&gus->dma_mutex);
+ mutex_unlock(&gus->dma_mutex);
return 0;
}
gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt;
@@ -160,7 +163,7 @@ int snd_gf1_dma_init(struct snd_gus_card * gus)
gus->gf1.dma_data_pcm_last =
gus->gf1.dma_data_synth =
gus->gf1.dma_data_synth_last = NULL;
- up(&gus->dma_mutex);
+ mutex_unlock(&gus->dma_mutex);
return 0;
}
@@ -168,7 +171,7 @@ int snd_gf1_dma_done(struct snd_gus_card * gus)
{
struct snd_gf1_dma_block *block;
- down(&gus->dma_mutex);
+ mutex_lock(&gus->dma_mutex);
gus->gf1.dma_shared--;
if (!gus->gf1.dma_shared) {
snd_dma_disable(gus->gf1.dma1);
@@ -185,7 +188,7 @@ int snd_gf1_dma_done(struct snd_gus_card * gus)
gus->gf1.dma_data_pcm_last =
gus->gf1.dma_data_synth_last = NULL;
}
- up(&gus->dma_mutex);
+ mutex_unlock(&gus->dma_mutex);
return 0;
}
@@ -204,13 +207,16 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
}
*block = *__block;
block->next = NULL;
-#if 0
- printk("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", block->addr, (long) block->buffer, block->count, block->cmd);
-#endif
-#if 0
- printk("gus->gf1.dma_data_pcm_last = 0x%lx\n", (long)gus->gf1.dma_data_pcm_last);
- printk("gus->gf1.dma_data_pcm = 0x%lx\n", (long)gus->gf1.dma_data_pcm);
-#endif
+
+ snd_printdd("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, (long) block->buffer, block->count,
+ block->cmd);
+
+ snd_printdd("gus->gf1.dma_data_pcm_last = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm_last);
+ snd_printdd("gus->gf1.dma_data_pcm = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm);
+
spin_lock_irqsave(&gus->dma_lock, flags);
if (synth) {
if (gus->gf1.dma_data_synth_last) {
diff --git a/sound/isa/gus/gus_dram.c b/sound/isa/gus/gus_dram.c
index f22fe7967fc..fd2e2e2ed4e 100644
--- a/sound/isa/gus/gus_dram.c
+++ b/sound/isa/gus/gus_dram.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* DRAM access routines
*
*
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/gus.h>
diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c
index d0c38e1856e..4dc9caf8ddc 100644
--- a/sound/isa/gus/gus_instr.c
+++ b/sound/isa/gus/gus_instr.c
@@ -1,6 +1,6 @@
/*
* Routines for Gravis UltraSound soundcards - Synthesizer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/gus.h>
diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c
index 9b1fe292de4..ca79878d8d8 100644
--- a/sound/isa/gus/gus_io.c
+++ b/sound/isa/gus/gus_io.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* I/O routines for GF1/InterWave synthesizer chips
*
*
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <sound/core.h>
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
index c19ba2910b7..2055aff71b5 100644
--- a/sound/isa/gus/gus_irq.c
+++ b/sound/isa/gus/gus_irq.c
@@ -1,6 +1,6 @@
/*
* Routine for IRQ handling from GF1/InterWave chip
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/gus.h>
@@ -30,7 +29,7 @@
#define STAT_ADD(x) while (0) { ; }
#endif
-irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_gus_interrupt(int irq, void *dev_id)
{
struct snd_gus_card * gus = dev_id;
unsigned char status;
@@ -42,14 +41,16 @@ __again:
if (status == 0)
return IRQ_RETVAL(handled);
handled = 1;
- // snd_printk("IRQ: status = 0x%x\n", status);
+ /* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
if (status & 0x02) {
STAT_ADD(gus->gf1.interrupt_stat_midi_in);
- gus->gf1.interrupt_handler_midi_in(gus);
+ if (gus->gf1.interrupt_handler_midi_in)
+ gus->gf1.interrupt_handler_midi_in(gus);
}
if (status & 0x01) {
STAT_ADD(gus->gf1.interrupt_stat_midi_out);
- gus->gf1.interrupt_handler_midi_out(gus);
+ if (gus->gf1.interrupt_handler_midi_out)
+ gus->gf1.interrupt_handler_midi_out(gus);
}
if (status & (0x20 | 0x40)) {
unsigned int already, _current_;
@@ -64,7 +65,9 @@ __again:
continue; /* multi request */
already |= _current_; /* mark request */
#if 0
- printk("voice = %i, voice_status = 0x%x, voice_verify = %i\n", voice, voice_status, inb(GUSP(gus, GF1PAGE)));
+ printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
+ "voice_verify = %i\n",
+ voice, voice_status, inb(GUSP(gus, GF1PAGE)));
#endif
pvoice = &gus->gf1.voices[voice];
if (pvoice->use) {
@@ -85,20 +88,24 @@ __again:
}
if (status & 0x04) {
STAT_ADD(gus->gf1.interrupt_stat_timer1);
- gus->gf1.interrupt_handler_timer1(gus);
+ if (gus->gf1.interrupt_handler_timer1)
+ gus->gf1.interrupt_handler_timer1(gus);
}
if (status & 0x08) {
STAT_ADD(gus->gf1.interrupt_stat_timer2);
- gus->gf1.interrupt_handler_timer2(gus);
+ if (gus->gf1.interrupt_handler_timer2)
+ gus->gf1.interrupt_handler_timer2(gus);
}
if (status & 0x80) {
if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) {
STAT_ADD(gus->gf1.interrupt_stat_dma_write);
- gus->gf1.interrupt_handler_dma_write(gus);
+ if (gus->gf1.interrupt_handler_dma_write)
+ gus->gf1.interrupt_handler_dma_write(gus);
}
if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) {
STAT_ADD(gus->gf1.interrupt_stat_dma_read);
- gus->gf1.interrupt_handler_dma_read(gus);
+ if (gus->gf1.interrupt_handler_dma_read)
+ gus->gf1.interrupt_handler_dma_read(gus);
}
}
if (--loop > 0)
@@ -136,7 +143,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus)
struct snd_info_entry *entry;
if (! snd_card_proc_new(gus->card, "gusirq", &entry))
- snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read);
+ snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read);
}
#endif
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index 6d15b3d18a8..4490ee442ff 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -1,6 +1,6 @@
/*
* Routines for Gravis UltraSound soundcards
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,19 +19,19 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ioport.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/gus.h>
#include <sound/control.h>
#include <asm/dma.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards");
MODULE_LICENSE("GPL");
@@ -104,12 +104,6 @@ static int snd_gus_free(struct snd_gus_card *gus)
{
if (gus->gf1.res_port2 == NULL)
goto __hw_end;
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
- if (gus->seq_dev) {
- snd_device_free(gus->card, gus->seq_dev);
- gus->seq_dev = NULL;
- }
-#endif
snd_gf1_stop(gus);
snd_gus_init_dma_irq(gus, 0);
__hw_end:
@@ -154,6 +148,14 @@ int snd_gus_create(struct snd_card *card,
gus = kzalloc(sizeof(*gus), GFP_KERNEL);
if (gus == NULL)
return -ENOMEM;
+ spin_lock_init(&gus->reg_lock);
+ spin_lock_init(&gus->voice_alloc);
+ spin_lock_init(&gus->active_voice_lock);
+ spin_lock_init(&gus->event_lock);
+ spin_lock_init(&gus->dma_lock);
+ spin_lock_init(&gus->pcm_volume_level_lock);
+ spin_lock_init(&gus->uart_cmd_lock);
+ mutex_init(&gus->dma_mutex);
gus->gf1.irq = -1;
gus->gf1.dma1 = -1;
gus->gf1.dma2 = -1;
@@ -179,7 +181,7 @@ int snd_gus_create(struct snd_card *card,
snd_gus_free(gus);
return -EBUSY;
}
- if (irq >= 0 && request_irq(irq, snd_gus_interrupt, SA_INTERRUPT, "GUS GF1", (void *) gus)) {
+ if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "GUS GF1", (void *) gus)) {
snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq);
snd_gus_free(gus);
return -EBUSY;
@@ -218,14 +220,6 @@ int snd_gus_create(struct snd_card *card,
gus->gf1.pcm_channels = pcm_channels;
gus->gf1.volume_ramp = 25;
gus->gf1.smooth_pan = 1;
- spin_lock_init(&gus->reg_lock);
- spin_lock_init(&gus->voice_alloc);
- spin_lock_init(&gus->active_voice_lock);
- spin_lock_init(&gus->event_lock);
- spin_lock_init(&gus->dma_lock);
- spin_lock_init(&gus->pcm_volume_level_lock);
- spin_lock_init(&gus->uart_cmd_lock);
- init_MUTEX(&gus->dma_mutex);
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops)) < 0) {
snd_gus_free(gus);
return err;
@@ -283,9 +277,11 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
static unsigned char dmas[8] =
{6, 1, 0, 2, 0, 3, 4, 5};
- snd_assert(gus != NULL, return -EINVAL);
+ if (snd_BUG_ON(!gus))
+ return -EINVAL;
card = gus->card;
- snd_assert(card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!card))
+ return -EINVAL;
gus->mix_cntrl_reg &= 0xf8;
gus->mix_cntrl_reg |= 0x01; /* disable MIC, LINE IN, enable LINE OUT */
@@ -294,10 +290,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 +302,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");
@@ -398,7 +394,7 @@ static int snd_gus_check_version(struct snd_gus_card * gus)
gus->ess_flag = 1;
} else {
snd_printk(KERN_ERR "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val);
- snd_printk(KERN_ERR " please - report to <perex@suse.cz>\n");
+ snd_printk(KERN_ERR " please - report to <perex@perex.cz>\n");
}
}
}
@@ -408,14 +404,6 @@ static int snd_gus_check_version(struct snd_gus_card * gus)
return 0;
}
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-static void snd_gus_seq_dev_free(struct snd_seq_device *seq_dev)
-{
- struct snd_gus_card *gus = seq_dev->private_data;
- gus->seq_dev = NULL;
-}
-#endif
-
int snd_gus_initialize(struct snd_gus_card *gus)
{
int err;
@@ -430,15 +418,6 @@ int snd_gus_initialize(struct snd_gus_card *gus)
}
if ((err = snd_gus_init_dma_irq(gus, 1)) < 0)
return err;
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
- if (snd_seq_device_new(gus->card, 1, SNDRV_SEQ_DEV_ID_GUS,
- sizeof(struct snd_gus_card *), &gus->seq_dev) >= 0) {
- strcpy(gus->seq_dev->name, "GUS");
- *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(gus->seq_dev) = gus;
- gus->seq_dev->private_data = gus;
- gus->seq_dev->private_free = snd_gus_seq_dev_free;
- }
-#endif
snd_gf1_start(gus);
gus->initialized = 1;
return 0;
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
index e8bdb860a19..af888a022fc 100644
--- a/sound/isa/gus/gus_mem.c
+++ b/sound/isa/gus/gus_mem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* GUS's memory allocation routines / bottom layer
*
*
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <sound/core.h>
@@ -34,9 +33,9 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
void snd_gf1_mem_lock(struct snd_gf1_mem * alloc, int xup)
{
if (!xup) {
- down(&alloc->memory_mutex);
+ mutex_lock(&alloc->memory_mutex);
} else {
- up(&alloc->memory_mutex);
+ mutex_unlock(&alloc->memory_mutex);
}
}
@@ -59,7 +58,7 @@ static struct snd_gf1_mem_block *snd_gf1_mem_xalloc(struct snd_gf1_mem * alloc,
alloc->first = nblock;
else
nblock->prev->next = nblock;
- up(&alloc->memory_mutex);
+ mutex_unlock(&alloc->memory_mutex);
return NULL;
}
pblock = pblock->next;
@@ -80,7 +79,7 @@ int snd_gf1_mem_xfree(struct snd_gf1_mem * alloc, struct snd_gf1_mem_block * blo
{
if (block->share) { /* ok.. shared block */
block->share--;
- up(&alloc->memory_mutex);
+ mutex_unlock(&alloc->memory_mutex);
return 0;
}
if (alloc->first == block) {
@@ -128,7 +127,8 @@ static struct snd_gf1_mem_block *snd_gf1_mem_share(struct snd_gf1_mem * alloc,
!share_id[2] && !share_id[3])
return NULL;
for (block = alloc->first; block; block = block->next)
- if (!memcmp(share_id, block->share_id, sizeof(share_id)))
+ if (!memcmp(share_id, block->share_id,
+ sizeof(block->share_id)))
return block;
return NULL;
}
@@ -143,9 +143,8 @@ static int snd_gf1_mem_find(struct snd_gf1_mem * alloc,
struct snd_gf1_mem_block *pblock;
unsigned int ptr1, ptr2;
- align--;
- if (w_16 && align < 1)
- align = 1;
+ if (w_16 && align < 2)
+ align = 2;
block->flags = w_16 ? SNDRV_GF1_MEM_BLOCK_16BIT : 0;
block->owner = SNDRV_GF1_MEM_OWNER_DRIVER;
block->share = 0;
@@ -165,7 +164,7 @@ static int snd_gf1_mem_find(struct snd_gf1_mem * alloc,
if (pblock->next->ptr < boundary)
ptr2 = pblock->next->ptr;
}
- ptr1 = (pblock->ptr + pblock->size + align) & ~align;
+ ptr1 = ALIGN(pblock->ptr + pblock->size, align);
if (ptr1 >= ptr2)
continue;
size1 = ptr2 - ptr1;
@@ -244,7 +243,7 @@ int snd_gf1_mem_init(struct snd_gus_card * gus)
#endif
alloc = &gus->gf1.mem_alloc;
- init_MUTEX(&alloc->memory_mutex);
+ mutex_init(&alloc->memory_mutex);
alloc->first = alloc->last = NULL;
if (!gus->gf1.memory)
return 0;
@@ -264,10 +263,8 @@ int snd_gf1_mem_init(struct snd_gus_card * gus)
if (snd_gf1_mem_xalloc(alloc, &block) == NULL)
return -ENOMEM;
#ifdef CONFIG_SND_DEBUG
- if (! snd_card_proc_new(gus->card, "gusmem", &entry)) {
- snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read);
- entry->c.text.read_size = 256 * 1024;
- }
+ if (! snd_card_proc_new(gus->card, "gusmem", &entry))
+ snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read);
#endif
return 0;
}
@@ -299,7 +296,7 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
gus = entry->private_data;
alloc = &gus->gf1.mem_alloc;
- down(&alloc->memory_mutex);
+ mutex_lock(&alloc->memory_mutex);
snd_iprintf(buffer, "8-bit banks : \n ");
for (i = 0; i < 4; i++)
snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_8[i].address, alloc->banks_8[i].size >> 10, i + 1 < 4 ? "," : "");
@@ -343,7 +340,7 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
}
snd_iprintf(buffer, " Total: memory = %i, used = %i, free = %i\n",
total, used, total - used);
- up(&alloc->memory_mutex);
+ mutex_unlock(&alloc->memory_mutex);
#if 0
ultra_iprintf(buffer, " Verify: free = %i, max 8-bit block = %i, max 16-bit block = %i\n",
ultra_memory_free_size(card, &card->gf1.mem_alloc),
diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c
index 4080255007d..2ccb3fadd7b 100644
--- a/sound/isa/gus/gus_mem_proc.c
+++ b/sound/isa/gus/gus_mem_proc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* GUS's memory access via proc filesystem
*
*
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/gus.h>
@@ -32,52 +31,21 @@ struct gus_proc_private {
struct snd_gus_card * gus;
};
-static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_private_data,
- struct file *file, char __user *buf,
- unsigned long count, unsigned long pos)
+static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
+ void *file_private_data,
+ struct file *file, char __user *buf,
+ size_t count, loff_t pos)
{
- long size;
struct gus_proc_private *priv = entry->private_data;
struct snd_gus_card *gus = priv->gus;
int err;
- size = count;
- if (pos + size > priv->size)
- size = (long)priv->size - pos;
- if (size > 0) {
- if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
- return err;
- return size;
- }
- return 0;
+ err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
+ if (err < 0)
+ return err;
+ return count;
}
-static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
- void *private_file_data,
- struct file *file,
- long long offset,
- int orig)
-{
- struct gus_proc_private *priv = entry->private_data;
-
- switch (orig) {
- case 0: /* SEEK_SET */
- file->f_pos = offset;
- break;
- case 1: /* SEEK_CUR */
- file->f_pos += offset;
- break;
- case 2: /* SEEK_END, offset is negative */
- file->f_pos = priv->size + offset;
- break;
- default:
- return -EINVAL;
- }
- if (file->f_pos > priv->size)
- file->f_pos = priv->size;
- return file->f_pos;
-}
-
static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
{
struct gus_proc_private *priv = entry->private_data;
@@ -86,7 +54,6 @@ static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
static struct snd_info_entry_ops snd_gf1_mem_proc_ops = {
.read = snd_gf1_mem_proc_dump,
- .llseek = snd_gf1_mem_proc_llseek,
};
int snd_gf1_mem_proc_init(struct snd_gus_card * gus)
diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c
index acc25a29720..0dd43414016 100644
--- a/sound/isa/gus/gus_mixer.c
+++ b/sound/isa/gus/gus_mixer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of ICS 2101 chip and "mixer" in GF1 chip
*
*
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <sound/core.h>
@@ -36,14 +35,7 @@
.get = snd_gf1_get_single, .put = snd_gf1_put_single, \
.private_value = shift | (invert << 8) }
-static int snd_gf1_info_single(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;
-}
+#define snd_gf1_info_single snd_ctl_boolean_mono_info
static int snd_gf1_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -169,9 +161,11 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus)
unsigned int idx, max;
int err;
- snd_assert(gus != NULL, return -EINVAL);
+ if (snd_BUG_ON(!gus))
+ return -EINVAL;
card = gus->card;
- snd_assert(card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!card))
+ return -EINVAL;
if (gus->ics_flag)
snd_component_add(card, "ICS2101");
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index d0829393ec8..2dcf45bf729 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of GF1 chip (PCM things)
*
* InterWave chips supports interleaved DMA, but this feature isn't used in
@@ -25,7 +25,6 @@
*
*/
-#include <sound/driver.h>
#include <asm/dma.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -83,7 +82,10 @@ static int snd_gf1_pcm_block_change(struct snd_pcm_substream *substream,
count += offset & 31;
offset &= ~31;
- // snd_printk("block change - offset = 0x%x, count = 0x%x\n", offset, count);
+ /*
+ snd_printk(KERN_DEBUG "block change - offset = 0x%x, count = 0x%x\n",
+ offset, count);
+ */
memset(&block, 0, sizeof(block));
block.cmd = SNDRV_GF1_DMA_IRQ;
if (snd_pcm_format_unsigned(runtime->format))
@@ -114,8 +116,6 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
unsigned char pan;
unsigned int voice;
- if (substream == NULL)
- return;
spin_lock_irqsave(&pcmp->lock, flags);
if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {
spin_unlock_irqrestore(&pcmp->lock, flags);
@@ -138,7 +138,11 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;
end = curr + (pcmp->block_size / runtime->channels);
end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;
- // snd_printk("init: curr=0x%x, begin=0x%x, end=0x%x, ctrl=0x%x, ramp=0x%x, rate=0x%x\n", curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+ /*
+ snd_printk(KERN_DEBUG "init: curr=0x%x, begin=0x%x, end=0x%x, "
+ "ctrl=0x%x, ramp=0x%x, rate=0x%x\n",
+ curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+ */
pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;
vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
spin_lock_irqsave(&gus->reg_lock, flags);
@@ -208,9 +212,11 @@ static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus,
ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;
#if 0
snd_gf1_select_voice(gus, pvoice->number);
- printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ printk(KERN_DEBUG "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);
- printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ printk(KERN_DEBUG "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
snd_gf1_select_voice(gus, pvoice->number);
#endif
pcmp->bpos++;
@@ -302,7 +308,11 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf,
unsigned int len;
unsigned long flags;
- // printk("poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n", (int)buf, pos, count, gus->gf1.port);
+ /*
+ printk(KERN_DEBUG
+ "poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n",
+ (int)buf, pos, count, gus->gf1.port);
+ */
while (count > 0) {
len = count;
if (len > 512) /* limit, to allow IRQ */
@@ -355,8 +365,10 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream,
bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
len = samples_to_bytes(runtime, count);
- snd_assert(bpos <= pcmp->dma_size, return -EIO);
- snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
+ if (snd_BUG_ON(bpos > pcmp->dma_size))
+ return -EIO;
+ if (snd_BUG_ON(bpos + len > pcmp->dma_size))
+ return -EIO;
if (copy_from_user(runtime->dma_area + bpos, src, len))
return -EFAULT;
if (snd_gf1_pcm_use_dma && len > 32) {
@@ -384,8 +396,10 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,
bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2));
len = samples_to_bytes(runtime, count);
- snd_assert(bpos <= pcmp->dma_size, return -EIO);
- snd_assert(bpos + len <= pcmp->dma_size, return -EIO);
+ if (snd_BUG_ON(bpos > pcmp->dma_size))
+ return -EIO;
+ if (snd_BUG_ON(bpos + len > pcmp->dma_size))
+ return -EIO;
snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, count);
if (snd_gf1_pcm_use_dma && len > 32) {
return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len);
@@ -679,7 +693,8 @@ static int snd_gf1_pcm_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_gf1_pcm_playback_free;
#if 0
- printk("playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n", (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
+ printk(KERN_DEBUG "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n",
+ (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
#endif
if ((err = snd_gf1_dma_init(gus)) < 0)
return err;
@@ -780,13 +795,13 @@ static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))
continue;
/* load real volume - better precision */
- spin_lock_irqsave(&gus->reg_lock, flags);
+ spin_lock(&gus->reg_lock);
snd_gf1_select_voice(gus, pvoice->number);
snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);
pcmp->final_volume = 1;
- spin_unlock_irqrestore(&gus->reg_lock, flags);
+ spin_unlock(&gus->reg_lock);
}
spin_unlock_irqrestore(&gus->voice_alloc, flags);
return change;
diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c
index b263655c411..3d1fed0c262 100644
--- a/sound/isa/gus/gus_reset.c
+++ b/sound/isa/gus/gus_reset.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -18,7 +18,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/time.h>
diff --git a/sound/isa/gus/gus_sample.c b/sound/isa/gus/gus_sample.c
deleted file mode 100644
index 9e0c55ab25b..00000000000
--- a/sound/isa/gus/gus_sample.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Routines for Gravis UltraSound soundcards - Sample support
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * 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 <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-
-/*
- *
- */
-
-static void select_instrument(struct snd_gus_card * gus, struct snd_gus_voice * v)
-{
- struct snd_seq_kinstr *instr;
-
-#if 0
- printk("select instrument: cluster = %li, std = 0x%x, bank = %i, prg = %i\n",
- v->instr.cluster,
- v->instr.std,
- v->instr.bank,
- v->instr.prg);
-#endif
- instr = snd_seq_instr_find(gus->gf1.ilist, &v->instr, 0, 1);
- if (instr != NULL) {
- if (instr->ops) {
- if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE))
- snd_gf1_simple_init(v);
- }
- snd_seq_instr_free_use(gus->gf1.ilist, instr);
- }
-}
-
-/*
- *
- */
-
-static void event_sample(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_stop)
- v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
- v->instr.std = ev->data.sample.param.sample.std;
- if (v->instr.std & 0xff000000) { /* private instrument */
- v->instr.std &= 0x00ffffff;
- v->instr.std |= (unsigned int)ev->source.client << 24;
- }
- v->instr.bank = ev->data.sample.param.sample.bank;
- v->instr.prg = ev->data.sample.param.sample.prg;
- select_instrument(p->gus, v);
-}
-
-static void event_cluster(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_stop)
- v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
- v->instr.cluster = ev->data.sample.param.cluster.cluster;
- select_instrument(p->gus, v);
-}
-
-static void event_start(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_start)
- v->sample_ops->sample_start(p->gus, v, ev->data.sample.param.position);
-}
-
-static void event_stop(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_stop)
- v->sample_ops->sample_stop(p->gus, v, ev->data.sample.param.stop_mode);
-}
-
-static void event_freq(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_freq)
- v->sample_ops->sample_freq(p->gus, v, ev->data.sample.param.frequency);
-}
-
-static void event_volume(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_volume)
- v->sample_ops->sample_volume(p->gus, v, &ev->data.sample.param.volume);
-}
-
-static void event_loop(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_loop)
- v->sample_ops->sample_loop(p->gus, v, &ev->data.sample.param.loop);
-}
-
-static void event_position(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_pos)
- v->sample_ops->sample_pos(p->gus, v, ev->data.sample.param.position);
-}
-
-static void event_private1(struct snd_seq_event *ev, struct snd_gus_port *p,
- struct snd_gus_voice *v)
-{
- if (v->sample_ops && v->sample_ops->sample_private1)
- v->sample_ops->sample_private1(p->gus, v, (unsigned char *)&ev->data.sample.param.raw8);
-}
-
-typedef void (gus_sample_event_handler_t)(struct snd_seq_event *ev,
- struct snd_gus_port *p,
- struct snd_gus_voice *v);
-static gus_sample_event_handler_t *gus_sample_event_handlers[9] = {
- event_sample,
- event_cluster,
- event_start,
- event_stop,
- event_freq,
- event_volume,
- event_loop,
- event_position,
- event_private1
-};
-
-void snd_gus_sample_event(struct snd_seq_event *ev, struct snd_gus_port *p)
-{
- int idx, voice;
- struct snd_gus_card *gus = p->gus;
- struct snd_gus_voice *v;
- unsigned long flags;
-
- idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
- if (idx < 0 || idx > 8)
- return;
- for (voice = 0; voice < 32; voice++) {
- v = &gus->gf1.voices[voice];
- if (v->use && v->client == ev->source.client &&
- v->port == ev->source.port &&
- v->index == ev->data.sample.channel) {
- spin_lock_irqsave(&gus->event_lock, flags);
- gus_sample_event_handlers[idx](ev, p, v);
- spin_unlock_irqrestore(&gus->event_lock, flags);
- return;
- }
- }
-}
diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c
deleted file mode 100644
index dcad6ed0198..00000000000
--- a/sound/isa/gus/gus_simple.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Routines for Gravis UltraSound soundcards - Simple instrument handlers
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * 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 <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-#include "gus_tables.h"
-
-/*
- *
- */
-
-static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-
-static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position);
-static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode);
-static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq);
-static void sample_volume(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume);
-static void sample_loop(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop);
-static void sample_pos(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position);
-static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data);
-
-static struct snd_gus_sample_ops sample_ops = {
- sample_start,
- sample_stop,
- sample_freq,
- sample_volume,
- sample_loop,
- sample_pos,
- sample_private1
-};
-
-#if 0
-
-static void note_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int wait);
-static void note_wait(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void note_off(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void note_volume(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void note_pitchbend(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void note_vibrato(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void note_tremolo(struct snd_gus_card *card, struct snd_gus_voice *voice);
-
-static struct snd_gus_note_handlers note_commands = {
- note_stop,
- note_wait,
- note_off,
- note_volume,
- note_pitchbend,
- note_vibrato,
- note_tremolo
-};
-
-static void chn_trigger_down(struct snd_gus_card *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority );
-static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note );
-static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 );
-
-static struct ULTRA_STRU_INSTRUMENT_CHANNEL_COMMANDS channel_commands = {
- chn_trigger_down,
- chn_trigger_up,
- chn_control
-};
-
-#endif
-
-static void do_volume_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void do_pan_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice);
-
-/*
- *
- */
-
-static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
- spin_lock(&gus->event_lock);
- snd_gf1_stop_voice(gus, voice->number);
- spin_lock(&gus->reg_lock);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0);
- spin_unlock(&gus->reg_lock);
- voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
- spin_unlock(&gus->event_lock);
-}
-
-static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
- spin_lock(&gus->event_lock);
- if (voice->flags & SNDRV_GF1_VFLG_RUNNING)
- do_volume_envelope(gus, voice);
- else
- snd_gf1_stop_voice(gus, voice->number);
- spin_unlock(&gus->event_lock);
-}
-
-static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
- spin_lock(&gus->event_lock);
- if ((voice->flags & (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) ==
- (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1))
- do_pan_envelope(gus, voice);
- spin_unlock(&gus->event_lock);
-}
-
-/*
- *
- */
-
-static void do_volume_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
- unsigned short next, rate, old_volume;
- int program_next_ramp;
- unsigned long flags;
-
- if (!gus->gf1.volume_ramp) {
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
- snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume);
- /* printk("gf1_volume = 0x%x\n", voice->gf1_volume); */
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return;
- }
- program_next_ramp = 0;
- rate = next = 0;
- while (1) {
- program_next_ramp = 0;
- rate = next = 0;
- switch (voice->venv_state) {
- case VENV_BEFORE:
- voice->venv_state = VENV_ATTACK;
- voice->venv_value_next = 0;
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
- snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- break;
- case VENV_ATTACK:
- voice->venv_state = VENV_SUSTAIN;
- program_next_ramp++;
- next = 255;
- rate = gus->gf1.volume_ramp;
- break;
- case VENV_SUSTAIN:
- voice->venv_state = VENV_RELEASE;
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
- snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, ((int)voice->gf1_volume * (int)voice->venv_value_next) / 255);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return;
- case VENV_RELEASE:
- voice->venv_state = VENV_DONE;
- program_next_ramp++;
- next = 0;
- rate = gus->gf1.volume_ramp;
- break;
- case VENV_DONE:
- snd_gf1_stop_voice(gus, voice->number);
- voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
- return;
- case VENV_VOLUME:
- program_next_ramp++;
- next = voice->venv_value_next;
- rate = gus->gf1.volume_ramp;
- voice->venv_state = voice->venv_state_prev;
- break;
- }
- voice->venv_value_next = next;
- if (!program_next_ramp)
- continue;
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
- old_volume = snd_gf1_read16(gus, SNDRV_GF1_VW_VOLUME) >> 8;
- if (!rate) {
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- continue;
- }
- next = (((int)voice->gf1_volume * (int)next) / 255) >> 8;
- if (old_volume < SNDRV_GF1_MIN_OFFSET)
- old_volume = SNDRV_GF1_MIN_OFFSET;
- if (next < SNDRV_GF1_MIN_OFFSET)
- next = SNDRV_GF1_MIN_OFFSET;
- if (next > SNDRV_GF1_MAX_OFFSET)
- next = SNDRV_GF1_MAX_OFFSET;
- if (old_volume == next) {
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- continue;
- }
- voice->volume_control &= ~0xc3;
- voice->volume_control |= 0x20;
- if (old_volume > next) {
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, next);
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, old_volume);
- voice->volume_control |= 0x40;
- } else {
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, old_volume);
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, next);
- }
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, rate);
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
- if (!gus->gf1.enh_mode) {
- snd_gf1_delay(gus);
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
- }
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return;
- }
-}
-
-static void do_pan_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
- unsigned long flags;
- unsigned char old_pan;
-
-#if 0
- snd_gf1_select_voice(gus, voice->number);
- printk(" -%i- do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n",
- voice->number,
- voice->flags,
- voice->gf1_pan,
- snd_gf1_i_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f);
-#endif
- if (gus->gf1.enh_mode) {
- voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
- return;
- }
- if (!gus->gf1.smooth_pan) {
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return;
- }
- if (!(voice->flags & SNDRV_GF1_VFLG_PAN)) /* before */
- voice->flags |= SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN;
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- old_pan = snd_gf1_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f;
- if (old_pan > voice->gf1_pan )
- old_pan--;
- if (old_pan < voice->gf1_pan)
- old_pan++;
- snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, old_pan);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- if (old_pan == voice->gf1_pan) /* the goal was reached */
- voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
-#if 0
- snd_gf1_select_voice(gus, voice->number);
- printk(" -%i- (1) do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n",
- voice->number,
- voice->flags,
- voice->gf1_pan,
- snd_gf1_i_read8(gus, GF1_VB_PAN) & 0x0f);
-#endif
-}
-
-static void set_enhanced_pan(struct snd_gus_card *gus, struct snd_gus_voice *voice, unsigned short pan)
-{
- unsigned long flags;
- unsigned short vlo, vro;
-
- vlo = SNDRV_GF1_ATTEN((SNDRV_GF1_ATTEN_TABLE_SIZE-1) - pan);
- vro = SNDRV_GF1_ATTEN(pan);
- if (pan != SNDRV_GF1_ATTEN_TABLE_SIZE - 1 && pan != 0) {
- vlo >>= 1;
- vro >>= 1;
- }
- vlo <<= 4;
- vro <<= 4;
-#if 0
- printk("vlo = 0x%x (0x%x), vro = 0x%x (0x%x)\n",
- vlo, snd_gf1_i_read16(gus, GF1_VW_OFFSET_LEFT),
- vro, snd_gf1_i_read16(gus, GF1_VW_OFFSET_RIGHT));
-#endif
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, vlo);
- snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, vro);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- voice->vlo = vlo;
- voice->vro = vro;
-}
-
-/*
- *
- */
-
-static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position)
-{
- unsigned long flags;
- unsigned int begin, addr, addr_end, addr_start;
- int w_16;
- struct simple_instrument *simple;
- struct snd_seq_kinstr *instr;
-
- instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
- if (instr == NULL)
- return;
- voice->instr = instr->instr; /* copy ID to speedup aliases */
- simple = KINSTR_DATA(instr);
- begin = simple->address.memory << 4;
- w_16 = simple->format & SIMPLE_WAVE_16BIT ? 0x04 : 0;
- addr_start = simple->loop_start;
- if (simple->format & SIMPLE_WAVE_LOOP) {
- addr_end = simple->loop_end;
- } else {
- addr_end = (simple->size << 4) - (w_16 ? 40 : 24);
- }
- if (simple->format & SIMPLE_WAVE_BACKWARD) {
- addr = simple->loop_end;
- if (position < simple->loop_end)
- addr -= position;
- } else {
- addr = position;
- }
- voice->control = 0x00;
- voice->mode = 0x20; /* enable offset registers */
- if (simple->format & SIMPLE_WAVE_16BIT)
- voice->control |= 0x04;
- if (simple->format & SIMPLE_WAVE_BACKWARD)
- voice->control |= 0x40;
- if (simple->format & SIMPLE_WAVE_LOOP) {
- voice->control |= 0x08;
- } else {
- voice->control |= 0x20;
- }
- if (simple->format & SIMPLE_WAVE_BIDIR)
- voice->control |= 0x10;
- if (simple->format & SIMPLE_WAVE_ULAW)
- voice->mode |= 0x40;
- if (w_16) {
- addr = ((addr << 1) & ~0x1f) | (addr & 0x0f);
- addr_start = ((addr_start << 1) & ~0x1f) | (addr_start & 0x0f);
- addr_end = ((addr_end << 1) & ~0x1f) | (addr_end & 0x0f);
- }
- addr += begin;
- addr_start += begin;
- addr_end += begin;
- snd_gf1_stop_voice(gus, voice->number);
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
- voice->venv_state = VENV_BEFORE;
- voice->volume_control = 0x03;
- snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
- snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
- snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
- if (!gus->gf1.enh_mode) {
- snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
- } else {
- snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT, voice->vlo);
- snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, voice->vlo);
- snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT, voice->vro);
- snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, voice->vro);
- snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, voice->effect_accumulator);
- snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, voice->gf1_effect_volume);
- snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, voice->gf1_effect_volume);
- }
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- do_volume_envelope(gus, voice);
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- if (gus->gf1.enh_mode)
- snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, voice->mode);
- snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control);
- if (!gus->gf1.enh_mode) {
- snd_gf1_delay(gus);
- snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control );
- }
- spin_unlock_irqrestore(&gus->reg_lock, flags);
-#if 0
- snd_gf1_print_voice_registers(gus);
-#endif
- voice->flags |= SNDRV_GF1_VFLG_RUNNING;
- snd_seq_instr_free_use(gus->gf1.ilist, instr);
-}
-
-static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode)
-{
- unsigned char control;
- unsigned long flags;
-
- if (!(voice->flags & SNDRV_GF1_VFLG_RUNNING))
- return;
- switch (mode) {
- default:
- if (gus->gf1.volume_ramp > 0) {
- if (voice->venv_state < VENV_RELEASE) {
- voice->venv_state = VENV_RELEASE;
- do_volume_envelope(gus, voice);
- }
- }
- if (mode != SAMPLE_STOP_VENVELOPE) {
- snd_gf1_stop_voice(gus, voice->number);
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
- }
- break;
- case SAMPLE_STOP_LOOP: /* disable loop only */
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- control = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
- control &= ~(0x83 | 0x04);
- control |= 0x20;
- snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, control);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- break;
- }
-}
-
-static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
- voice->fc_register = snd_gf1_translate_freq(gus, freq);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
-}
-
-static void sample_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume)
-{
- if (volume->volume >= 0) {
- volume->volume &= 0x3fff;
- voice->gf1_volume = snd_gf1_lvol_to_gvol_raw(volume->volume << 2) << 4;
- voice->venv_state_prev = VENV_SUSTAIN;
- voice->venv_state = VENV_VOLUME;
- do_volume_envelope(gus, voice);
- }
- if (volume->lr >= 0) {
- volume->lr &= 0x3fff;
- if (!gus->gf1.enh_mode) {
- voice->gf1_pan = (volume->lr >> 10) & 15;
- if (!gus->gf1.full_range_pan) {
- if (voice->gf1_pan == 0)
- voice->gf1_pan++;
- if (voice->gf1_pan == 15)
- voice->gf1_pan--;
- }
- voice->flags &= ~SNDRV_GF1_VFLG_PAN; /* before */
- do_pan_envelope(gus, voice);
- } else {
- set_enhanced_pan(gus, voice, volume->lr >> 7);
- }
- }
-}
-
-static void sample_loop(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop)
-{
- unsigned long flags;
- int w_16 = voice->control & 0x04;
- unsigned int begin, addr_start, addr_end;
- struct simple_instrument *simple;
- struct snd_seq_kinstr *instr;
-
-#if 0
- printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end);
-#endif
- instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
- if (instr == NULL)
- return;
- voice->instr = instr->instr; /* copy ID to speedup aliases */
- simple = KINSTR_DATA(instr);
- begin = simple->address.memory;
- addr_start = loop->start;
- addr_end = loop->end;
- addr_start = (((addr_start << 1) & ~0x1f) | (addr_start & 0x0f)) + begin;
- addr_end = (((addr_end << 1) & ~0x1f) | (addr_end & 0x0f)) + begin;
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
- snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- snd_seq_instr_free_use(gus->gf1.ilist, instr);
-}
-
-static void sample_pos(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position)
-{
- unsigned long flags;
- int w_16 = voice->control & 0x04;
- unsigned int begin, addr;
- struct simple_instrument *simple;
- struct snd_seq_kinstr *instr;
-
-#if 0
- printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end);
-#endif
- instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
- if (instr == NULL)
- return;
- voice->instr = instr->instr; /* copy ID to speedup aliases */
- simple = KINSTR_DATA(instr);
- begin = simple->address.memory;
- addr = (((position << 1) & ~0x1f) | (position & 0x0f)) + begin;
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_select_voice(gus, voice->number);
- snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- snd_seq_instr_free_use(gus->gf1.ilist, instr);
-}
-
-#if 0
-
-static unsigned char get_effects_mask( ultra_card_t *card, int value )
-{
- if ( value > 7 ) return 0;
- if ( card -> gf1.effects && card -> gf1.effects -> chip_type == ULTRA_EFFECT_CHIP_INTERWAVE )
- return card -> gf1.effects -> chip.interwave.voice_output[ value ];
- return 0;
-}
-
-#endif
-
-static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data)
-{
-#if 0
- unsigned long flags;
- unsigned char uc;
-
- switch ( *data ) {
- case ULTRA_PRIV1_IW_EFFECT:
- uc = get_effects_mask( card, ultra_get_byte( data, 4 ) );
- uc |= get_effects_mask( card, ultra_get_byte( data, 4 ) >> 4 );
- uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) );
- uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) >> 4 );
- voice -> data.simple.effect_accumulator = uc;
- voice -> data.simple.effect_volume = ultra_translate_voice_volume( card, ultra_get_word( data, 2 ) ) << 4;
- if ( !card -> gf1.enh_mode ) return;
- if ( voice -> flags & VFLG_WAIT_FOR_START ) return;
- if ( voice -> flags & VFLG_RUNNING )
- {
- CLI( &flags );
- gf1_select_voice( card, voice -> number );
- ultra_write8( card, GF1_VB_ACCUMULATOR, voice -> data.simple.effect_accumulator );
- ultra_write16( card, GF1_VW_EFFECT_VOLUME_FINAL, voice -> data.simple.effect_volume );
- STI( &flags );
- }
- break;
- case ULTRA_PRIV1_IW_LFO:
- ultra_lfo_command( card, voice -> number, data );
- }
-#endif
-}
-
-#if 0
-
-/*
- *
- */
-
-static void note_stop( ultra_card_t *card, ultra_voice_t *voice, int wait )
-{
-}
-
-static void note_wait( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_off( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_volume( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_pitchbend( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_vibrato( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_tremolo( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-/*
- *
- */
-
-static void chn_trigger_down( ultra_card_t *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority )
-{
-}
-
-static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note )
-{
-}
-
-static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 )
-{
-}
-
-/*
- *
- */
-
-#endif
-
-void snd_gf1_simple_init(struct snd_gus_voice *voice)
-{
- voice->handler_wave = interrupt_wave;
- voice->handler_volume = interrupt_volume;
- voice->handler_effect = interrupt_effect;
- voice->volume_change = NULL;
- voice->sample_ops = &sample_ops;
-}
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c
deleted file mode 100644
index 85a1b051f09..00000000000
--- a/sound/isa/gus/gus_synth.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Routines for Gravis UltraSound soundcards - Synthesizer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * 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 <linux/init.h>
-#include <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-#include <sound/seq_device.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer");
-MODULE_LICENSE("GPL");
-
-/*
- *
- */
-
-static void snd_gus_synth_free_voices(struct snd_gus_card * gus, int client, int port)
-{
- int idx;
- struct snd_gus_voice * voice;
-
- for (idx = 0; idx < 32; idx++) {
- voice = &gus->gf1.voices[idx];
- if (voice->use && voice->client == client && voice->port == port)
- snd_gf1_free_voice(gus, voice);
- }
-}
-
-static int snd_gus_synth_use(void *private_data, struct snd_seq_port_subscribe *info)
-{
- struct snd_gus_port * port = private_data;
- struct snd_gus_card * gus = port->gus;
- struct snd_gus_voice * voice;
- unsigned int idx;
-
- if (info->voices > 32)
- return -EINVAL;
- down(&gus->register_mutex);
- if (!snd_gus_use_inc(gus)) {
- up(&gus->register_mutex);
- return -EFAULT;
- }
- for (idx = 0; idx < info->voices; idx++) {
- voice = snd_gf1_alloc_voice(gus, SNDRV_GF1_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port);
- if (voice == NULL) {
- snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
- snd_gus_use_dec(gus);
- up(&gus->register_mutex);
- return -EBUSY;
- }
- voice->index = idx;
- }
- up(&gus->register_mutex);
- return 0;
-}
-
-static int snd_gus_synth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
-{
- struct snd_gus_port * port = private_data;
- struct snd_gus_card * gus = port->gus;
-
- down(&gus->register_mutex);
- snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
- snd_gus_use_dec(gus);
- up(&gus->register_mutex);
- return 0;
-}
-
-/*
- *
- */
-
-static void snd_gus_synth_free_private_instruments(struct snd_gus_port *p, int client)
-{
- struct snd_seq_instr_header ifree;
-
- memset(&ifree, 0, sizeof(ifree));
- ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE;
- snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0);
-}
-
-static int snd_gus_synth_event_input(struct snd_seq_event *ev, int direct,
- void *private_data, int atomic, int hop)
-{
- struct snd_gus_port * p = private_data;
-
- snd_assert(p != NULL, return -EINVAL);
- if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
- ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
- snd_gus_sample_event(ev, p);
- return 0;
- }
- if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
- ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
- if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
- snd_gus_synth_free_private_instruments(p, ev->data.addr.client);
- return 0;
- }
- }
- if (direct) {
- if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
- snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops,
- p->gus->gf1.ilist,
- ev,
- p->gus->gf1.seq_client,
- atomic, hop);
- return 0;
- }
- }
- return 0;
-}
-
-static void snd_gus_synth_instr_notify(void *private_data,
- struct snd_seq_kinstr *instr,
- int what)
-{
- unsigned int idx;
- struct snd_gus_card *gus = private_data;
- struct snd_gus_voice *pvoice;
- unsigned long flags;
-
- spin_lock_irqsave(&gus->event_lock, flags);
- for (idx = 0; idx < 32; idx++) {
- pvoice = &gus->gf1.voices[idx];
- if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
- if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
- pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY);
- } else {
- snd_gf1_stop_voice(gus, pvoice->number);
- pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
- }
- }
- }
- spin_unlock_irqrestore(&gus->event_lock, flags);
-}
-
-/*
- *
- */
-
-static void snd_gus_synth_free_port(void *private_data)
-{
- struct snd_gus_port * p = private_data;
-
- if (p)
- snd_midi_channel_free_set(p->chset);
-}
-
-static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx)
-{
- struct snd_gus_port * p;
- struct snd_seq_port_callback callbacks;
- char name[32];
- int result;
-
- p = &gus->gf1.seq_ports[idx];
- p->chset = snd_midi_channel_alloc_set(16);
- if (p->chset == NULL)
- return -ENOMEM;
- p->chset->private_data = p;
- p->gus = gus;
- p->client = gus->gf1.seq_client;
-
- memset(&callbacks, 0, sizeof(callbacks));
- callbacks.owner = THIS_MODULE;
- callbacks.use = snd_gus_synth_use;
- callbacks.unuse = snd_gus_synth_unuse;
- callbacks.event_input = snd_gus_synth_event_input;
- callbacks.private_free = snd_gus_synth_free_port;
- callbacks.private_data = p;
-
- sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx);
- p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client,
- &callbacks,
- SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
- SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
- SNDRV_SEQ_PORT_TYPE_SYNTH,
- 16, 0,
- name);
- if (p->chset->port < 0) {
- result = p->chset->port;
- snd_gus_synth_free_port(p);
- return result;
- }
- p->port = p->chset->port;
- return 0;
-}
-
-/*
- *
- */
-
-static int snd_gus_synth_new_device(struct snd_seq_device *dev)
-{
- struct snd_gus_card *gus;
- int client, i;
- struct snd_seq_port_subscribe sub;
- struct snd_iwffff_ops *iwops;
- struct snd_gf1_ops *gf1ops;
- struct snd_simple_ops *simpleops;
-
- gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
- if (gus == NULL)
- return -EINVAL;
-
- init_MUTEX(&gus->register_mutex);
- gus->gf1.seq_client = -1;
-
- /* allocate new client */
- client = gus->gf1.seq_client =
- snd_seq_create_kernel_client(gus->card, 1, gus->interwave ?
- "AMD InterWave" : "GF1");
- if (client < 0)
- return client;
-
- for (i = 0; i < 4; i++)
- snd_gus_synth_create_port(gus, i);
-
- gus->gf1.ilist = snd_seq_instr_list_new();
- if (gus->gf1.ilist == NULL) {
- snd_seq_delete_kernel_client(client);
- gus->gf1.seq_client = -1;
- return -ENOMEM;
- }
- gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
-
- simpleops = &gus->gf1.simple_ops;
- snd_seq_simple_init(simpleops, gus, NULL);
- simpleops->put_sample = snd_gus_simple_put_sample;
- simpleops->get_sample = snd_gus_simple_get_sample;
- simpleops->remove_sample = snd_gus_simple_remove_sample;
- simpleops->notify = snd_gus_synth_instr_notify;
-
- gf1ops = &gus->gf1.gf1_ops;
- snd_seq_gf1_init(gf1ops, gus, &simpleops->kops);
- gf1ops->put_sample = snd_gus_gf1_put_sample;
- gf1ops->get_sample = snd_gus_gf1_get_sample;
- gf1ops->remove_sample = snd_gus_gf1_remove_sample;
- gf1ops->notify = snd_gus_synth_instr_notify;
-
- iwops = &gus->gf1.iwffff_ops;
- snd_seq_iwffff_init(iwops, gus, &gf1ops->kops);
- iwops->put_sample = snd_gus_iwffff_put_sample;
- iwops->get_sample = snd_gus_iwffff_get_sample;
- iwops->remove_sample = snd_gus_iwffff_remove_sample;
- iwops->notify = snd_gus_synth_instr_notify;
-
- memset(&sub, 0, sizeof(sub));
- sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
- sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
- sub.dest.client = client;
- sub.dest.port = 0;
- snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
-
- return 0;
-}
-
-static int snd_gus_synth_delete_device(struct snd_seq_device *dev)
-{
- struct snd_gus_card *gus;
-
- gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
- if (gus == NULL)
- return -EINVAL;
-
- if (gus->gf1.seq_client >= 0) {
- snd_seq_delete_kernel_client(gus->gf1.seq_client);
- gus->gf1.seq_client = -1;
- }
- if (gus->gf1.ilist)
- snd_seq_instr_list_free(&gus->gf1.ilist);
- return 0;
-}
-
-static int __init alsa_gus_synth_init(void)
-{
- static struct snd_seq_dev_ops ops = {
- snd_gus_synth_new_device,
- snd_gus_synth_delete_device
- };
-
- return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops,
- sizeof(struct snd_gus_card *));
-}
-
-static void __exit alsa_gus_synth_exit(void)
-{
- snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS);
-}
-
-module_init(alsa_gus_synth_init)
-module_exit(alsa_gus_synth_exit)
diff --git a/sound/isa/gus/gus_tables.h b/sound/isa/gus/gus_tables.h
index 4adf098d326..42a4ca0d622 100644
--- a/sound/isa/gus/gus_tables.h
+++ b/sound/isa/gus/gus_tables.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/sound/isa/gus/gus_timer.c b/sound/isa/gus/gus_timer.c
index a43b662f17c..c53727147a1 100644
--- a/sound/isa/gus/gus_timer.c
+++ b/sound/isa/gus/gus_timer.c
@@ -1,6 +1,6 @@
/*
* Routines for Gravis UltraSound soundcards - Timers
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
* GUS have similar timers as AdLib (OPL2/OPL3 chips).
*
@@ -21,7 +21,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/gus.h>
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
index 654290a8b21..21cc42e4c4b 100644
--- a/sound/isa/gus/gus_uart.c
+++ b/sound/isa/gus/gus_uart.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for the GF1 MIDI interface - like UART 6850
*
*
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/time.h>
@@ -130,8 +129,14 @@ static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream)
}
spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
#if 0
- snd_printk("read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
- snd_printk("[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n", gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100), inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
+ snd_printk(KERN_DEBUG
+ "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
+ gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
+ snd_printk(KERN_DEBUG
+ "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
+ "(page = 0x%x)\n",
+ gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100),
+ inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
#endif
return 0;
}
diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c
index dbbc0a6d765..3dd841ae708 100644
--- a/sound/isa/gus/gus_volume.c
+++ b/sound/isa/gus/gus_volume.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/gus.h>
#define __GUS_TABLES_ALLOC__
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index d1165b96fa3..7ce29ffa1af 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -1,6 +1,6 @@
/*
* Driver for Gravis UltraSound Classic soundcard
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,12 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/delay.h>
#include <linux/time.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/gus.h>
@@ -33,14 +32,17 @@
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Gravis UltraSound Classic");
+#define CRD_NAME "Gravis UltraSound Classic"
+#define DEV_NAME "gusclassic"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Classic}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x230,0x240,0x250,0x260 */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 3,5,9,11,12,15 */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
@@ -51,32 +53,78 @@ static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for GUS Classic soundcard.");
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for GUS Classic soundcard.");
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable GUS Classic soundcard.");
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for GUS Classic driver.");
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for GUS Classic driver.");
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for GUS Classic driver.");
+MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver.");
module_param_array(dma2, int, NULL, 0444);
-MODULE_PARM_DESC(dma2, "DMA2 # for GUS Classic driver.");
+MODULE_PARM_DESC(dma2, "DMA2 # for " CRD_NAME " driver.");
module_param_array(joystick_dac, int, NULL, 0444);
-MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Classic driver.");
+MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for " CRD_NAME " driver.");
module_param_array(channels, int, NULL, 0444);
-MODULE_PARM_DESC(channels, "GF1 channels for GUS Classic driver.");
+MODULE_PARM_DESC(channels, "GF1 channels for " CRD_NAME " driver.");
module_param_array(pcm_channels, int, NULL, 0444);
-MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Classic driver.");
+MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for " CRD_NAME " driver.");
+
+static int snd_gusclassic_match(struct device *dev, unsigned int n)
+{
+ return enable[n];
+}
+
+static int snd_gusclassic_create(struct snd_card *card,
+ struct device *dev, unsigned int n,
+ struct snd_gus_card **rgus)
+{
+ static long possible_ports[] = {0x220, 0x230, 0x240, 0x250, 0x260};
+ static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, 4, -1};
+ static int possible_dmas[] = {5, 6, 7, 1, 3, -1};
+
+ int i, error;
+
+ if (irq[n] == SNDRV_AUTO_IRQ) {
+ irq[n] = snd_legacy_find_free_irq(possible_irqs);
+ if (irq[n] < 0) {
+ dev_err(dev, "unable to find a free IRQ\n");
+ return -EBUSY;
+ }
+ }
+ if (dma1[n] == SNDRV_AUTO_DMA) {
+ dma1[n] = snd_legacy_find_free_dma(possible_dmas);
+ if (dma1[n] < 0) {
+ dev_err(dev, "unable to find a free DMA1\n");
+ return -EBUSY;
+ }
+ }
+ if (dma2[n] == SNDRV_AUTO_DMA) {
+ dma2[n] = snd_legacy_find_free_dma(possible_dmas);
+ if (dma2[n] < 0) {
+ dev_err(dev, "unable to find a free DMA2\n");
+ return -EBUSY;
+ }
+ }
-static struct platform_device *devices[SNDRV_CARDS];
+ if (port[n] != SNDRV_AUTO_PORT)
+ return snd_gus_create(card, port[n], irq[n], dma1[n], dma2[n],
+ 0, channels[n], pcm_channels[n], 0, rgus);
+ i = 0;
+ do {
+ port[n] = possible_ports[i];
+ error = snd_gus_create(card, port[n], irq[n], dma1[n], dma2[n],
+ 0, channels[n], pcm_channels[n], 0, rgus);
+ } while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
-#define PFX "gusclassic: "
+ return error;
+}
-static int __init snd_gusclassic_detect(struct snd_gus_card * gus)
+static int snd_gusclassic_detect(struct snd_gus_card *gus)
{
unsigned char d;
@@ -95,187 +143,101 @@ static int __init snd_gusclassic_detect(struct snd_gus_card * gus)
return 0;
}
-static void __init snd_gusclassic_init(int dev, struct snd_gus_card * gus)
-{
- gus->equal_irq = 0;
- gus->codec_flag = 0;
- gus->max_flag = 0;
- gus->joystick_dac = joystick_dac[dev];
-}
-
-static int __init snd_gusclassic_probe(struct platform_device *pdev)
+static int snd_gusclassic_probe(struct device *dev, unsigned int n)
{
- int dev = pdev->id;
- static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, 4, -1};
- static int possible_dmas[] = {5, 6, 7, 1, 3, -1};
- int xirq, xdma1, xdma2;
struct snd_card *card;
- struct snd_gus_card *gus = NULL;
- int err;
-
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
- if (pcm_channels[dev] < 2)
- pcm_channels[dev] = 2;
-
- xirq = irq[dev];
- if (xirq == SNDRV_AUTO_IRQ) {
- if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
- err = -EBUSY;
- goto _err;
- }
- }
- xdma1 = dma1[dev];
- if (xdma1 == SNDRV_AUTO_DMA) {
- if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA1\n");
- err = -EBUSY;
- goto _err;
- }
- }
- xdma2 = dma2[dev];
- if (xdma2 == SNDRV_AUTO_DMA) {
- if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA2\n");
- err = -EBUSY;
- goto _err;
- }
- }
+ struct snd_gus_card *gus;
+ int error;
- if (port[dev] != SNDRV_AUTO_PORT) {
- err = snd_gus_create(card,
- port[dev],
- xirq, xdma1, xdma2,
- 0, channels[dev], pcm_channels[dev],
- 0, &gus);
- } else {
- /* auto-probe legacy ports */
- static unsigned long possible_ports[] = {
- 0x220, 0x230, 0x240, 0x250, 0x260,
- };
- int i;
- for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
- err = snd_gus_create(card,
- possible_ports[i],
- xirq, xdma1, xdma2,
- 0, channels[dev], pcm_channels[dev],
- 0, &gus);
- if (err >= 0) {
- port[dev] = possible_ports[i];
- break;
- }
- }
- }
- if (err < 0)
- goto _err;
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
- if ((err = snd_gusclassic_detect(gus)) < 0)
- goto _err;
+ if (pcm_channels[n] < 2)
+ pcm_channels[n] = 2;
- snd_gusclassic_init(dev, gus);
- if ((err = snd_gus_initialize(gus)) < 0)
- goto _err;
+ error = snd_gusclassic_create(card, dev, n, &gus);
+ if (error < 0)
+ goto out;
+ error = snd_gusclassic_detect(gus);
+ if (error < 0)
+ goto out;
+
+ gus->joystick_dac = joystick_dac[n];
+
+ error = snd_gus_initialize(gus);
+ if (error < 0)
+ goto out;
+
+ error = -ENODEV;
if (gus->max_flag || gus->ess_flag) {
- snd_printk(KERN_ERR PFX "GUS Classic or ACE soundcard was not detected at 0x%lx\n", gus->gf1.port);
- err = -ENODEV;
- goto _err;
+ dev_err(dev, "GUS Classic or ACE soundcard was "
+ "not detected at 0x%lx\n", gus->gf1.port);
+ goto out;
}
- if ((err = snd_gf1_new_mixer(gus)) < 0)
- goto _err;
+ error = snd_gf1_new_mixer(gus);
+ if (error < 0)
+ goto out;
- if ((err = snd_gf1_pcm_new(gus, 0, 0, NULL)) < 0)
- goto _err;
+ error = snd_gf1_pcm_new(gus, 0, 0, NULL);
+ if (error < 0)
+ goto out;
if (!gus->ace_flag) {
- if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
- goto _err;
+ error = snd_gf1_rawmidi_new(gus, 0, NULL);
+ if (error < 0)
+ goto out;
}
- sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %d, dma %d", gus->gf1.port, xirq, xdma1);
- if (dma2 >= 0)
- sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
- snd_card_set_dev(card, &pdev->dev);
+ sprintf(card->longname + strlen(card->longname),
+ " at 0x%lx, irq %d, dma %d",
+ gus->gf1.port, gus->gf1.irq, gus->gf1.dma1);
- if ((err = snd_card_register(card)) < 0)
- goto _err;
+ if (gus->gf1.dma2 >= 0)
+ sprintf(card->longname + strlen(card->longname),
+ "&%d", gus->gf1.dma2);
- platform_set_drvdata(pdev, card);
+ error = snd_card_register(card);
+ if (error < 0)
+ goto out;
+
+ dev_set_drvdata(dev, card);
return 0;
- _err:
- snd_card_free(card);
- return err;
+out: snd_card_free(card);
+ return error;
}
-static int snd_gusclassic_remove(struct platform_device *devptr)
+static int snd_gusclassic_remove(struct device *dev, unsigned int n)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(dev));
return 0;
}
-#define GUSCLASSIC_DRIVER "snd_gusclassic"
-
-static struct platform_driver snd_gusclassic_driver = {
+static struct isa_driver snd_gusclassic_driver = {
+ .match = snd_gusclassic_match,
.probe = snd_gusclassic_probe,
.remove = snd_gusclassic_remove,
- /* FIXME: suspend/resume */
+#if 0 /* FIXME */
+ .suspend = snd_gusclassic_suspend,
+ .remove = snd_gusclassic_remove,
+#endif
.driver = {
- .name = GUSCLASSIC_DRIVER
- },
+ .name = DEV_NAME
+ }
};
-static void __init_or_module snd_gusclassic_unregister_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_gusclassic_driver);
-}
-
static int __init alsa_card_gusclassic_init(void)
{
- int i, cards, err;
-
- err = platform_driver_register(&snd_gusclassic_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(GUSCLASSIC_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
- }
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR "GUS Classic soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_gusclassic_unregister_all();
- return err;
+ return isa_register_driver(&snd_gusclassic_driver, SNDRV_CARDS);
}
static void __exit alsa_card_gusclassic_exit(void)
{
- snd_gusclassic_unregister_all();
+ isa_unregister_driver(&snd_gusclassic_driver);
}
-module_init(alsa_card_gusclassic_init)
-module_exit(alsa_card_gusclassic_exit)
+module_init(alsa_card_gusclassic_init);
+module_exit(alsa_card_gusclassic_exit);
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 239f16e6b9e..28a16936a39 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -1,6 +1,6 @@
/*
* Driver for Gravis UltraSound Extreme soundcards
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,12 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/delay.h>
#include <linux/time.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/gus.h>
@@ -37,14 +36,17 @@
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Gravis UltraSound Extreme");
+#define CRD_NAME "Gravis UltraSound Extreme"
+#define DEV_NAME "gusextreme"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Extreme}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
static long gf1_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x210,0x220,0x230,0x240,0x250,0x260,0x270 */
static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x300,0x310,0x320 */
@@ -59,43 +61,105 @@ static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for GUS Extreme soundcard.");
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for GUS Extreme soundcard.");
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable GUS Extreme soundcard.");
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for GUS Extreme driver.");
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
module_param_array(gf1_port, long, NULL, 0444);
-MODULE_PARM_DESC(gf1_port, "GF1 port # for GUS Extreme driver (optional).");
+MODULE_PARM_DESC(gf1_port, "GF1 port # for " CRD_NAME " driver (optional).");
module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for GUS Extreme driver.");
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for GUS Extreme driver.");
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for GUS Extreme driver.");
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
module_param_array(gf1_irq, int, NULL, 0444);
-MODULE_PARM_DESC(gf1_irq, "GF1 IRQ # for GUS Extreme driver.");
+MODULE_PARM_DESC(gf1_irq, "GF1 IRQ # for " CRD_NAME " driver.");
module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for GUS Extreme driver.");
+MODULE_PARM_DESC(dma8, "8-bit DMA # for " CRD_NAME " driver.");
module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "GF1 DMA # for GUS Extreme driver.");
+MODULE_PARM_DESC(dma1, "GF1 DMA # for " CRD_NAME " driver.");
module_param_array(joystick_dac, int, NULL, 0444);
-MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Extreme driver.");
+MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for " CRD_NAME " driver.");
module_param_array(channels, int, NULL, 0444);
-MODULE_PARM_DESC(channels, "GF1 channels for GUS Extreme driver.");
+MODULE_PARM_DESC(channels, "GF1 channels for " CRD_NAME " driver.");
module_param_array(pcm_channels, int, NULL, 0444);
-MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Extreme driver.");
+MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for " CRD_NAME " driver.");
-struct platform_device *devices[SNDRV_CARDS];
+static int snd_gusextreme_match(struct device *dev, unsigned int n)
+{
+ return enable[n];
+}
+
+static int snd_gusextreme_es1688_create(struct snd_card *card,
+ struct snd_es1688 *chip,
+ struct device *dev, unsigned int n)
+{
+ static long possible_ports[] = {0x220, 0x240, 0x260};
+ static int possible_irqs[] = {5, 9, 10, 7, -1};
+ static int possible_dmas[] = {1, 3, 0, -1};
+ int i, error;
-#define PFX "gusextreme: "
+ if (irq[n] == SNDRV_AUTO_IRQ) {
+ irq[n] = snd_legacy_find_free_irq(possible_irqs);
+ if (irq[n] < 0) {
+ dev_err(dev, "unable to find a free IRQ for ES1688\n");
+ return -EBUSY;
+ }
+ }
+ if (dma8[n] == SNDRV_AUTO_DMA) {
+ dma8[n] = snd_legacy_find_free_dma(possible_dmas);
+ if (dma8[n] < 0) {
+ dev_err(dev, "unable to find a free DMA for ES1688\n");
+ return -EBUSY;
+ }
+ }
-static int __init snd_gusextreme_detect(int dev,
- struct snd_card *card,
- struct snd_gus_card * gus,
- struct snd_es1688 *es1688)
+ if (port[n] != SNDRV_AUTO_PORT)
+ return snd_es1688_create(card, chip, port[n], mpu_port[n],
+ irq[n], mpu_irq[n], dma8[n], ES1688_HW_1688);
+
+ i = 0;
+ do {
+ port[n] = possible_ports[i];
+ error = snd_es1688_create(card, chip, port[n], mpu_port[n],
+ irq[n], mpu_irq[n], dma8[n], ES1688_HW_1688);
+ } while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
+
+ return error;
+}
+
+static int snd_gusextreme_gus_card_create(struct snd_card *card,
+ struct device *dev, unsigned int n,
+ struct snd_gus_card **rgus)
+{
+ static int possible_irqs[] = {11, 12, 15, 9, 5, 7, 3, -1};
+ static int possible_dmas[] = {5, 6, 7, 3, 1, -1};
+
+ if (gf1_irq[n] == SNDRV_AUTO_IRQ) {
+ gf1_irq[n] = snd_legacy_find_free_irq(possible_irqs);
+ if (gf1_irq[n] < 0) {
+ dev_err(dev, "unable to find a free IRQ for GF1\n");
+ return -EBUSY;
+ }
+ }
+ if (dma1[n] == SNDRV_AUTO_DMA) {
+ dma1[n] = snd_legacy_find_free_dma(possible_dmas);
+ if (dma1[n] < 0) {
+ dev_err(dev, "unable to find a free DMA for GF1\n");
+ return -EBUSY;
+ }
+ }
+ return snd_gus_create(card, gf1_port[n], gf1_irq[n], dma1[n], -1,
+ 0, channels[n], pcm_channels[n], 0, rgus);
+}
+
+static int snd_gusextreme_detect(struct snd_gus_card *gus,
+ struct snd_es1688 *es1688)
{
unsigned long flags;
unsigned char d;
@@ -117,12 +181,13 @@ static int __init snd_gusextreme_detect(int dev,
spin_lock_irqsave(&es1688->mixer_lock, flags);
snd_es1688_mixer_write(es1688, 0x40, 0x0b); /* don't change!!! */
spin_unlock_irqrestore(&es1688->mixer_lock, flags);
+
spin_lock_irqsave(&es1688->reg_lock, flags);
- outb(gf1_port[dev] & 0x040 ? 2 : 0, ES1688P(es1688, INIT1));
+ outb(gus->gf1.port & 0x040 ? 2 : 0, ES1688P(es1688, INIT1));
outb(0, 0x201);
- outb(gf1_port[dev] & 0x020 ? 2 : 0, ES1688P(es1688, INIT1));
+ outb(gus->gf1.port & 0x020 ? 2 : 0, ES1688P(es1688, INIT1));
outb(0, 0x201);
- outb(gf1_port[dev] & 0x010 ? 3 : 1, ES1688P(es1688, INIT1));
+ outb(gus->gf1.port & 0x010 ? 3 : 1, ES1688P(es1688, INIT1));
spin_unlock_irqrestore(&es1688->reg_lock, flags);
udelay(100);
@@ -139,253 +204,169 @@ static int __init snd_gusextreme_detect(int dev,
snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
return -EIO;
}
- return 0;
-}
-static void __init snd_gusextreme_init(int dev, struct snd_gus_card * gus)
-{
- gus->joystick_dac = joystick_dac[dev];
+ return 0;
}
-static int __init snd_gusextreme_mixer(struct snd_es1688 *chip)
+static int snd_gusextreme_mixer(struct snd_card *card)
{
- struct snd_card *card = chip->card;
struct snd_ctl_elem_id id1, id2;
- int err;
+ int error;
memset(&id1, 0, sizeof(id1));
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+
/* reassign AUX to SYNTHESIZER */
strcpy(id1.name, "Aux Playback Volume");
strcpy(id2.name, "Synth Playback Volume");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
+ error = snd_ctl_rename_id(card, &id1, &id2);
+ if (error < 0)
+ return error;
+
/* reassign Master Playback Switch to Synth Playback Switch */
strcpy(id1.name, "Master Playback Switch");
strcpy(id2.name, "Synth Playback Switch");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
+ error = snd_ctl_rename_id(card, &id1, &id2);
+ if (error < 0)
+ return error;
+
return 0;
}
-static int __init snd_gusextreme_probe(struct platform_device *pdev)
+static int snd_gusextreme_probe(struct device *dev, unsigned int n)
{
- int dev = pdev->id;
- static int possible_ess_irqs[] = {5, 9, 10, 7, -1};
- static int possible_ess_dmas[] = {1, 3, 0, -1};
- static int possible_gf1_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
- static int possible_gf1_dmas[] = {5, 6, 7, 1, 3, -1};
- int xgf1_irq, xgf1_dma, xess_irq, xmpu_irq, xess_dma;
struct snd_card *card;
struct snd_gus_card *gus;
struct snd_es1688 *es1688;
struct snd_opl3 *opl3;
- int err;
+ int error;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
+ if (error < 0)
+ return error;
- xgf1_irq = gf1_irq[dev];
- if (xgf1_irq == SNDRV_AUTO_IRQ) {
- if ((xgf1_irq = snd_legacy_find_free_irq(possible_gf1_irqs)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ for GF1\n");
- err = -EBUSY;
- goto out;
- }
- }
- xess_irq = irq[dev];
- if (xess_irq == SNDRV_AUTO_IRQ) {
- if ((xess_irq = snd_legacy_find_free_irq(possible_ess_irqs)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ for ES1688\n");
- err = -EBUSY;
- goto out;
- }
- }
- if (mpu_port[dev] == SNDRV_AUTO_PORT)
- mpu_port[dev] = 0;
- xmpu_irq = mpu_irq[dev];
- if (xmpu_irq > 15)
- xmpu_irq = -1;
- xgf1_dma = dma1[dev];
- if (xgf1_dma == SNDRV_AUTO_DMA) {
- if ((xgf1_dma = snd_legacy_find_free_dma(possible_gf1_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA for GF1\n");
- err = -EBUSY;
- goto out;
- }
- }
- xess_dma = dma8[dev];
- if (xess_dma == SNDRV_AUTO_DMA) {
- if ((xess_dma = snd_legacy_find_free_dma(possible_ess_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA for ES1688\n");
- err = -EBUSY;
- goto out;
- }
- }
+ es1688 = card->private_data;
- if (port[dev] != SNDRV_AUTO_PORT) {
- err = snd_es1688_create(card, port[dev], mpu_port[dev],
- xess_irq, xmpu_irq, xess_dma,
- ES1688_HW_1688, &es1688);
- } else {
- /* auto-probe legacy ports */
- static unsigned long possible_ports[] = {0x220, 0x240, 0x260};
- int i;
- for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
- err = snd_es1688_create(card,
- possible_ports[i],
- mpu_port[dev],
- xess_irq, xmpu_irq, xess_dma,
- ES1688_HW_1688, &es1688);
- if (err >= 0) {
- port[dev] = possible_ports[i];
- break;
- }
- }
- }
- if (err < 0)
+ if (mpu_port[n] == SNDRV_AUTO_PORT)
+ mpu_port[n] = 0;
+
+ if (mpu_irq[n] > 15)
+ mpu_irq[n] = -1;
+
+ error = snd_gusextreme_es1688_create(card, es1688, dev, n);
+ if (error < 0)
goto out;
- if (gf1_port[dev] < 0)
- gf1_port[dev] = port[dev] + 0x20;
- if ((err = snd_gus_create(card,
- gf1_port[dev],
- xgf1_irq,
- xgf1_dma,
- -1,
- 0, channels[dev],
- pcm_channels[dev], 0,
- &gus)) < 0)
+ if (gf1_port[n] < 0)
+ gf1_port[n] = es1688->port + 0x20;
+
+ error = snd_gusextreme_gus_card_create(card, dev, n, &gus);
+ if (error < 0)
goto out;
- if ((err = snd_gusextreme_detect(dev, card, gus, es1688)) < 0)
+ error = snd_gusextreme_detect(gus, es1688);
+ if (error < 0)
goto out;
- snd_gusextreme_init(dev, gus);
- if ((err = snd_gus_initialize(gus)) < 0)
+ gus->joystick_dac = joystick_dac[n];
+
+ error = snd_gus_initialize(gus);
+ if (error < 0)
goto out;
+ error = -ENODEV;
if (!gus->ess_flag) {
- snd_printk(KERN_ERR PFX "GUS Extreme soundcard was not detected at 0x%lx\n", gus->gf1.port);
- err = -ENODEV;
+ dev_err(dev, "GUS Extreme soundcard was not "
+ "detected at 0x%lx\n", gus->gf1.port);
goto out;
}
- if ((err = snd_es1688_pcm(es1688, 0, NULL)) < 0)
+ gus->codec_flag = 1;
+
+ error = snd_es1688_pcm(card, es1688, 0, NULL);
+ if (error < 0)
goto out;
- if ((err = snd_es1688_mixer(es1688)) < 0)
+ error = snd_es1688_mixer(card, es1688);
+ if (error < 0)
goto out;
snd_component_add(card, "ES1688");
- if (pcm_channels[dev] > 0) {
- if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+
+ if (pcm_channels[n] > 0) {
+ error = snd_gf1_pcm_new(gus, 1, 1, NULL);
+ if (error < 0)
goto out;
}
- if ((err = snd_gf1_new_mixer(gus)) < 0)
+
+ error = snd_gf1_new_mixer(gus);
+ if (error < 0)
goto out;
- if ((err = snd_gusextreme_mixer(es1688)) < 0)
+ error = snd_gusextreme_mixer(card);
+ if (error < 0)
goto out;
if (snd_opl3_create(card, es1688->port, es1688->port + 2,
- OPL3_HW_OPL3, 0, &opl3) < 0) {
- printk(KERN_ERR PFX "gusextreme: opl3 not detected at 0x%lx\n", es1688->port);
- } else {
- if ((err = snd_opl3_hwdep_new(opl3, 0, 2, NULL)) < 0)
+ OPL3_HW_OPL3, 0, &opl3) < 0)
+ dev_warn(dev, "opl3 not detected at 0x%lx\n", es1688->port);
+ else {
+ error = snd_opl3_hwdep_new(opl3, 0, 2, NULL);
+ if (error < 0)
goto out;
}
- if (es1688->mpu_port >= 0x300 &&
- (err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
- es1688->mpu_port, 0,
- xmpu_irq,
- SA_INTERRUPT,
- NULL)) < 0)
- goto out;
-
- sprintf(card->longname, "Gravis UltraSound Extreme at 0x%lx, irq %i&%i, dma %i&%i",
- es1688->port, xgf1_irq, xess_irq, xgf1_dma, xess_dma);
+ if (es1688->mpu_port >= 0x300) {
+ error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
+ es1688->mpu_port, 0, mpu_irq[n], NULL);
+ if (error < 0)
+ goto out;
+ }
- snd_card_set_dev(card, &pdev->dev);
+ sprintf(card->longname, "Gravis UltraSound Extreme at 0x%lx, "
+ "irq %i&%i, dma %i&%i", es1688->port,
+ gus->gf1.irq, es1688->irq, gus->gf1.dma1, es1688->dma8);
- if ((err = snd_card_register(card)) < 0)
+ error = snd_card_register(card);
+ if (error < 0)
goto out;
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(dev, card);
return 0;
- out:
- snd_card_free(card);
- return err;
+out: snd_card_free(card);
+ return error;
}
-static int snd_gusextreme_remove(struct platform_device *devptr)
+static int snd_gusextreme_remove(struct device *dev, unsigned int n)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(dev));
return 0;
}
-#define GUSEXTREME_DRIVER "snd_gusextreme"
-
-static struct platform_driver snd_gusextreme_driver = {
+static struct isa_driver snd_gusextreme_driver = {
+ .match = snd_gusextreme_match,
.probe = snd_gusextreme_probe,
.remove = snd_gusextreme_remove,
- /* FIXME: suspend/resume */
+#if 0 /* FIXME */
+ .suspend = snd_gusextreme_suspend,
+ .resume = snd_gusextreme_resume,
+#endif
.driver = {
- .name = GUSEXTREME_DRIVER
- },
+ .name = DEV_NAME
+ }
};
-static void __init_or_module snd_gusextreme_unregister_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_gusextreme_driver);
-}
-
static int __init alsa_card_gusextreme_init(void)
{
- int i, cards, err;
-
- err = platform_driver_register(&snd_gusextreme_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(GUSEXTREME_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
- }
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR "GUS Extreme soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_gusextreme_unregister_all();
- return err;
+ return isa_register_driver(&snd_gusextreme_driver, SNDRV_CARDS);
}
static void __exit alsa_card_gusextreme_exit(void)
{
- snd_gusextreme_unregister_all();
+ isa_unregister_driver(&snd_gusextreme_driver);
}
-module_init(alsa_card_gusextreme_init)
-module_exit(alsa_card_gusextreme_exit)
+module_init(alsa_card_gusextreme_init);
+module_exit(alsa_card_gusextreme_exit);
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index d4d2b2a517d..39df36ca3ac 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -1,6 +1,6 @@
/*
* Driver for Gravis UltraSound MAX soundcard
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,29 +19,28 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/delay.h>
#include <linux/time.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/gus.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Gravis UltraSound MAX");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound MAX}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x230,0x240,0x250,0x260 */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,3,5,9,11,12,15 */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
@@ -72,20 +71,18 @@ MODULE_PARM_DESC(channels, "Used GF1 channels for GUS MAX driver.");
module_param_array(pcm_channels, int, NULL, 0444);
MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS MAX driver.");
-static struct platform_device *devices[SNDRV_CARDS];
-
struct snd_gusmax {
int irq;
struct snd_card *card;
struct snd_gus_card *gus;
- struct snd_cs4231 *cs4231;
+ struct snd_wss *wss;
unsigned short gus_status_reg;
unsigned short pcm_status_reg;
};
#define PFX "gusmax: "
-static int __init snd_gusmax_detect(struct snd_gus_card * gus)
+static int snd_gusmax_detect(struct snd_gus_card *gus)
{
unsigned char d;
@@ -105,9 +102,9 @@ static int __init snd_gusmax_detect(struct snd_gus_card * gus)
return 0;
}
-static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id)
{
- struct snd_gusmax *maxcard = (struct snd_gusmax *) dev_id;
+ struct snd_gusmax *maxcard = dev_id;
int loop, max = 5;
int handled = 0;
@@ -115,19 +112,20 @@ static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *r
loop = 0;
if (inb(maxcard->gus_status_reg)) {
handled = 1;
- snd_gus_interrupt(irq, maxcard->gus, regs);
+ snd_gus_interrupt(irq, maxcard->gus);
loop++;
}
if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
handled = 1;
- snd_cs4231_interrupt(irq, maxcard->cs4231, regs);
+ snd_wss_interrupt(irq, maxcard->wss);
loop++;
}
} while (loop && --max > 0);
return IRQ_RETVAL(handled);
}
-static void __init snd_gusmax_init(int dev, struct snd_card *card, struct snd_gus_card * gus)
+static void snd_gusmax_init(int dev, struct snd_card *card,
+ struct snd_gus_card *gus)
{
gus->equal_irq = 1;
gus->codec_flag = 1;
@@ -142,10 +140,7 @@ static void __init snd_gusmax_init(int dev, struct snd_card *card, struct snd_gu
outb(gus->max_cntrl_val, GUSP(gus, MAXCNTRLPORT));
}
-#define CS4231_PRIVATE( left, right, shift, mute ) \
- ((left << 24)|(right << 16)|(shift<<8)|mute)
-
-static int __init snd_gusmax_mixer(struct snd_cs4231 *chip)
+static int snd_gusmax_mixer(struct snd_wss *chip)
{
struct snd_card *card = chip->card;
struct snd_ctl_elem_id id1, id2;
@@ -196,7 +191,7 @@ static int __init snd_gusmax_mixer(struct snd_cs4231 *chip)
static void snd_gusmax_free(struct snd_card *card)
{
- struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
+ struct snd_gusmax *maxcard = card->private_data;
if (maxcard == NULL)
return;
@@ -204,23 +199,27 @@ static void snd_gusmax_free(struct snd_card *card)
free_irq(maxcard->irq, (void *)maxcard);
}
-static int __init snd_gusmax_probe(struct platform_device *pdev)
+static int snd_gusmax_match(struct device *pdev, unsigned int dev)
+{
+ return enable[dev];
+}
+
+static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
{
- int dev = pdev->id;
static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
static int possible_dmas[] = {5, 6, 7, 1, 3, -1};
int xirq, xdma1, xdma2, err;
struct snd_card *card;
struct snd_gus_card *gus = NULL;
- struct snd_cs4231 *cs4231;
+ struct snd_wss *wss;
struct snd_gusmax *maxcard;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_gusmax));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_gusmax), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_gusmax_free;
- maxcard = (struct snd_gusmax *)card->private_data;
+ maxcard = card->private_data;
maxcard->card = card;
maxcard->irq = -1;
@@ -292,55 +291,60 @@ static int __init snd_gusmax_probe(struct platform_device *pdev)
goto _err;
}
- if (request_irq(xirq, snd_gusmax_interrupt, SA_INTERRUPT, "GUS MAX", (void *)maxcard)) {
+ if (request_irq(xirq, snd_gusmax_interrupt, 0, "GUS MAX", (void *)maxcard)) {
snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq);
err = -EBUSY;
goto _err;
}
maxcard->irq = xirq;
- if ((err = snd_cs4231_create(card,
- gus->gf1.port + 0x10c, -1, xirq,
- xdma2 < 0 ? xdma1 : xdma2, xdma1,
- CS4231_HW_DETECT,
- CS4231_HWSHARE_IRQ |
- CS4231_HWSHARE_DMA1 |
- CS4231_HWSHARE_DMA2,
- &cs4231)) < 0)
+ err = snd_wss_create(card,
+ gus->gf1.port + 0x10c, -1, xirq,
+ xdma2 < 0 ? xdma1 : xdma2, xdma1,
+ WSS_HW_DETECT,
+ WSS_HWSHARE_IRQ |
+ WSS_HWSHARE_DMA1 |
+ WSS_HWSHARE_DMA2,
+ &wss);
+ if (err < 0)
goto _err;
- if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0)
+ err = snd_wss_pcm(wss, 0, NULL);
+ if (err < 0)
goto _err;
- if ((err = snd_cs4231_mixer(cs4231)) < 0)
+ err = snd_wss_mixer(wss);
+ if (err < 0)
goto _err;
- if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0)
+ err = snd_wss_timer(wss, 2, NULL);
+ if (err < 0)
goto _err;
if (pcm_channels[dev] > 0) {
if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
goto _err;
}
- if ((err = snd_gusmax_mixer(cs4231)) < 0)
+ err = snd_gusmax_mixer(wss);
+ if (err < 0)
goto _err;
- if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
+ err = snd_gf1_rawmidi_new(gus, 0, NULL);
+ if (err < 0)
goto _err;
sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %i, dma %i", gus->gf1.port, xirq, xdma1);
if (xdma2 >= 0)
sprintf(card->longname + strlen(card->longname), "&%i", xdma2);
- snd_card_set_dev(card, &pdev->dev);
-
- if ((err = snd_card_register(card)) < 0)
+ err = snd_card_register(card);
+ if (err < 0)
goto _err;
maxcard->gus = gus;
- maxcard->cs4231 = cs4231;
+ maxcard->wss = wss;
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(pdev, card);
return 0;
_err:
@@ -348,70 +352,32 @@ static int __init snd_gusmax_probe(struct platform_device *pdev)
return err;
}
-static int snd_gusmax_remove(struct platform_device *devptr)
+static int snd_gusmax_remove(struct device *devptr, unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
return 0;
}
-#define GUSMAX_DRIVER "snd_gusmax"
+#define DEV_NAME "gusmax"
-static struct platform_driver snd_gusmax_driver = {
+static struct isa_driver snd_gusmax_driver = {
+ .match = snd_gusmax_match,
.probe = snd_gusmax_probe,
.remove = snd_gusmax_remove,
/* FIXME: suspend/resume */
.driver = {
- .name = GUSMAX_DRIVER
+ .name = DEV_NAME
},
};
-static void __init_or_module snd_gusmax_unregister_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_gusmax_driver);
-}
-
static int __init alsa_card_gusmax_init(void)
{
- int i, cards, err;
-
- err = platform_driver_register(&snd_gusmax_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(GUSMAX_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
- }
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR "GUS MAX soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_gusmax_unregister_all();
- return err;
+ return isa_register_driver(&snd_gusmax_driver, SNDRV_CARDS);
}
static void __exit alsa_card_gusmax_exit(void)
{
- snd_gusmax_unregister_all();
+ isa_unregister_driver(&snd_gusmax_driver);
}
module_init(alsa_card_gusmax_init)
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 9838d992b10..ad55e5cb8e9 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -1,6 +1,6 @@
/*
* Driver for AMD InterWave soundcard
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -22,18 +22,16 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/gus.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#ifdef SNDRV_STB
#include <sound/tea6330t.h>
#endif
@@ -41,7 +39,7 @@
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
#ifndef SNDRV_STB
MODULE_DESCRIPTION("AMD InterWave");
@@ -57,9 +55,9 @@ MODULE_SUPPORTED_DEVICE("{{AMD,InterWave STB with TEA6330T}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
#ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#endif
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x210,0x220,0x230,0x240,0x250,0x260 */
#ifdef SNDRV_STB
@@ -70,9 +68,9 @@ static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
/* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
-static int midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int midi[SNDRV_CARDS];
static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
-static int effect[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int effect[SNDRV_CARDS];
#ifdef SNDRV_STB
#define PFX "interwave-stb: "
@@ -115,14 +113,11 @@ MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for InterWave driver.");
module_param_array(effect, int, NULL, 0444);
MODULE_PARM_DESC(effect, "Effects enable for InterWave driver.");
-static struct platform_device *platform_devices[SNDRV_CARDS];
-static int pnp_registered;
-
struct snd_interwave {
int irq;
struct snd_card *card;
struct snd_gus_card *gus;
- struct snd_cs4231 *cs4231;
+ struct snd_wss *wss;
#ifdef SNDRV_STB
struct resource *i2c_res;
#endif
@@ -138,6 +133,8 @@ struct snd_interwave {
#ifdef CONFIG_PNP
+static int isa_registered;
+static int pnp_registered;
static struct pnp_card_device_id snd_interwave_pnpids[] = {
#ifndef SNDRV_STB
@@ -172,7 +169,7 @@ static void snd_interwave_i2c_setlines(struct snd_i2c_bus *bus, int ctrl, int da
unsigned long port = bus->private_value;
#if 0
- printk("i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
+ printk(KERN_DEBUG "i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
#endif
outb((data << 1) | ctrl, port);
udelay(10);
@@ -185,7 +182,7 @@ static int snd_interwave_i2c_getclockline(struct snd_i2c_bus *bus)
res = inb(port) & 1;
#if 0
- printk("i2c_getclockline - 0x%lx -> %i\n", port, res);
+ printk(KERN_DEBUG "i2c_getclockline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -199,7 +196,7 @@ static int snd_interwave_i2c_getdataline(struct snd_i2c_bus *bus, int ack)
udelay(10);
res = (inb(port) & 2) >> 1;
#if 0
- printk("i2c_getdataline - 0x%lx -> %i\n", port, res);
+ printk(KERN_DEBUG "i2c_getdataline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -210,9 +207,9 @@ static struct snd_i2c_bit_ops snd_interwave_i2c_bit_ops = {
.getdata = snd_interwave_i2c_getdataline,
};
-static int __devinit snd_interwave_detect_stb(struct snd_interwave *iwcard,
- struct snd_gus_card * gus, int dev,
- struct snd_i2c_bus **rbus)
+static int snd_interwave_detect_stb(struct snd_interwave *iwcard,
+ struct snd_gus_card *gus, int dev,
+ struct snd_i2c_bus **rbus)
{
unsigned long port;
struct snd_i2c_bus *bus;
@@ -252,11 +249,11 @@ static int __devinit snd_interwave_detect_stb(struct snd_interwave *iwcard,
}
#endif
-static int __devinit snd_interwave_detect(struct snd_interwave *iwcard,
- struct snd_gus_card * gus,
- int dev
+static int snd_interwave_detect(struct snd_interwave *iwcard,
+ struct snd_gus_card *gus,
+ int dev
#ifdef SNDRV_STB
- , struct snd_i2c_bus **rbus
+ , struct snd_i2c_bus **rbus
#endif
)
{
@@ -299,9 +296,9 @@ static int __devinit snd_interwave_detect(struct snd_interwave *iwcard,
return -ENODEV;
}
-static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id)
{
- struct snd_interwave *iwcard = (struct snd_interwave *) dev_id;
+ struct snd_interwave *iwcard = dev_id;
int loop, max = 5;
int handled = 0;
@@ -309,19 +306,19 @@ static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs
loop = 0;
if (inb(iwcard->gus_status_reg)) {
handled = 1;
- snd_gus_interrupt(irq, iwcard->gus, regs);
+ snd_gus_interrupt(irq, iwcard->gus);
loop++;
}
if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
handled = 1;
- snd_cs4231_interrupt(irq, iwcard->cs4231, regs);
+ snd_wss_interrupt(irq, iwcard->wss);
loop++;
}
} while (loop && --max > 0);
return IRQ_RETVAL(handled);
}
-static void __devinit snd_interwave_reset(struct snd_gus_card * gus)
+static void snd_interwave_reset(struct snd_gus_card *gus)
{
snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x00);
udelay(160);
@@ -329,7 +326,7 @@ static void __devinit snd_interwave_reset(struct snd_gus_card * gus)
udelay(160);
}
-static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *sizes)
+static void snd_interwave_bank_sizes(struct snd_gus_card *gus, int *sizes)
{
unsigned int idx;
unsigned int local;
@@ -344,7 +341,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
snd_gf1_poke(gus, local, d);
snd_gf1_poke(gus, local + 1, d + 1);
#if 0
- printk("d = 0x%x, local = 0x%x, local + 1 = 0x%x, idx << 22 = 0x%x\n",
+ printk(KERN_DEBUG "d = 0x%x, local = 0x%x, "
+ "local + 1 = 0x%x, idx << 22 = 0x%x\n",
d,
snd_gf1_peek(gus, local),
snd_gf1_peek(gus, local + 1),
@@ -358,7 +356,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
}
}
#if 0
- printk("sizes: %i %i %i %i\n", sizes[0], sizes[1], sizes[2], sizes[3]);
+ printk(KERN_DEBUG "sizes: %i %i %i %i\n",
+ sizes[0], sizes[1], sizes[2], sizes[3]);
#endif
}
@@ -378,7 +377,7 @@ struct rom_hdr {
/* 511 */ unsigned char csum;
};
-static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
+static void snd_interwave_detect_memory(struct snd_gus_card *gus)
{
static unsigned int lmc[13] =
{
@@ -412,12 +411,12 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
lmct = (psizes[3] << 24) | (psizes[2] << 16) |
(psizes[1] << 8) | psizes[0];
#if 0
- printk("lmct = 0x%08x\n", lmct);
+ printk(KERN_DEBUG "lmct = 0x%08x\n", lmct);
#endif
for (i = 0; i < ARRAY_SIZE(lmc); i++)
if (lmct == lmc[i]) {
#if 0
- printk("found !!! %i\n", i);
+ printk(KERN_DEBUG "found !!! %i\n", i);
#endif
snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i);
snd_interwave_bank_sizes(gus, psizes);
@@ -443,19 +442,11 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
for (bank_pos = 0; bank_pos < 16L * 1024L * 1024L; bank_pos += 4L * 1024L * 1024L) {
for (i = 0; i < 8; ++i)
iwave[i] = snd_gf1_peek(gus, bank_pos + i);
-#ifdef CONFIG_SND_DEBUG_ROM
- printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos,
- iwave[0], iwave[1], iwave[2], iwave[3],
- iwave[4], iwave[5], iwave[6], iwave[7]);
-#endif
if (strncmp(iwave, "INTRWAVE", 8))
continue; /* first check */
csum = 0;
for (i = 0; i < sizeof(struct rom_hdr); i++)
csum += snd_gf1_peek(gus, bank_pos + i);
-#ifdef CONFIG_SND_DEBUG_ROM
- printk(KERN_DEBUG "ROM checksum = 0x%x (computed)\n", csum);
-#endif
if (csum != 0)
continue; /* not valid rom */
gus->gf1.rom_banks++;
@@ -477,7 +468,7 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
snd_interwave_reset(gus);
}
-static void __devinit snd_interwave_init(int dev, struct snd_gus_card * gus)
+static void snd_interwave_init(int dev, struct snd_gus_card *gus)
{
unsigned long flags;
@@ -500,13 +491,17 @@ static void __devinit snd_interwave_init(int dev, struct snd_gus_card * gus)
}
static struct snd_kcontrol_new snd_interwave_controls[] = {
-CS4231_DOUBLE("Master Playback Switch", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Master Playback Volume", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
-CS4231_DOUBLE("Mic Playback Switch", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
-CS4231_DOUBLE("Mic Playback Volume", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
+WSS_DOUBLE("Master Playback Switch", 0,
+ CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Master Playback Volume", 0,
+ CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
+WSS_DOUBLE("Mic Playback Switch", 0,
+ CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("Mic Playback Volume", 0,
+ CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
};
-static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip)
+static int snd_interwave_mixer(struct snd_wss *chip)
{
struct snd_card *card = chip->card;
struct snd_ctl_elem_id id1, id2;
@@ -529,10 +524,10 @@ static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip)
for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++)
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0)
return err;
- snd_cs4231_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
- snd_cs4231_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
- snd_cs4231_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
- snd_cs4231_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
+ snd_wss_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
+ snd_wss_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
+ snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
+ snd_wss_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
/* reassign AUXA to SYNTHESIZER */
strcpy(id1.name, "Aux Playback Switch");
strcpy(id2.name, "Synth Playback Switch");
@@ -556,53 +551,32 @@ static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip)
#ifdef CONFIG_PNP
-static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
int err;
iwcard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (iwcard->dev == NULL) {
- kfree(cfg);
+ if (iwcard->dev == NULL)
return -EBUSY;
- }
+
#ifdef SNDRV_STB
iwcard->devtc = pnp_request_card_device(card, id->devs[1].id, NULL);
- if (iwcard->devtc == NULL) {
- kfree(cfg);
+ if (iwcard->devtc == NULL)
return -EBUSY;
- }
#endif
/* Synth & Codec initialization */
pdev = iwcard->dev;
- pnp_init_resource_table(cfg);
- if (port[dev] != SNDRV_AUTO_PORT) {
- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
- pnp_resource_change(&cfg->port_resource[1], port[dev] + 0x100, 12);
- pnp_resource_change(&cfg->port_resource[2], port[dev] + 0x10c, 4);
- }
- if (dma1[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
- if (dma2[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
- if (dma2[dev] < 0)
- pnp_resource_change(&cfg->dma_resource[1], 4, 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR "InterWave - Synth - the requested resources are invalid, using auto config\n");
+
err = pnp_activate_dev(pdev);
if (err < 0) {
- kfree(cfg);
snd_printk(KERN_ERR "InterWave PnP configure failure (out of resources?)\n");
return err;
}
if (pnp_port_start(pdev, 0) + 0x100 != pnp_port_start(pdev, 1) ||
pnp_port_start(pdev, 0) + 0x10c != pnp_port_start(pdev, 2)) {
- kfree(cfg);
snd_printk(KERN_ERR "PnP configure failure (wrong ports)\n");
return -ENOENT;
}
@@ -611,29 +585,23 @@ static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
if (dma2[dev] >= 0)
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("isapnp IW: sb port=0x%lx, gf1 port=0x%lx, codec port=0x%lx\n",
- pnp_port_start(pdev, 0),
- pnp_port_start(pdev, 1),
- pnp_port_start(pdev, 2));
+ snd_printdd("isapnp IW: sb port=0x%llx, gf1 port=0x%llx, codec port=0x%llx\n",
+ (unsigned long long)pnp_port_start(pdev, 0),
+ (unsigned long long)pnp_port_start(pdev, 1),
+ (unsigned long long)pnp_port_start(pdev, 2));
snd_printdd("isapnp IW: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
#ifdef SNDRV_STB
/* Tone Control initialization */
pdev = iwcard->devtc;
- pnp_init_resource_table(cfg);
- if (port_tc[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port_tc[dev], 1);
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR "InterWave - ToneControl - the requested resources are invalid, using auto config\n");
+
err = pnp_activate_dev(pdev);
if (err < 0) {
- kfree(cfg);
snd_printk(KERN_ERR "InterWave ToneControl PnP configure failure (out of resources?)\n");
return err;
}
port_tc[dev] = pnp_port_start(pdev, 0);
snd_printdd("isapnp IW: tone control port=0x%lx\n", port_tc[dev]);
#endif
- kfree(cfg);
return 0;
}
#endif /* CONFIG_PNP */
@@ -651,27 +619,30 @@ static void snd_interwave_free(struct snd_card *card)
free_irq(iwcard->irq, (void *)iwcard);
}
-static struct snd_card *snd_interwave_card_new(int dev)
+static int snd_interwave_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
struct snd_interwave *iwcard;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_interwave));
- if (card == NULL)
- return NULL;
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_interwave), &card);
+ if (err < 0)
+ return err;
iwcard = card->private_data;
iwcard->card = card;
iwcard->irq = -1;
card->private_free = snd_interwave_free;
- return card;
+ *cardp = card;
+ return 0;
}
-static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
+static int snd_interwave_probe(struct snd_card *card, int dev)
{
int xirq, xdma1, xdma2;
struct snd_interwave *iwcard = card->private_data;
- struct snd_cs4231 *cs4231;
+ struct snd_wss *wss;
struct snd_gus_card *gus;
#ifdef SNDRV_STB
struct snd_i2c_bus *i2c_bus;
@@ -706,40 +677,46 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
if ((err = snd_gus_initialize(gus)) < 0)
return err;
- if (request_irq(xirq, snd_interwave_interrupt, SA_INTERRUPT,
+ if (request_irq(xirq, snd_interwave_interrupt, 0,
"InterWave", iwcard)) {
snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq);
return -EBUSY;
}
iwcard->irq = xirq;
- if ((err = snd_cs4231_create(card,
- gus->gf1.port + 0x10c, -1, xirq,
- xdma2 < 0 ? xdma1 : xdma2, xdma1,
- CS4231_HW_INTERWAVE,
- CS4231_HWSHARE_IRQ |
- CS4231_HWSHARE_DMA1 |
- CS4231_HWSHARE_DMA2,
- &cs4231)) < 0)
+ err = snd_wss_create(card,
+ gus->gf1.port + 0x10c, -1, xirq,
+ xdma2 < 0 ? xdma1 : xdma2, xdma1,
+ WSS_HW_INTERWAVE,
+ WSS_HWSHARE_IRQ |
+ WSS_HWSHARE_DMA1 |
+ WSS_HWSHARE_DMA2,
+ &wss);
+ if (err < 0)
return err;
- if ((err = snd_cs4231_pcm(cs4231, 0, &pcm)) < 0)
+ err = snd_wss_pcm(wss, 0, &pcm);
+ if (err < 0)
return err;
sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
strcat(pcm->name, " (codec)");
- if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0)
+ err = snd_wss_timer(wss, 2, NULL);
+ if (err < 0)
return err;
- if ((err = snd_cs4231_mixer(cs4231)) < 0)
+ err = snd_wss_mixer(wss);
+ if (err < 0)
return err;
if (pcm_channels[dev] > 0) {
- if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+ err = snd_gf1_pcm_new(gus, 1, 1, NULL);
+ if (err < 0)
return err;
}
- if ((err = snd_interwave_mixer(cs4231)) < 0)
+ err = snd_interwave_mixer(wss);
+ if (err < 0)
return err;
#ifdef SNDRV_STB
@@ -783,35 +760,47 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
if (xdma2 >= 0)
sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
- if ((err = snd_card_register(card)) < 0)
+ err = snd_card_register(card);
+ if (err < 0)
return err;
- iwcard->cs4231 = cs4231;
+ iwcard->wss = wss;
iwcard->gus = gus;
return 0;
}
-static int __init snd_interwave_nonpnp_probe1(int dev, struct platform_device *devptr)
+static int snd_interwave_isa_probe1(int dev, struct device *devptr)
{
struct snd_card *card;
int err;
- card = snd_interwave_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_interwave_card_new(devptr, dev, &card);
+ if (err < 0)
+ return err;
- snd_card_set_dev(card, &devptr->dev);
if ((err = snd_interwave_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
}
- platform_set_drvdata(devptr, card);
+ dev_set_drvdata(devptr, card);
return 0;
}
-static int __init snd_interwave_nonpnp_probe(struct platform_device *pdev)
+static int snd_interwave_isa_match(struct device *pdev,
+ unsigned int dev)
+{
+ if (!enable[dev])
+ return 0;
+#ifdef CONFIG_PNP
+ if (isapnp[dev])
+ return 0;
+#endif
+ return 1;
+}
+
+static int snd_interwave_isa_probe(struct device *pdev,
+ unsigned int dev)
{
- int dev = pdev->id;
int err;
static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
static int possible_dmas[] = {0, 1, 3, 5, 6, 7, -1};
@@ -836,13 +825,13 @@ static int __init snd_interwave_nonpnp_probe(struct platform_device *pdev)
}
if (port[dev] != SNDRV_AUTO_PORT)
- return snd_interwave_nonpnp_probe1(dev, pdev);
+ return snd_interwave_isa_probe1(dev, pdev);
else {
static long possible_ports[] = {0x210, 0x220, 0x230, 0x240, 0x250, 0x260};
int i;
for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
port[dev] = possible_ports[i];
- err = snd_interwave_nonpnp_probe1(dev, pdev);
+ err = snd_interwave_isa_probe1(dev, pdev);
if (! err)
return 0;
}
@@ -850,16 +839,16 @@ static int __init snd_interwave_nonpnp_probe(struct platform_device *pdev)
}
}
-static int __devexit snd_interwave_nonpnp_remove(struct platform_device *devptr)
+static int snd_interwave_isa_remove(struct device *devptr, unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
return 0;
}
-static struct platform_driver snd_interwave_driver = {
- .probe = snd_interwave_nonpnp_probe,
- .remove = __devexit_p(snd_interwave_nonpnp_remove),
+static struct isa_driver snd_interwave_driver = {
+ .match = snd_interwave_isa_match,
+ .probe = snd_interwave_isa_probe,
+ .remove = snd_interwave_isa_remove,
/* FIXME: suspend,resume */
.driver = {
.name = INTERWAVE_DRIVER
@@ -867,9 +856,8 @@ static struct platform_driver snd_interwave_driver = {
};
#ifdef CONFIG_PNP
-
-static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_interwave_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
static int dev;
struct snd_card *card;
@@ -882,15 +870,14 @@ static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_interwave_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_interwave_card_new(&pcard->card->dev, dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_interwave_pnp(dev, card->private_data, pcard, pid)) < 0) {
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_interwave_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
@@ -900,7 +887,7 @@ static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
return 0;
}
-static void __devexit snd_interwave_pnp_remove(struct pnp_card_link * pcard)
+static void snd_interwave_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -911,70 +898,39 @@ static struct pnp_card_driver interwave_pnpc_driver = {
.name = INTERWAVE_PNP_DRIVER,
.id_table = snd_interwave_pnpids,
.probe = snd_interwave_pnp_detect,
- .remove = __devexit_p(snd_interwave_pnp_remove),
+ .remove = snd_interwave_pnp_remove,
/* FIXME: suspend,resume */
};
#endif /* CONFIG_PNP */
-static void __init_or_module snd_interwave_unregister_all(void)
-{
- int i;
-
- if (pnp_registered)
- pnp_unregister_card_driver(&interwave_pnpc_driver);
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&snd_interwave_driver);
-}
-
static int __init alsa_card_interwave_init(void)
{
- int i, err, cards = 0;
-
- if ((err = platform_driver_register(&snd_interwave_driver)) < 0)
- return err;
+ int err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
+ err = isa_register_driver(&snd_interwave_driver, SNDRV_CARDS);
#ifdef CONFIG_PNP
- if (isapnp[i])
- continue;
-#endif
- device = platform_device_register_simple(INTERWAVE_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- cards++;
- }
+ if (!err)
+ isa_registered = 1;
- /* ISA PnP cards */
- i = pnp_register_card_driver(&interwave_pnpc_driver);
- if (i >= 0) {
+ err = pnp_register_card_driver(&interwave_pnpc_driver);
+ if (!err)
pnp_registered = 1;
- cards += i;
- }
- if (!cards) {
-#ifdef MODULE
- printk(KERN_ERR "InterWave soundcard not found or device busy\n");
+ if (isa_registered)
+ err = 0;
#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_interwave_unregister_all();
return err;
}
static void __exit alsa_card_interwave_exit(void)
{
- snd_interwave_unregister_all();
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&interwave_pnpc_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_interwave_driver);
}
module_init(alsa_card_interwave_init)
diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile
new file mode 100644
index 00000000000..2171c0aa2f6
--- /dev/null
+++ b/sound/isa/msnd/Makefile
@@ -0,0 +1,9 @@
+
+snd-msnd-lib-objs := msnd.o msnd_midi.o msnd_pinnacle_mixer.o
+snd-msnd-pinnacle-objs := msnd_pinnacle.o
+snd-msnd-classic-objs := msnd_classic.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_MSND_PINNACLE) += snd-msnd-pinnacle.o snd-msnd-lib.o
+obj-$(CONFIG_SND_MSND_CLASSIC) += snd-msnd-classic.o snd-msnd-lib.o
+
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
new file mode 100644
index 00000000000..1cee18fb28a
--- /dev/null
+++ b/sound/isa/msnd/msnd.c
@@ -0,0 +1,708 @@
+/*********************************************************************
+ *
+ * 2002/06/30 Karsten Wiese:
+ * removed kernel-version dependencies.
+ * ripped from linux kernel 2.4.18 (OSS Implementation) by me.
+ * In the OSS Version, this file is compiled to a separate MODULE,
+ * that is used by the pinnacle and the classic driver.
+ * since there is no classic driver for alsa yet (i dont have a classic
+ * & writing one blindfold is difficult) this file's object is statically
+ * linked into the pinnacle-driver-module for now. look for the string
+ * "uncomment this to make this a module again"
+ * to do guess what.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * msnd.c - Driver Base
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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.
+ *
+ ********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "msnd.h"
+
+#define LOGNAME "msnd"
+
+
+void snd_msnd_init_queue(void *base, int start, int size)
+{
+ writew(PCTODSP_BASED(start), base + JQS_wStart);
+ writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+ writew(0, base + JQS_wHead);
+ writew(0, base + JQS_wTail);
+}
+EXPORT_SYMBOL(snd_msnd_init_queue);
+
+static int snd_msnd_wait_TXDE(struct snd_msnd *dev)
+{
+ unsigned int io = dev->io;
+ int timeout = 1000;
+
+ while (timeout-- > 0)
+ if (inb(io + HP_ISR) & HPISR_TXDE)
+ return 0;
+
+ return -EIO;
+}
+
+static int snd_msnd_wait_HC0(struct snd_msnd *dev)
+{
+ unsigned int io = dev->io;
+ int timeout = 1000;
+
+ while (timeout-- > 0)
+ if (!(inb(io + HP_CVR) & HPCVR_HC))
+ return 0;
+
+ return -EIO;
+}
+
+int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_HC0(dev) == 0) {
+ outb(cmd, dev->io + HP_CVR);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
+
+int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
+ unsigned char mid, unsigned char low)
+{
+ unsigned int io = dev->io;
+
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(high, io + HP_TXH);
+ outb(mid, io + HP_TXM);
+ outb(low, io + HP_TXL);
+ return 0;
+ }
+
+ snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_word);
+
+int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
+{
+ int i;
+
+ if (len % 3 != 0) {
+ snd_printk(KERN_ERR LOGNAME
+ ": Upload host data not multiple of 3!\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i += 3)
+ if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
+ return -EIO;
+
+ inb(dev->io + HP_RXL);
+ inb(dev->io + HP_CVR);
+
+ return 0;
+}
+EXPORT_SYMBOL(snd_msnd_upload_host);
+
+int snd_msnd_enable_irq(struct snd_msnd *dev)
+{
+ unsigned long flags;
+
+ if (dev->irq_ref++)
+ return 0;
+
+ snd_printdd(LOGNAME ": Enabling IRQ\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+ if (dev->type == msndClassic)
+ outb(dev->irqid, dev->io + HP_IRQM);
+
+ outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+ outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+ enable_irq(dev->irq);
+ snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
+ dev->dspq_buff_size);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_enable_irq);
+
+int snd_msnd_disable_irq(struct snd_msnd *dev)
+{
+ unsigned long flags;
+
+ if (--dev->irq_ref > 0)
+ return 0;
+
+ if (dev->irq_ref < 0)
+ snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
+ dev->irq_ref);
+
+ snd_printdd(LOGNAME ": Disabling IRQ\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+ if (dev->type == msndClassic)
+ outb(HPIRQ_NONE, dev->io + HP_IRQM);
+ disable_irq(dev->irq);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_disable_irq);
+
+static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
+{
+ long tmp = (size * HZ * chip->play_sample_size) / 8;
+ return tmp / (chip->play_sample_rate * chip->play_channels);
+}
+
+static void snd_msnd_dsp_write_flush(struct snd_msnd *chip)
+{
+ if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
+ return;
+ set_bit(F_WRITEFLUSH, &chip->flags);
+/* interruptible_sleep_on_timeout(
+ &chip->writeflush,
+ get_play_delay_jiffies(&chip, chip->DAPF.len));*/
+ clear_bit(F_WRITEFLUSH, &chip->flags);
+ if (!signal_pending(current))
+ schedule_timeout_interruptible(
+ get_play_delay_jiffies(chip, chip->play_period_bytes));
+ clear_bit(F_WRITING, &chip->flags);
+}
+
+void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
+{
+ if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
+ clear_bit(F_READING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ snd_printd(KERN_INFO LOGNAME
+ ": Stopping read for %p\n", file);
+ chip->mode &= ~FMODE_READ;
+ }
+ clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ }
+ if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
+ if (test_bit(F_WRITING, &chip->flags)) {
+ snd_msnd_dsp_write_flush(chip);
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+ }
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ snd_printd(KERN_INFO
+ LOGNAME ": Stopping write for %p\n", file);
+ chip->mode &= ~FMODE_WRITE;
+ }
+ clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ }
+}
+EXPORT_SYMBOL(snd_msnd_dsp_halt);
+
+
+int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
+{
+ int /*size, n,*/ timeout = 3;
+ u16 wTmp;
+ /* void *DAQD; */
+
+ /* Increment the tail and check for queue wrap */
+ wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+ if (wTmp > readw(chip->DARQ + JQS_wSize))
+ wTmp = 0;
+ while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
+ udelay(1);
+
+ if (chip->capturePeriods == 2) {
+ void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
+ bank * DAQDS__size + DAQDS_wStart;
+ unsigned short offset = 0x3000 + chip->capturePeriodBytes;
+
+ if (readw(pDAQ) != PCTODSP_BASED(0x3000))
+ offset = 0x3000;
+ writew(PCTODSP_BASED(offset), pDAQ);
+ }
+
+ writew(wTmp, chip->DARQ + JQS_wTail);
+
+#if 0
+ /* Get our digital audio queue struct */
+ DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
+
+ /* Get length of data */
+ size = readw(DAQD + DAQDS_wSize);
+
+ /* Read data from the head (unprotected bank 1 access okay
+ since this is only called inside an interrupt) */
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ n = msnd_fifo_write(&chip->DARF,
+ (char *)(chip->base + bank * DAR_BUFF_SIZE),
+ size, 0);
+ if (n <= 0) {
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ return n;
+ }
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+#endif
+
+ return 1;
+}
+EXPORT_SYMBOL(snd_msnd_DARQ);
+
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
+{
+ u16 DAPQ_tail;
+ int protect = start, nbanks = 0;
+ void *DAQD;
+ static int play_banks_submitted;
+ /* unsigned long flags;
+ spin_lock_irqsave(&chip->lock, flags); not necessary */
+
+ DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
+ while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) {
+ int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
+
+ if (start) {
+ start = 0;
+ play_banks_submitted = 0;
+ }
+
+ /* Get our digital audio queue struct */
+ DAQD = bank_num * DAQDS__size + chip->mappedbase +
+ DAPQ_DATA_BUFF;
+
+ /* Write size of this bank */
+ writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
+ if (play_banks_submitted < 3)
+ ++play_banks_submitted;
+ else if (chip->playPeriods == 2) {
+ unsigned short offset = chip->play_period_bytes;
+
+ if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
+ offset = 0;
+
+ writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
+ }
+ ++nbanks;
+
+ /* Then advance the tail */
+ /*
+ if (protect)
+ snd_printd(KERN_INFO "B %X %lX\n",
+ bank_num, xtime.tv_usec);
+ */
+
+ DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
+ writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
+ /* Tell the DSP to play the bank */
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
+ if (protect)
+ if (2 == bank_num)
+ break;
+ }
+ /*
+ if (protect)
+ snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
+ */
+ /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
+ return nbanks;
+}
+EXPORT_SYMBOL(snd_msnd_DAPQ);
+
+static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+ chip->last_playbank = -1;
+ chip->playLimit = pcm_count * (pcm_periods - 1);
+ chip->playPeriods = pcm_periods;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
+
+ chip->play_period_bytes = pcm_count;
+
+ for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+ writew(PCTODSP_BASED((u32)(pcm_count * n)),
+ pDAQ + DAQDS_wStart);
+ writew(0, pDAQ + DAQDS_wSize);
+ writew(1, pDAQ + DAQDS_wFormat);
+ writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+ writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+ writew(n, pDAQ + DAQDS_wFlags);
+ }
+}
+
+static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ void *pDAQ;
+ /* unsigned long flags; */
+
+ /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
+
+ chip->last_recbank = 2;
+ chip->captureLimit = pcm_count * (pcm_periods - 1);
+ chip->capturePeriods = pcm_periods;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
+ writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
+ chip->DARQ + JQS_wTail);
+
+#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);
+#endif
+
+ chip->capturePeriodBytes = pcm_count;
+ snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
+
+ pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+ for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+ u32 tmp = pcm_count * n;
+
+ writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
+ writew(pcm_count, pDAQ + DAQDS_wSize);
+ writew(1, pDAQ + DAQDS_wFormat);
+ writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
+ writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+ writew(n, pDAQ + DAQDS_wFlags);
+ }
+}
+
+static struct snd_pcm_hardware snd_msnd_playback = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 0x3000,
+ .period_bytes_min = 0x40,
+ .period_bytes_max = 0x1800,
+ .periods_min = 2,
+ .periods_max = 3,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware snd_msnd_capture = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 0x3000,
+ .period_bytes_min = 0x40,
+ .period_bytes_max = 0x1800,
+ .periods_min = 2,
+ .periods_max = 3,
+ .fifo_size = 0,
+};
+
+
+static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_enable_irq(chip);
+
+ runtime->dma_area = chip->mappedbase;
+ runtime->dma_bytes = 0x3000;
+
+ chip->playback_substream = substream;
+ runtime->hw = snd_msnd_playback;
+ return 0;
+}
+
+static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ snd_msnd_disable_irq(chip);
+ clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ return 0;
+}
+
+
+static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int i;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+ chip->play_sample_size = snd_pcm_format_width(params_format(params));
+ chip->play_channels = params_channels(params);
+ chip->play_sample_rate = params_rate(params);
+
+ for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+ writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+ }
+ /* dont do this here:
+ * snd_msnd_calibrate_adc(chip->play_sample_rate);
+ */
+
+ return 0;
+}
+
+static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+ unsigned int pcm_periods = pcm_size / pcm_count;
+
+ snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
+ chip->playDMAPos = 0;
+ return 0;
+}
+
+static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ int result = 0;
+
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ snd_printdd("snd_msnd_playback_trigger(START)\n");
+ chip->banksPlayed = 0;
+ set_bit(F_WRITING, &chip->flags);
+ snd_msnd_DAPQ(chip, 1);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ snd_printdd("snd_msnd_playback_trigger(STop)\n");
+ /* interrupt diagnostic, comment this out later */
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+ } else {
+ snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
+ result = -EINVAL;
+ }
+
+ snd_printdd("snd_msnd_playback_trigger() ENDE\n");
+ return result;
+}
+
+static snd_pcm_uframes_t
+snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ return bytes_to_frames(substream->runtime, chip->playDMAPos);
+}
+
+
+static struct snd_pcm_ops snd_msnd_playback_ops = {
+ .open = snd_msnd_playback_open,
+ .close = snd_msnd_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_msnd_playback_hw_params,
+ .prepare = snd_msnd_playback_prepare,
+ .trigger = snd_msnd_playback_trigger,
+ .pointer = snd_msnd_playback_pointer,
+};
+
+static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ set_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ snd_msnd_enable_irq(chip);
+ runtime->dma_area = chip->mappedbase + 0x3000;
+ runtime->dma_bytes = 0x3000;
+ memset(runtime->dma_area, 0, runtime->dma_bytes);
+ chip->capture_substream = substream;
+ runtime->hw = snd_msnd_capture;
+ return 0;
+}
+
+static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ snd_msnd_disable_irq(chip);
+ clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ return 0;
+}
+
+static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+ unsigned int pcm_periods = pcm_size / pcm_count;
+
+ snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
+ chip->captureDMAPos = 0;
+ return 0;
+}
+
+static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ chip->last_recbank = -1;
+ set_bit(F_READING, &chip->flags);
+ if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
+ return 0;
+
+ clear_bit(F_READING, &chip->flags);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ clear_bit(F_READING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static snd_pcm_uframes_t
+snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ return bytes_to_frames(runtime, chip->captureDMAPos);
+}
+
+
+static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int i;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+ chip->capture_sample_size = snd_pcm_format_width(params_format(params));
+ chip->capture_channels = params_channels(params);
+ chip->capture_sample_rate = params_rate(params);
+
+ for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+ writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
+ }
+ return 0;
+}
+
+
+static struct snd_pcm_ops snd_msnd_capture_ops = {
+ .open = snd_msnd_capture_open,
+ .close = snd_msnd_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_msnd_capture_hw_params,
+ .prepare = snd_msnd_capture_prepare,
+ .trigger = snd_msnd_capture_trigger,
+ .pointer = snd_msnd_capture_pointer,
+};
+
+
+int snd_msnd_pcm(struct snd_card *card, int device,
+ struct snd_pcm **rpcm)
+{
+ struct snd_msnd *chip = card->private_data;
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
+
+ pcm->private_data = chip;
+ strcpy(pcm->name, "Hurricane");
+
+
+ if (rpcm)
+ *rpcm = pcm;
+ return 0;
+}
+EXPORT_SYMBOL(snd_msnd_pcm);
+
+MODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
new file mode 100644
index 00000000000..dbac3a42347
--- /dev/null
+++ b/sound/isa/msnd/msnd.h
@@ -0,0 +1,308 @@
+/*********************************************************************
+ *
+ * msnd.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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.
+ *
+ ********************************************************************/
+#ifndef __MSND_H
+#define __MSND_H
+
+#define DEFSAMPLERATE 44100
+#define DEFSAMPLESIZE SNDRV_PCM_FORMAT_S16
+#define DEFCHANNELS 1
+
+#define SRAM_BANK_SIZE 0x8000
+#define SRAM_CNTL_START 0x7F00
+#define SMA_STRUCT_START 0x7F40
+
+#define DSP_BASE_ADDR 0x4000
+#define DSP_BANK_BASE 0x4000
+
+#define AGND 0x01
+#define SIGNAL 0x02
+
+#define EXT_DSP_BIT_DCAL 0x0001
+#define EXT_DSP_BIT_MIDI_CON 0x0002
+
+#define BUFFSIZE 0x8000
+#define HOSTQ_SIZE 0x40
+
+#define DAP_BUFF_SIZE 0x2400
+
+#define DAPQ_STRUCT_SIZE 0x10
+#define DARQ_STRUCT_SIZE 0x10
+#define DAPQ_BUFF_SIZE (3 * 0x10)
+#define DARQ_BUFF_SIZE (3 * 0x10)
+#define MODQ_BUFF_SIZE 0x400
+
+#define DAPQ_DATA_BUFF 0x6C00
+#define DARQ_DATA_BUFF 0x6C30
+#define MODQ_DATA_BUFF 0x6C60
+#define MIDQ_DATA_BUFF 0x7060
+
+#define DAPQ_OFFSET SRAM_CNTL_START
+#define DARQ_OFFSET (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
+
+#define HP_ICR 0x00
+#define HP_CVR 0x01
+#define HP_ISR 0x02
+#define HP_IVR 0x03
+#define HP_NU 0x04
+#define HP_INFO 0x04
+#define HP_TXH 0x05
+#define HP_RXH 0x05
+#define HP_TXM 0x06
+#define HP_RXM 0x06
+#define HP_TXL 0x07
+#define HP_RXL 0x07
+
+#define HP_ICR_DEF 0x00
+#define HP_CVR_DEF 0x12
+#define HP_ISR_DEF 0x06
+#define HP_IVR_DEF 0x0f
+#define HP_NU_DEF 0x00
+
+#define HP_IRQM 0x09
+
+#define HPR_BLRC 0x08
+#define HPR_SPR1 0x09
+#define HPR_SPR2 0x0A
+#define HPR_TCL0 0x0B
+#define HPR_TCL1 0x0C
+#define HPR_TCL2 0x0D
+#define HPR_TCL3 0x0E
+#define HPR_TCL4 0x0F
+
+#define HPICR_INIT 0x80
+#define HPICR_HM1 0x40
+#define HPICR_HM0 0x20
+#define HPICR_HF1 0x10
+#define HPICR_HF0 0x08
+#define HPICR_TREQ 0x02
+#define HPICR_RREQ 0x01
+
+#define HPCVR_HC 0x80
+
+#define HPISR_HREQ 0x80
+#define HPISR_DMA 0x40
+#define HPISR_HF3 0x10
+#define HPISR_HF2 0x08
+#define HPISR_TRDY 0x04
+#define HPISR_TXDE 0x02
+#define HPISR_RXDF 0x01
+
+#define HPIO_290 0
+#define HPIO_260 1
+#define HPIO_250 2
+#define HPIO_240 3
+#define HPIO_230 4
+#define HPIO_220 5
+#define HPIO_210 6
+#define HPIO_3E0 7
+
+#define HPMEM_NONE 0
+#define HPMEM_B000 1
+#define HPMEM_C800 2
+#define HPMEM_D000 3
+#define HPMEM_D400 4
+#define HPMEM_D800 5
+#define HPMEM_E000 6
+#define HPMEM_E800 7
+
+#define HPIRQ_NONE 0
+#define HPIRQ_5 1
+#define HPIRQ_7 2
+#define HPIRQ_9 3
+#define HPIRQ_10 4
+#define HPIRQ_11 5
+#define HPIRQ_12 6
+#define HPIRQ_15 7
+
+#define HIMT_PLAY_DONE 0x00
+#define HIMT_RECORD_DONE 0x01
+#define HIMT_MIDI_EOS 0x02
+#define HIMT_MIDI_OUT 0x03
+
+#define HIMT_MIDI_IN_UCHAR 0x0E
+#define HIMT_DSP 0x0F
+
+#define HDEX_BASE 0x92
+#define HDEX_PLAY_START (0 + HDEX_BASE)
+#define HDEX_PLAY_STOP (1 + HDEX_BASE)
+#define HDEX_PLAY_PAUSE (2 + HDEX_BASE)
+#define HDEX_PLAY_RESUME (3 + HDEX_BASE)
+#define HDEX_RECORD_START (4 + HDEX_BASE)
+#define HDEX_RECORD_STOP (5 + HDEX_BASE)
+#define HDEX_MIDI_IN_START (6 + HDEX_BASE)
+#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE)
+#define HDEX_MIDI_OUT_START (8 + HDEX_BASE)
+#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE)
+#define HDEX_AUX_REQ (10 + HDEX_BASE)
+
+#define HDEXAR_CLEAR_PEAKS 1
+#define HDEXAR_IN_SET_POTS 2
+#define HDEXAR_AUX_SET_POTS 3
+#define HDEXAR_CAL_A_TO_D 4
+#define HDEXAR_RD_EXT_DSP_BITS 5
+
+/* Pinnacle only HDEXAR defs */
+#define HDEXAR_SET_ANA_IN 0
+#define HDEXAR_SET_SYNTH_IN 4
+#define HDEXAR_READ_DAT_IN 5
+#define HDEXAR_MIC_SET_POTS 6
+#define HDEXAR_SET_DAT_IN 7
+
+#define HDEXAR_SET_SYNTH_48 8
+#define HDEXAR_SET_SYNTH_44 9
+
+#define HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF))
+#define LOWORD(l) ((u16)(u32)(l))
+#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF))
+#define LOBYTE(w) ((u8)(w))
+#define MAKELONG(low, hi) ((long)(((u16)(low))|(((u32)((u16)(hi)))<<16)))
+#define MAKEWORD(low, hi) ((u16)(((u8)(low))|(((u16)((u8)(hi)))<<8)))
+
+#define PCTODSP_OFFSET(w) (u16)((w)/2)
+#define PCTODSP_BASED(w) (u16)(((w)/2) + DSP_BASE_ADDR)
+#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2)
+
+#ifdef SLOWIO
+# undef outb
+# undef inb
+# define outb outb_p
+# define inb inb_p
+#endif
+
+/* JobQueueStruct */
+#define JQS_wStart 0x00
+#define JQS_wSize 0x02
+#define JQS_wHead 0x04
+#define JQS_wTail 0x06
+#define JQS__size 0x08
+
+/* DAQueueDataStruct */
+#define DAQDS_wStart 0x00
+#define DAQDS_wSize 0x02
+#define DAQDS_wFormat 0x04
+#define DAQDS_wSampleSize 0x06
+#define DAQDS_wChannels 0x08
+#define DAQDS_wSampleRate 0x0A
+#define DAQDS_wIntMsg 0x0C
+#define DAQDS_wFlags 0x0E
+#define DAQDS__size 0x10
+
+#include <sound/pcm.h>
+
+struct snd_msnd {
+ void __iomem *mappedbase;
+ int play_period_bytes;
+ int playLimit;
+ int playPeriods;
+ int playDMAPos;
+ int banksPlayed;
+ int captureDMAPos;
+ int capturePeriodBytes;
+ int captureLimit;
+ int capturePeriods;
+ struct snd_card *card;
+ void *msndmidi_mpu;
+ struct snd_rawmidi *rmidi;
+
+ /* Hardware resources */
+ long io;
+ int memid, irqid;
+ int irq, irq_ref;
+ unsigned long base;
+
+ /* Motorola 56k DSP SMA */
+ void __iomem *SMA;
+ void __iomem *DAPQ;
+ void __iomem *DARQ;
+ void __iomem *MODQ;
+ void __iomem *MIDQ;
+ void __iomem *DSPQ;
+ int dspq_data_buff, dspq_buff_size;
+
+ /* State variables */
+ enum { msndClassic, msndPinnacle } type;
+ fmode_t mode;
+ unsigned long flags;
+#define F_RESETTING 0
+#define F_HAVEDIGITAL 1
+#define F_AUDIO_WRITE_INUSE 2
+#define F_WRITING 3
+#define F_WRITEBLOCK 4
+#define F_WRITEFLUSH 5
+#define F_AUDIO_READ_INUSE 6
+#define F_READING 7
+#define F_READBLOCK 8
+#define F_EXT_MIDI_INUSE 9
+#define F_HDR_MIDI_INUSE 10
+#define F_DISABLE_WRITE_NDELAY 11
+ spinlock_t lock;
+ spinlock_t mixer_lock;
+ int nresets;
+ unsigned recsrc;
+#define LEVEL_ENTRIES 32
+ int left_levels[LEVEL_ENTRIES];
+ int right_levels[LEVEL_ENTRIES];
+ int calibrate_signal;
+ int play_sample_size, play_sample_rate, play_channels;
+ int play_ndelay;
+ int capture_sample_size, capture_sample_rate, capture_channels;
+ int capture_ndelay;
+ u8 bCurrentMidiPatch;
+
+ int last_playbank, last_recbank;
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+};
+
+void snd_msnd_init_queue(void *base, int start, int size);
+
+int snd_msnd_send_dsp_cmd(struct snd_msnd *chip, u8 cmd);
+int snd_msnd_send_word(struct snd_msnd *chip,
+ unsigned char high,
+ unsigned char mid,
+ unsigned char low);
+int snd_msnd_upload_host(struct snd_msnd *chip,
+ const u8 *bin, int len);
+int snd_msnd_enable_irq(struct snd_msnd *chip);
+int snd_msnd_disable_irq(struct snd_msnd *chip);
+void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
+int snd_msnd_DARQ(struct snd_msnd *chip, int start);
+int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
+
+int snd_msndmidi_new(struct snd_card *card, int device);
+void snd_msndmidi_input_read(void *mpu);
+
+void snd_msndmix_setup(struct snd_msnd *chip);
+int snd_msndmix_new(struct snd_card *card);
+int snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc);
+#endif /* __MSND_H */
diff --git a/sound/isa/msnd/msnd_classic.c b/sound/isa/msnd/msnd_classic.c
new file mode 100644
index 00000000000..3b23a096fa4
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.c
@@ -0,0 +1,3 @@
+/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */
+#define MSND_CLASSIC
+#include "msnd_pinnacle.c"
diff --git a/sound/isa/msnd/msnd_classic.h b/sound/isa/msnd/msnd_classic.h
new file mode 100644
index 00000000000..f18d5fa5baf
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.h
@@ -0,0 +1,129 @@
+/*********************************************************************
+ *
+ * msnd_classic.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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.
+ *
+ ********************************************************************/
+#ifndef __MSND_CLASSIC_H
+#define __MSND_CLASSIC_H
+
+#define DSP_NUMIO 0x10
+
+#define HP_MEMM 0x08
+
+#define HP_BITM 0x0E
+#define HP_WAIT 0x0D
+#define HP_DSPR 0x0A
+#define HP_PROR 0x0B
+#define HP_BLKS 0x0C
+
+#define HPPRORESET_OFF 0
+#define HPPRORESET_ON 1
+
+#define HPDSPRESET_OFF 0
+#define HPDSPRESET_ON 1
+
+#define HPBLKSEL_0 0
+#define HPBLKSEL_1 1
+
+#define HPWAITSTATE_0 0
+#define HPWAITSTATE_1 1
+
+#define HPBITMODE_16 0
+#define HPBITMODE_8 1
+
+#define HIDSP_INT_PLAY_UNDER 0x00
+#define HIDSP_INT_RECORD_OVER 0x01
+#define HIDSP_INPUT_CLIPPING 0x02
+#define HIDSP_MIDI_IN_OVER 0x10
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x0040
+#define TIME_PRO_RESET 0x0032
+
+#define DAR_BUFF_SIZE 0x2000
+
+#define MIDQ_BUFF_SIZE 0x200
+#define DSPQ_BUFF_SIZE 0x40
+
+#define DSPQ_DATA_BUFF 0x7260
+
+#define MOP_SYNTH 0x10
+#define MOP_EXTOUT 0x32
+#define MOP_EXTTHRU 0x02
+#define MOP_OUTMASK 0x01
+
+#define MIP_EXTIN 0x01
+#define MIP_SYNTH 0x00
+#define MIP_INMASK 0x32
+
+/* Classic SMA Common Data */
+#define SMA_wCurrPlayBytes 0x0000
+#define SMA_wCurrRecordBytes 0x0002
+#define SMA_wCurrPlayVolLeft 0x0004
+#define SMA_wCurrPlayVolRight 0x0006
+#define SMA_wCurrInVolLeft 0x0008
+#define SMA_wCurrInVolRight 0x000a
+#define SMA_wUser_3 0x000c
+#define SMA_wUser_4 0x000e
+#define SMA_dwUser_5 0x0010
+#define SMA_dwUser_6 0x0014
+#define SMA_wUser_7 0x0018
+#define SMA_wReserved_A 0x001a
+#define SMA_wReserved_B 0x001c
+#define SMA_wReserved_C 0x001e
+#define SMA_wReserved_D 0x0020
+#define SMA_wReserved_E 0x0022
+#define SMA_wReserved_F 0x0024
+#define SMA_wReserved_G 0x0026
+#define SMA_wReserved_H 0x0028
+#define SMA_wCurrDSPStatusFlags 0x002a
+#define SMA_wCurrHostStatusFlags 0x002c
+#define SMA_wCurrInputTagBits 0x002e
+#define SMA_wCurrLeftPeak 0x0030
+#define SMA_wCurrRightPeak 0x0032
+#define SMA_wExtDSPbits 0x0034
+#define SMA_bExtHostbits 0x0036
+#define SMA_bBoardLevel 0x0037
+#define SMA_bInPotPosRight 0x0038
+#define SMA_bInPotPosLeft 0x0039
+#define SMA_bAuxPotPosRight 0x003a
+#define SMA_bAuxPotPosLeft 0x003b
+#define SMA_wCurrMastVolLeft 0x003c
+#define SMA_wCurrMastVolRight 0x003e
+#define SMA_bUser_12 0x0040
+#define SMA_bUser_13 0x0041
+#define SMA_wUser_14 0x0042
+#define SMA_wUser_15 0x0044
+#define SMA_wCalFreqAtoD 0x0046
+#define SMA_wUser_16 0x0048
+#define SMA_wUser_17 0x004a
+#define SMA__size 0x004c
+
+#define INITCODEFILE "turtlebeach/msndinit.bin"
+#define PERMCODEFILE "turtlebeach/msndperm.bin"
+#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)"
+
+#endif /* __MSND_CLASSIC_H */
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
new file mode 100644
index 00000000000..ffc67fd80c2
--- /dev/null
+++ b/sound/isa/msnd/msnd_midi.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * Copyright (c) 2009 by Krzysztof Helt
+ * Routines for control of MPU-401 in UART mode
+ *
+ * MPU-401 supports UART mode which is not capable generate transmit
+ * interrupts thus output is done via polling. Also, if irq < 0, then
+ * input is done also via polling. Do not expect good performance.
+ *
+ *
+ * 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 <linux/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "msnd.h"
+
+#define MSNDMIDI_MODE_BIT_INPUT 0
+#define MSNDMIDI_MODE_BIT_OUTPUT 1
+#define MSNDMIDI_MODE_BIT_INPUT_TRIGGER 2
+#define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER 3
+
+struct snd_msndmidi {
+ struct snd_msnd *dev;
+
+ unsigned long mode; /* MSNDMIDI_MODE_XXXX */
+
+ struct snd_rawmidi_substream *substream_input;
+
+ spinlock_t input_lock;
+};
+
+/*
+ * input/output open/close - protected by open_mutex in rawmidi.c
+ */
+static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_msndmidi *mpu;
+
+ snd_printdd("snd_msndmidi_input_open()\n");
+
+ mpu = substream->rmidi->private_data;
+
+ mpu->substream_input = substream;
+
+ snd_msnd_enable_irq(mpu->dev);
+
+ snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START);
+ set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+ return 0;
+}
+
+static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_msndmidi *mpu;
+
+ mpu = substream->rmidi->private_data;
+ snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP);
+ clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+ mpu->substream_input = NULL;
+ snd_msnd_disable_irq(mpu->dev);
+ return 0;
+}
+
+static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
+{
+ u16 tail;
+
+ tail = readw(mpu->dev->MIDQ + JQS_wTail);
+ writew(tail, mpu->dev->MIDQ + JQS_wHead);
+}
+
+/*
+ * trigger input
+ */
+static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ unsigned long flags;
+ struct snd_msndmidi *mpu;
+
+ snd_printdd("snd_msndmidi_input_trigger(, %i)\n", up);
+
+ mpu = substream->rmidi->private_data;
+ spin_lock_irqsave(&mpu->input_lock, flags);
+ if (up) {
+ if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
+ &mpu->mode))
+ snd_msndmidi_input_drop(mpu);
+ } else {
+ clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
+ }
+ spin_unlock_irqrestore(&mpu->input_lock, flags);
+ if (up)
+ snd_msndmidi_input_read(mpu);
+}
+
+void snd_msndmidi_input_read(void *mpuv)
+{
+ unsigned long flags;
+ struct snd_msndmidi *mpu = mpuv;
+ void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
+
+ spin_lock_irqsave(&mpu->input_lock, flags);
+ while (readw(mpu->dev->MIDQ + JQS_wTail) !=
+ readw(mpu->dev->MIDQ + JQS_wHead)) {
+ u16 wTmp, val;
+ val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
+
+ if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
+ &mpu->mode))
+ snd_rawmidi_receive(mpu->substream_input,
+ (unsigned char *)&val, 1);
+
+ wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
+ if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
+ writew(0, mpu->dev->MIDQ + JQS_wHead);
+ else
+ writew(wTmp, mpu->dev->MIDQ + JQS_wHead);
+ }
+ spin_unlock_irqrestore(&mpu->input_lock, flags);
+}
+EXPORT_SYMBOL(snd_msndmidi_input_read);
+
+static struct snd_rawmidi_ops snd_msndmidi_input = {
+ .open = snd_msndmidi_input_open,
+ .close = snd_msndmidi_input_close,
+ .trigger = snd_msndmidi_input_trigger,
+};
+
+static void snd_msndmidi_free(struct snd_rawmidi *rmidi)
+{
+ struct snd_msndmidi *mpu = rmidi->private_data;
+ kfree(mpu);
+}
+
+int snd_msndmidi_new(struct snd_card *card, int device)
+{
+ struct snd_msnd *chip = card->private_data;
+ struct snd_msndmidi *mpu;
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi);
+ if (err < 0)
+ return err;
+ mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
+ if (mpu == NULL) {
+ snd_device_free(card, rmidi);
+ return -ENOMEM;
+ }
+ mpu->dev = chip;
+ chip->msndmidi_mpu = mpu;
+ rmidi->private_data = mpu;
+ rmidi->private_free = snd_msndmidi_free;
+ spin_lock_init(&mpu->input_lock);
+ strcpy(rmidi->name, "MSND MIDI");
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_msndmidi_input);
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+ return 0;
+}
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
new file mode 100644
index 00000000000..5016bf957f5
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -0,0 +1,1243 @@
+/*********************************************************************
+ *
+ * Linux multisound pinnacle/fiji driver for ALSA.
+ *
+ * 2002/06/30 Karsten Wiese:
+ * for now this is only used to build a pinnacle / fiji driver.
+ * the OSS parent of this code is designed to also support
+ * the multisound classic via the file msnd_classic.c.
+ * to make it easier for some brave heart to implemt classic
+ * support in alsa, i left all the MSND_CLASSIC tokens in this file.
+ * but for now this untested & undone.
+ *
+ *
+ * ripped from linux kernel 2.4.18 by Karsten Wiese.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ * msnd_pinnacle.c / msnd_classic.c
+ *
+ * -- If MSND_CLASSIC is defined:
+ *
+ * -> driver for Turtle Beach Classic/Monterey/Tahiti
+ *
+ * -- Else
+ *
+ * -> driver for Turtle Beach Pinnacle/Fiji
+ *
+ * 12-3-2000 Modified IO port validation Steve Sycamore
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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.
+ *
+ ********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/firmware.h>
+#include <linux/isa.h>
+#include <linux/isapnp.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+#include <sound/mpu401.h>
+
+#ifdef MSND_CLASSIC
+# ifndef __alpha__
+# define SLOWIO
+# endif
+#endif
+#include "msnd.h"
+#ifdef MSND_CLASSIC
+# include "msnd_classic.h"
+# define LOGNAME "msnd_classic"
+# define DEV_NAME "msnd-classic"
+#else
+# include "msnd_pinnacle.h"
+# define LOGNAME "snd_msnd_pinnacle"
+# define DEV_NAME "msnd-pinnacle"
+#endif
+
+static void set_default_audio_parameters(struct snd_msnd *chip)
+{
+ chip->play_sample_size = DEFSAMPLESIZE;
+ chip->play_sample_rate = DEFSAMPLERATE;
+ chip->play_channels = DEFCHANNELS;
+ chip->capture_sample_size = DEFSAMPLESIZE;
+ chip->capture_sample_rate = DEFSAMPLERATE;
+ chip->capture_channels = DEFCHANNELS;
+}
+
+static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
+{
+ switch (HIBYTE(wMessage)) {
+ case HIMT_PLAY_DONE: {
+ if (chip->banksPlayed < 3)
+ snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
+ (unsigned)jiffies, LOBYTE(wMessage));
+
+ if (chip->last_playbank == LOBYTE(wMessage)) {
+ snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
+ break;
+ }
+ chip->banksPlayed++;
+
+ if (test_bit(F_WRITING, &chip->flags))
+ snd_msnd_DAPQ(chip, 0);
+
+ chip->last_playbank = LOBYTE(wMessage);
+ chip->playDMAPos += chip->play_period_bytes;
+ if (chip->playDMAPos > chip->playLimit)
+ chip->playDMAPos = 0;
+ snd_pcm_period_elapsed(chip->playback_substream);
+
+ break;
+ }
+ case HIMT_RECORD_DONE:
+ if (chip->last_recbank == LOBYTE(wMessage))
+ break;
+ chip->last_recbank = LOBYTE(wMessage);
+ chip->captureDMAPos += chip->capturePeriodBytes;
+ if (chip->captureDMAPos > (chip->captureLimit))
+ chip->captureDMAPos = 0;
+
+ if (test_bit(F_READING, &chip->flags))
+ snd_msnd_DARQ(chip, chip->last_recbank);
+
+ snd_pcm_period_elapsed(chip->capture_substream);
+ break;
+
+ case HIMT_DSP:
+ switch (LOBYTE(wMessage)) {
+#ifndef MSND_CLASSIC
+ case HIDSP_PLAY_UNDER:
+#endif
+ case HIDSP_INT_PLAY_UNDER:
+ snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
+ chip->banksPlayed);
+ if (chip->banksPlayed > 2)
+ clear_bit(F_WRITING, &chip->flags);
+ break;
+
+ case HIDSP_INT_RECORD_OVER:
+ snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
+ clear_bit(F_READING, &chip->flags);
+ break;
+
+ default:
+ snd_printd(KERN_WARNING LOGNAME
+ ": DSP message %d 0x%02x\n",
+ LOBYTE(wMessage), LOBYTE(wMessage));
+ break;
+ }
+ break;
+
+ case HIMT_MIDI_IN_UCHAR:
+ if (chip->msndmidi_mpu)
+ snd_msndmidi_input_read(chip->msndmidi_mpu);
+ break;
+
+ default:
+ snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
+ HIBYTE(wMessage), HIBYTE(wMessage));
+ break;
+ }
+}
+
+static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
+{
+ struct snd_msnd *chip = dev_id;
+ void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
+
+ /* Send ack to DSP */
+ /* inb(chip->io + HP_RXL); */
+
+ /* Evaluate queued DSP messages */
+ while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
+ u16 wTmp;
+
+ snd_msnd_eval_dsp_msg(chip,
+ readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
+
+ wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
+ if (wTmp > readw(chip->DSPQ + JQS_wSize))
+ writew(0, chip->DSPQ + JQS_wHead);
+ else
+ writew(wTmp, chip->DSPQ + JQS_wHead);
+ }
+ /* Send ack to DSP */
+ inb(chip->io + HP_RXL);
+ return IRQ_HANDLED;
+}
+
+
+static int snd_msnd_reset_dsp(long io, unsigned char *info)
+{
+ int timeout = 100;
+
+ outb(HPDSPRESET_ON, io + HP_DSPR);
+ msleep(1);
+#ifndef MSND_CLASSIC
+ if (info)
+ *info = inb(io + HP_INFO);
+#endif
+ outb(HPDSPRESET_OFF, io + HP_DSPR);
+ msleep(1);
+ while (timeout-- > 0) {
+ if (inb(io + HP_CVR) == HP_CVR_DEF)
+ return 0;
+ msleep(1);
+ }
+ snd_printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+ return -EIO;
+}
+
+static int snd_msnd_probe(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ unsigned char info;
+#ifndef MSND_CLASSIC
+ char *xv, *rev = NULL;
+ char *pin = "TB Pinnacle", *fiji = "TB Fiji";
+ char *pinfiji = "TB Pinnacle/Fiji";
+#endif
+
+ if (!request_region(chip->io, DSP_NUMIO, "probing")) {
+ snd_printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+ return -ENODEV;
+ }
+
+ if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
+ release_region(chip->io, DSP_NUMIO);
+ return -ENODEV;
+ }
+
+#ifdef MSND_CLASSIC
+ strcpy(card->shortname, "Classic/Tahiti/Monterey");
+ strcpy(card->longname, "Turtle Beach Multisound");
+ printk(KERN_INFO LOGNAME ": %s, "
+ "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+ card->shortname,
+ chip->io, chip->io + DSP_NUMIO - 1,
+ chip->irq,
+ chip->base, chip->base + 0x7fff);
+#else
+ switch (info >> 4) {
+ case 0xf:
+ xv = "<= 1.15";
+ break;
+ case 0x1:
+ xv = "1.18/1.2";
+ break;
+ case 0x2:
+ xv = "1.3";
+ break;
+ case 0x3:
+ xv = "1.4";
+ break;
+ default:
+ xv = "unknown";
+ break;
+ }
+
+ switch (info & 0x7) {
+ case 0x0:
+ rev = "I";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x1:
+ rev = "F";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x2:
+ rev = "G";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x3:
+ rev = "H";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x4:
+ rev = "E";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x5:
+ rev = "C";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x6:
+ rev = "D";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x7:
+ rev = "A-B (Fiji) or A-E (Pinnacle)";
+ strcpy(card->shortname, pinfiji);
+ break;
+ }
+ strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
+ printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
+ "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+ card->shortname,
+ rev, xv,
+ chip->io, chip->io + DSP_NUMIO - 1,
+ chip->irq,
+ chip->base, chip->base + 0x7fff);
+#endif
+
+ release_region(chip->io, DSP_NUMIO);
+ return 0;
+}
+
+static int snd_msnd_init_sma(struct snd_msnd *chip)
+{
+ static int initted;
+ u16 mastVolLeft, mastVolRight;
+ unsigned long flags;
+
+#ifdef MSND_CLASSIC
+ outb(chip->memid, chip->io + HP_MEMM);
+#endif
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ /* Motorola 56k shared memory base */
+ chip->SMA = chip->mappedbase + SMA_STRUCT_START;
+
+ if (initted) {
+ mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);
+ mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);
+ } else
+ mastVolLeft = mastVolRight = 0;
+ memset_io(chip->mappedbase, 0, 0x8000);
+
+ /* Critical section: bank 1 access */
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ memset_io(chip->mappedbase, 0, 0x8000);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /* Digital audio play queue */
+ chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
+ snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
+
+ /* Digital audio record queue */
+ chip->DARQ = chip->mappedbase + DARQ_OFFSET;
+ snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
+
+ /* MIDI out queue */
+ chip->MODQ = chip->mappedbase + MODQ_OFFSET;
+ snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
+
+ /* MIDI in queue */
+ chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;
+ snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
+
+ /* DSP -> host message queue */
+ chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;
+ snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
+
+ /* Setup some DSP values */
+#ifndef MSND_CLASSIC
+ writew(1, chip->SMA + SMA_wCurrPlayFormat);
+ writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
+ writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
+ writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
+#endif
+ writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
+ writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
+ writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
+#ifndef MSND_CLASSIC
+ writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
+ writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
+#endif
+ writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
+
+ initted = 1;
+
+ return 0;
+}
+
+
+static int upload_dsp_code(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ const struct firmware *init_fw = NULL, *perm_fw = NULL;
+ int err;
+
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+
+ err = request_firmware(&init_fw, INITCODEFILE, card->dev);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+ goto cleanup1;
+ }
+ err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+ goto cleanup;
+ }
+
+ memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
+ if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
+ printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+ err = -ENODEV;
+ goto cleanup;
+ }
+ printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
+ err = 0;
+
+cleanup:
+ release_firmware(perm_fw);
+cleanup1:
+ release_firmware(init_fw);
+ return err;
+}
+
+#ifdef MSND_CLASSIC
+static void reset_proteus(struct snd_msnd *chip)
+{
+ outb(HPPRORESET_ON, chip->io + HP_PROR);
+ msleep(TIME_PRO_RESET);
+ outb(HPPRORESET_OFF, chip->io + HP_PROR);
+ msleep(TIME_PRO_RESET_DONE);
+}
+#endif
+
+static int snd_msnd_initialize(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int err, timeout;
+
+#ifdef MSND_CLASSIC
+ outb(HPWAITSTATE_0, chip->io + HP_WAIT);
+ outb(HPBITMODE_16, chip->io + HP_BITM);
+
+ reset_proteus(chip);
+#endif
+ err = snd_msnd_init_sma(chip);
+ if (err < 0) {
+ printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+ return err;
+ }
+
+ err = snd_msnd_reset_dsp(chip->io, NULL);
+ if (err < 0)
+ return err;
+
+ err = upload_dsp_code(card);
+ if (err < 0) {
+ printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+ return err;
+ }
+
+ timeout = 200;
+
+ while (readw(chip->mappedbase)) {
+ msleep(1);
+ if (!timeout--) {
+ snd_printd(KERN_ERR LOGNAME ": DSP reset timeout\n");
+ return -EIO;
+ }
+ }
+
+ snd_msndmix_setup(chip);
+ return 0;
+}
+
+static int snd_msnd_dsp_full_reset(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int rv;
+
+ if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)
+ return 0;
+
+ set_bit(F_RESETTING, &chip->flags);
+ snd_msnd_dsp_halt(chip, NULL); /* Unconditionally halt */
+
+ rv = snd_msnd_initialize(card);
+ if (rv)
+ printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
+ snd_msndmix_force_recsrc(chip, 0);
+ clear_bit(F_RESETTING, &chip->flags);
+ return rv;
+}
+
+static int snd_msnd_dev_free(struct snd_device *device)
+{
+ snd_printdd("snd_msnd_chip_free()\n");
+ return 0;
+}
+
+static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
+{
+ if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)
+ return 0;
+ snd_msnd_dsp_full_reset(chip->card);
+ return snd_msnd_send_dsp_cmd(chip, cmd);
+}
+
+static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
+{
+ snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
+ writew(srate, chip->SMA + SMA_wCalFreqAtoD);
+ if (chip->calibrate_signal == 0)
+ writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
+ | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+ else
+ writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
+ & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+ if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+ snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
+ schedule_timeout_interruptible(msecs_to_jiffies(333));
+ return 0;
+ }
+ printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
+ return -EIO;
+}
+
+/*
+ * ALSA callback function, called when attempting to open the MIDI device.
+ */
+static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
+{
+ snd_msnd_enable_irq(mpu->private_data);
+ snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);
+ return 0;
+}
+
+static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
+{
+ snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);
+ snd_msnd_disable_irq(mpu->private_data);
+}
+
+static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+
+static int snd_msnd_attach(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int err;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_msnd_dev_free,
+ };
+
+ err = request_irq(chip->irq, snd_msnd_interrupt, 0, card->shortname,
+ chip);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
+ return err;
+ }
+ if (request_region(chip->io, DSP_NUMIO, card->shortname) == NULL) {
+ free_irq(chip->irq, chip);
+ return -EBUSY;
+ }
+
+ if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
+ printk(KERN_ERR LOGNAME
+ ": unable to grab memory region 0x%lx-0x%lx\n",
+ chip->base, chip->base + BUFFSIZE - 1);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ return -EBUSY;
+ }
+ chip->mappedbase = ioremap_nocache(chip->base, 0x8000);
+ if (!chip->mappedbase) {
+ printk(KERN_ERR LOGNAME
+ ": unable to map memory region 0x%lx-0x%lx\n",
+ chip->base, chip->base + BUFFSIZE - 1);
+ err = -EIO;
+ goto err_release_region;
+ }
+
+ err = snd_msnd_dsp_full_reset(card);
+ if (err < 0)
+ goto err_release_region;
+
+ /* Register device */
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0)
+ goto err_release_region;
+
+ err = snd_msnd_pcm(card, 0, NULL);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
+ goto err_release_region;
+ }
+
+ err = snd_msndmix_new(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
+ goto err_release_region;
+ }
+
+
+ if (mpu_io[0] != SNDRV_AUTO_PORT) {
+ struct snd_mpu401 *mpu;
+
+ err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_io[0],
+ MPU401_MODE_INPUT |
+ MPU401_MODE_OUTPUT,
+ mpu_irq[0],
+ &chip->rmidi);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME
+ ": error creating new Midi device\n");
+ goto err_release_region;
+ }
+ mpu = chip->rmidi->private_data;
+
+ mpu->open_input = snd_msnd_mpu401_open;
+ mpu->close_input = snd_msnd_mpu401_close;
+ mpu->private_data = chip;
+ }
+
+ disable_irq(chip->irq);
+ snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
+ snd_msndmix_force_recsrc(chip, 0);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto err_release_region;
+
+ return 0;
+
+err_release_region:
+ if (chip->mappedbase)
+ iounmap(chip->mappedbase);
+ release_mem_region(chip->base, BUFFSIZE);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ return err;
+}
+
+
+static void snd_msnd_unload(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+
+ iounmap(chip->mappedbase);
+ release_mem_region(chip->base, BUFFSIZE);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ snd_card_free(card);
+}
+
+#ifndef MSND_CLASSIC
+
+/* Pinnacle/Fiji Logical Device Configuration */
+
+static int snd_msnd_write_cfg(int cfg, int reg, int value)
+{
+ outb(reg, cfg);
+ outb(value, cfg + 1);
+ if (value != inb(cfg + 1)) {
+ printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
+ return -EIO;
+ return 0;
+}
+
+static int snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
+ return -EIO;
+ return 0;
+}
+
+static int snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
+ return -EIO;
+ return 0;
+}
+
+static int snd_msnd_write_cfg_mem(int cfg, int num, int mem)
+{
+ u16 wmem;
+
+ mem >>= 8;
+ wmem = (u16)(mem & 0xfff);
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
+ return -EIO;
+ if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL,
+ MEMTYPE_HIADDR | MEMTYPE_16BIT))
+ return -EIO;
+ return 0;
+}
+
+static int snd_msnd_activate_logical(int cfg, int num)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
+ return -EIO;
+ return 0;
+}
+
+static int snd_msnd_write_cfg_logical(int cfg, int num, u16 io0,
+ u16 io1, u16 irq, int mem)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg_io0(cfg, num, io0))
+ return -EIO;
+ if (snd_msnd_write_cfg_io1(cfg, num, io1))
+ return -EIO;
+ if (snd_msnd_write_cfg_irq(cfg, num, irq))
+ return -EIO;
+ if (snd_msnd_write_cfg_mem(cfg, num, mem))
+ return -EIO;
+ if (snd_msnd_activate_logical(cfg, num))
+ return -EIO;
+ return 0;
+}
+
+static int snd_msnd_pinnacle_cfg_reset(int cfg)
+{
+ int i;
+
+ /* Reset devices if told to */
+ printk(KERN_INFO LOGNAME ": Resetting all devices\n");
+ for (i = 0; i < 4; ++i)
+ if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");
+
+static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+#ifndef MSND_CLASSIC
+static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+/* Extra Peripheral Configuration (Default: Disable) */
+static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int ide_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+
+static long joystick_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+/* If we have the digital daugherboard... */
+static int digital[SNDRV_CARDS];
+
+/* Extra Peripheral Configuration */
+static int reset[SNDRV_CARDS];
+#endif
+
+static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
+
+static int calibrate_signal;
+
+#ifdef CONFIG_PNP
+static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+module_param_array(isapnp, bool, NULL, 0444);
+MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
+#define has_isapnp(x) isapnp[x]
+#else
+#define has_isapnp(x) 0
+#endif
+
+MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
+MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(INITCODEFILE);
+MODULE_FIRMWARE(PERMCODEFILE);
+
+module_param_array(io, long, NULL, S_IRUGO);
+MODULE_PARM_DESC(io, "IO port #");
+module_param_array(irq, int, NULL, S_IRUGO);
+module_param_array(mem, long, NULL, S_IRUGO);
+module_param_array(write_ndelay, int, NULL, S_IRUGO);
+module_param(calibrate_signal, int, S_IRUGO);
+#ifndef MSND_CLASSIC
+module_param_array(digital, int, NULL, S_IRUGO);
+module_param_array(cfg, long, NULL, S_IRUGO);
+module_param_array(reset, int, 0, S_IRUGO);
+module_param_array(mpu_io, long, NULL, S_IRUGO);
+module_param_array(mpu_irq, int, NULL, S_IRUGO);
+module_param_array(ide_io0, long, NULL, S_IRUGO);
+module_param_array(ide_io1, long, NULL, S_IRUGO);
+module_param_array(ide_irq, int, NULL, S_IRUGO);
+module_param_array(joystick_io, long, NULL, S_IRUGO);
+#endif
+
+
+static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
+{
+ if (io[i] == SNDRV_AUTO_PORT)
+ return 0;
+
+ if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
+ printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+ return 0;
+ }
+
+#ifdef MSND_CLASSIC
+ if (!(io[i] == 0x290 ||
+ io[i] == 0x260 ||
+ io[i] == 0x250 ||
+ io[i] == 0x240 ||
+ io[i] == 0x230 ||
+ io[i] == 0x220 ||
+ io[i] == 0x210 ||
+ io[i] == 0x3e0)) {
+ printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set "
+ " to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "
+ "or 0x3E0\n");
+ return 0;
+ }
+#else
+ if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
+ printk(KERN_ERR LOGNAME
+ ": \"io\" - DSP I/O base must within the range 0x100 "
+ "to 0x3E0 and must be evenly divisible by 0x10\n");
+ return 0;
+ }
+#endif /* MSND_CLASSIC */
+
+ if (!(irq[i] == 5 ||
+ irq[i] == 7 ||
+ irq[i] == 9 ||
+ irq[i] == 10 ||
+ irq[i] == 11 ||
+ irq[i] == 12)) {
+ printk(KERN_ERR LOGNAME
+ ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+ return 0;
+ }
+
+ if (!(mem[i] == 0xb0000 ||
+ mem[i] == 0xc8000 ||
+ mem[i] == 0xd0000 ||
+ mem[i] == 0xd8000 ||
+ mem[i] == 0xe0000 ||
+ mem[i] == 0xe8000)) {
+ printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+ "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "
+ "0xe8000\n");
+ return 0;
+ }
+
+#ifndef MSND_CLASSIC
+ if (cfg[i] == SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ } else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
+ printk(KERN_INFO LOGNAME
+ ": Config port must be 0x250, 0x260 or 0x270 "
+ "(or unspecified for PnP mode)\n");
+ return 0;
+ }
+#endif /* MSND_CLASSIC */
+
+ return 1;
+}
+
+static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
+{
+ int err;
+ struct snd_card *card;
+ struct snd_msnd *chip;
+
+ if (has_isapnp(idx)
+#ifndef MSND_CLASSIC
+ || cfg[idx] == SNDRV_AUTO_PORT
+#endif
+ ) {
+ printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ return -ENODEV;
+ }
+
+ err = snd_card_new(pdev, index[idx], id[idx], THIS_MODULE,
+ sizeof(struct snd_msnd), &card);
+ if (err < 0)
+ return err;
+
+ chip = card->private_data;
+ chip->card = card;
+
+#ifdef MSND_CLASSIC
+ switch (irq[idx]) {
+ case 5:
+ chip->irqid = HPIRQ_5; break;
+ case 7:
+ chip->irqid = HPIRQ_7; break;
+ case 9:
+ chip->irqid = HPIRQ_9; break;
+ case 10:
+ chip->irqid = HPIRQ_10; break;
+ case 11:
+ chip->irqid = HPIRQ_11; break;
+ case 12:
+ chip->irqid = HPIRQ_12; break;
+ }
+
+ switch (mem[idx]) {
+ case 0xb0000:
+ chip->memid = HPMEM_B000; break;
+ case 0xc8000:
+ chip->memid = HPMEM_C800; break;
+ case 0xd0000:
+ chip->memid = HPMEM_D000; break;
+ case 0xd8000:
+ chip->memid = HPMEM_D800; break;
+ case 0xe0000:
+ chip->memid = HPMEM_E000; break;
+ case 0xe8000:
+ chip->memid = HPMEM_E800; break;
+ }
+#else
+ printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
+ cfg[idx]);
+
+ if (!request_region(cfg[idx], 2, "Pinnacle/Fiji Config")) {
+ printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n",
+ cfg[idx]);
+ snd_card_free(card);
+ return -EIO;
+ }
+ if (reset[idx])
+ if (snd_msnd_pinnacle_cfg_reset(cfg[idx])) {
+ err = -EIO;
+ goto cfg_error;
+ }
+
+ /* DSP */
+ err = snd_msnd_write_cfg_logical(cfg[idx], 0,
+ io[idx], 0,
+ irq[idx], mem[idx]);
+
+ if (err)
+ goto cfg_error;
+
+ /* The following are Pinnacle specific */
+
+ /* MPU */
+ if (mpu_io[idx] != SNDRV_AUTO_PORT
+ && mpu_irq[idx] != SNDRV_AUTO_IRQ) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring MPU to I/O 0x%lx IRQ %d\n",
+ mpu_io[idx], mpu_irq[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 1,
+ mpu_io[idx], 0,
+ mpu_irq[idx], 0);
+
+ if (err)
+ goto cfg_error;
+ }
+
+ /* IDE */
+ if (ide_io0[idx] != SNDRV_AUTO_PORT
+ && ide_io1[idx] != SNDRV_AUTO_PORT
+ && ide_irq[idx] != SNDRV_AUTO_IRQ) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
+ ide_io0[idx], ide_io1[idx], ide_irq[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 2,
+ ide_io0[idx], ide_io1[idx],
+ ide_irq[idx], 0);
+
+ if (err)
+ goto cfg_error;
+ }
+
+ /* Joystick */
+ if (joystick_io[idx] != SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring joystick to I/O 0x%lx\n",
+ joystick_io[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 3,
+ joystick_io[idx], 0,
+ 0, 0);
+
+ if (err)
+ goto cfg_error;
+ }
+ release_region(cfg[idx], 2);
+
+#endif /* MSND_CLASSIC */
+
+ set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+ chip->type = msndClassic;
+#else
+ chip->type = msndPinnacle;
+#endif
+ chip->io = io[idx];
+ chip->irq = irq[idx];
+ chip->base = mem[idx];
+
+ chip->calibrate_signal = calibrate_signal ? 1 : 0;
+ chip->recsrc = 0;
+ chip->dspq_data_buff = DSPQ_DATA_BUFF;
+ chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+ if (write_ndelay[idx])
+ clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+ else
+ set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+ if (digital[idx])
+ set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+ spin_lock_init(&chip->lock);
+ err = snd_msnd_probe(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ snd_card_free(card);
+ return err;
+ }
+
+ err = snd_msnd_attach(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ snd_card_free(card);
+ return err;
+ }
+ dev_set_drvdata(pdev, card);
+
+ return 0;
+
+#ifndef MSND_CLASSIC
+cfg_error:
+ release_region(cfg[idx], 2);
+ snd_card_free(card);
+ return err;
+#endif
+}
+
+static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
+{
+ snd_msnd_unload(dev_get_drvdata(pdev));
+ return 0;
+}
+
+static struct isa_driver snd_msnd_driver = {
+ .match = snd_msnd_isa_match,
+ .probe = snd_msnd_isa_probe,
+ .remove = snd_msnd_isa_remove,
+ /* FIXME: suspend, resume */
+ .driver = {
+ .name = DEV_NAME
+ },
+};
+
+#ifdef CONFIG_PNP
+static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
+{
+ static int idx;
+ struct pnp_dev *pnp_dev;
+ struct pnp_dev *mpu_dev;
+ struct snd_card *card;
+ struct snd_msnd *chip;
+ int ret;
+
+ for ( ; idx < SNDRV_CARDS; idx++) {
+ if (has_isapnp(idx))
+ break;
+ }
+ if (idx >= SNDRV_CARDS)
+ return -ENODEV;
+
+ /*
+ * Check that we still have room for another sound card ...
+ */
+ pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
+ if (!pnp_dev)
+ return -ENODEV;
+
+ mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);
+ if (!mpu_dev)
+ return -ENODEV;
+
+ if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
+ printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
+ return -EBUSY;
+ }
+
+ if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
+ printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Create a new ALSA sound card entry, in anticipation
+ * of detecting our hardware ...
+ */
+ ret = snd_card_new(&pcard->card->dev,
+ index[idx], id[idx], THIS_MODULE,
+ sizeof(struct snd_msnd), &card);
+ if (ret < 0)
+ return ret;
+
+ chip = card->private_data;
+ chip->card = card;
+
+ /*
+ * Read the correct parameters off the ISA PnP bus ...
+ */
+ io[idx] = pnp_port_start(pnp_dev, 0);
+ irq[idx] = pnp_irq(pnp_dev, 0);
+ mem[idx] = pnp_mem_start(pnp_dev, 0);
+ mpu_io[idx] = pnp_port_start(mpu_dev, 0);
+ mpu_irq[idx] = pnp_irq(mpu_dev, 0);
+
+ set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+ chip->type = msndClassic;
+#else
+ chip->type = msndPinnacle;
+#endif
+ chip->io = io[idx];
+ chip->irq = irq[idx];
+ chip->base = mem[idx];
+
+ chip->calibrate_signal = calibrate_signal ? 1 : 0;
+ chip->recsrc = 0;
+ chip->dspq_data_buff = DSPQ_DATA_BUFF;
+ chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+ if (write_ndelay[idx])
+ clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+ else
+ set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+ if (digital[idx])
+ set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+ spin_lock_init(&chip->lock);
+ ret = snd_msnd_probe(card);
+ if (ret < 0) {
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ goto _release_card;
+ }
+
+ ret = snd_msnd_attach(card);
+ if (ret < 0) {
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ goto _release_card;
+ }
+
+ pnp_set_card_drvdata(pcard, card);
+ ++idx;
+ return 0;
+
+_release_card:
+ snd_card_free(card);
+ return ret;
+}
+
+static void snd_msnd_pnp_remove(struct pnp_card_link *pcard)
+{
+ snd_msnd_unload(pnp_get_card_drvdata(pcard));
+ pnp_set_card_drvdata(pcard, NULL);
+}
+
+static int isa_registered;
+static int pnp_registered;
+
+static struct pnp_card_device_id msnd_pnpids[] = {
+ /* Pinnacle PnP */
+ { .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },
+ { .id = "" } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);
+
+static struct pnp_card_driver msnd_pnpc_driver = {
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .name = "msnd_pinnacle",
+ .id_table = msnd_pnpids,
+ .probe = snd_msnd_pnp_detect,
+ .remove = snd_msnd_pnp_remove,
+};
+#endif /* CONFIG_PNP */
+
+static int __init snd_msnd_init(void)
+{
+ int err;
+
+ err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+ if (!err)
+ isa_registered = 1;
+
+ err = pnp_register_card_driver(&msnd_pnpc_driver);
+ if (!err)
+ pnp_registered = 1;
+
+ if (isa_registered)
+ err = 0;
+#endif
+ return err;
+}
+
+static void __exit snd_msnd_exit(void)
+{
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&msnd_pnpc_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_msnd_driver);
+}
+
+module_init(snd_msnd_init);
+module_exit(snd_msnd_exit);
+
diff --git a/sound/isa/msnd/msnd_pinnacle.h b/sound/isa/msnd/msnd_pinnacle.h
new file mode 100644
index 00000000000..48318d1ee34
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.h
@@ -0,0 +1,181 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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.
+ *
+ ********************************************************************/
+#ifndef __MSND_PINNACLE_H
+#define __MSND_PINNACLE_H
+
+#define DSP_NUMIO 0x08
+
+#define IREG_LOGDEVICE 0x07
+#define IREG_ACTIVATE 0x30
+#define LD_ACTIVATE 0x01
+#define LD_DISACTIVATE 0x00
+#define IREG_EECONTROL 0x3F
+#define IREG_MEMBASEHI 0x40
+#define IREG_MEMBASELO 0x41
+#define IREG_MEMCONTROL 0x42
+#define IREG_MEMRANGEHI 0x43
+#define IREG_MEMRANGELO 0x44
+#define MEMTYPE_8BIT 0x00
+#define MEMTYPE_16BIT 0x02
+#define MEMTYPE_RANGE 0x00
+#define MEMTYPE_HIADDR 0x01
+#define IREG_IO0_BASEHI 0x60
+#define IREG_IO0_BASELO 0x61
+#define IREG_IO1_BASEHI 0x62
+#define IREG_IO1_BASELO 0x63
+#define IREG_IRQ_NUMBER 0x70
+#define IREG_IRQ_TYPE 0x71
+#define IRQTYPE_HIGH 0x02
+#define IRQTYPE_LOW 0x00
+#define IRQTYPE_LEVEL 0x01
+#define IRQTYPE_EDGE 0x00
+
+#define HP_DSPR 0x04
+#define HP_BLKS 0x04
+
+#define HPDSPRESET_OFF 2
+#define HPDSPRESET_ON 0
+
+#define HPBLKSEL_0 2
+#define HPBLKSEL_1 3
+
+#define HIMT_DAT_OFF 0x03
+
+#define HIDSP_PLAY_UNDER 0x00
+#define HIDSP_INT_PLAY_UNDER 0x01
+#define HIDSP_SSI_TX_UNDER 0x02
+#define HIDSP_RECQ_OVERFLOW 0x08
+#define HIDSP_INT_RECORD_OVER 0x09
+#define HIDSP_SSI_RX_OVERFLOW 0x0a
+
+#define HIDSP_MIDI_IN_OVER 0x10
+
+#define HIDSP_MIDI_FRAME_ERR 0x11
+#define HIDSP_MIDI_PARITY_ERR 0x12
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define HIDSP_INPUT_CLIPPING 0x20
+#define HIDSP_MIX_CLIPPING 0x30
+#define HIDSP_DAT_IN_OFF 0x21
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x001E
+#define TIME_PRO_RESET 0x0032
+
+#define DAR_BUFF_SIZE 0x1000
+
+#define MIDQ_BUFF_SIZE 0x800
+#define DSPQ_BUFF_SIZE 0x5A0
+
+#define DSPQ_DATA_BUFF 0x7860
+
+#define MOP_WAVEHDR 0
+#define MOP_EXTOUT 1
+#define MOP_HWINIT 0xfe
+#define MOP_NONE 0xff
+#define MOP_MAX 1
+
+#define MIP_EXTIN 0
+#define MIP_WAVEHDR 1
+#define MIP_HWINIT 0xfe
+#define MIP_MAX 1
+
+/* Pinnacle/Fiji SMA Common Data */
+#define SMA_wCurrPlayBytes 0x0000
+#define SMA_wCurrRecordBytes 0x0002
+#define SMA_wCurrPlayVolLeft 0x0004
+#define SMA_wCurrPlayVolRight 0x0006
+#define SMA_wCurrInVolLeft 0x0008
+#define SMA_wCurrInVolRight 0x000a
+#define SMA_wCurrMHdrVolLeft 0x000c
+#define SMA_wCurrMHdrVolRight 0x000e
+#define SMA_dwCurrPlayPitch 0x0010
+#define SMA_dwCurrPlayRate 0x0014
+#define SMA_wCurrMIDIIOPatch 0x0018
+#define SMA_wCurrPlayFormat 0x001a
+#define SMA_wCurrPlaySampleSize 0x001c
+#define SMA_wCurrPlayChannels 0x001e
+#define SMA_wCurrPlaySampleRate 0x0020
+#define SMA_wCurrRecordFormat 0x0022
+#define SMA_wCurrRecordSampleSize 0x0024
+#define SMA_wCurrRecordChannels 0x0026
+#define SMA_wCurrRecordSampleRate 0x0028
+#define SMA_wCurrDSPStatusFlags 0x002a
+#define SMA_wCurrHostStatusFlags 0x002c
+#define SMA_wCurrInputTagBits 0x002e
+#define SMA_wCurrLeftPeak 0x0030
+#define SMA_wCurrRightPeak 0x0032
+#define SMA_bMicPotPosLeft 0x0034
+#define SMA_bMicPotPosRight 0x0035
+#define SMA_bMicPotMaxLeft 0x0036
+#define SMA_bMicPotMaxRight 0x0037
+#define SMA_bInPotPosLeft 0x0038
+#define SMA_bInPotPosRight 0x0039
+#define SMA_bAuxPotPosLeft 0x003a
+#define SMA_bAuxPotPosRight 0x003b
+#define SMA_bInPotMaxLeft 0x003c
+#define SMA_bInPotMaxRight 0x003d
+#define SMA_bAuxPotMaxLeft 0x003e
+#define SMA_bAuxPotMaxRight 0x003f
+#define SMA_bInPotMaxMethod 0x0040
+#define SMA_bAuxPotMaxMethod 0x0041
+#define SMA_wCurrMastVolLeft 0x0042
+#define SMA_wCurrMastVolRight 0x0044
+#define SMA_wCalFreqAtoD 0x0046
+#define SMA_wCurrAuxVolLeft 0x0048
+#define SMA_wCurrAuxVolRight 0x004a
+#define SMA_wCurrPlay1VolLeft 0x004c
+#define SMA_wCurrPlay1VolRight 0x004e
+#define SMA_wCurrPlay2VolLeft 0x0050
+#define SMA_wCurrPlay2VolRight 0x0052
+#define SMA_wCurrPlay3VolLeft 0x0054
+#define SMA_wCurrPlay3VolRight 0x0056
+#define SMA_wCurrPlay4VolLeft 0x0058
+#define SMA_wCurrPlay4VolRight 0x005a
+#define SMA_wCurrPlay1PeakLeft 0x005c
+#define SMA_wCurrPlay1PeakRight 0x005e
+#define SMA_wCurrPlay2PeakLeft 0x0060
+#define SMA_wCurrPlay2PeakRight 0x0062
+#define SMA_wCurrPlay3PeakLeft 0x0064
+#define SMA_wCurrPlay3PeakRight 0x0066
+#define SMA_wCurrPlay4PeakLeft 0x0068
+#define SMA_wCurrPlay4PeakRight 0x006a
+#define SMA_wCurrPlayPeakLeft 0x006c
+#define SMA_wCurrPlayPeakRight 0x006e
+#define SMA_wCurrDATSR 0x0070
+#define SMA_wCurrDATRXCHNL 0x0072
+#define SMA_wCurrDATTXCHNL 0x0074
+#define SMA_wCurrDATRXRate 0x0076
+#define SMA_dwDSPPlayCount 0x0078
+#define SMA__size 0x007c
+
+#define INITCODEFILE "turtlebeach/pndspini.bin"
+#define PERMCODEFILE "turtlebeach/pndsperm.bin"
+#define LONGNAME "MultiSound (Pinnacle/Fiji)"
+
+#endif /* __MSND_PINNACLE_H */
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
new file mode 100644
index 00000000000..031dc69b747
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle_mixer.c
@@ -0,0 +1,344 @@
+/***************************************************************************
+ msnd_pinnacle_mixer.c - description
+ -------------------
+ begin : Fre Jun 7 2002
+ copyright : (C) 2002 by karsten wiese
+ email : annabellesgarden@yahoo.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. *
+ * *
+ ***************************************************************************/
+
+#include <linux/io.h>
+#include <linux/export.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include "msnd.h"
+#include "msnd_pinnacle.h"
+
+
+#define MSND_MIXER_VOLUME 0
+#define MSND_MIXER_PCM 1
+#define MSND_MIXER_AUX 2 /* Input source 1 (aux1) */
+#define MSND_MIXER_IMIX 3 /* Recording monitor */
+#define MSND_MIXER_SYNTH 4
+#define MSND_MIXER_SPEAKER 5
+#define MSND_MIXER_LINE 6
+#define MSND_MIXER_MIC 7
+#define MSND_MIXER_RECLEV 11 /* Recording level */
+#define MSND_MIXER_IGAIN 12 /* Input gain */
+#define MSND_MIXER_OGAIN 13 /* Output gain */
+#define MSND_MIXER_DIGITAL 17 /* Digital (input) 1 */
+
+/* Device mask bits */
+
+#define MSND_MASK_VOLUME (1 << MSND_MIXER_VOLUME)
+#define MSND_MASK_SYNTH (1 << MSND_MIXER_SYNTH)
+#define MSND_MASK_PCM (1 << MSND_MIXER_PCM)
+#define MSND_MASK_SPEAKER (1 << MSND_MIXER_SPEAKER)
+#define MSND_MASK_LINE (1 << MSND_MIXER_LINE)
+#define MSND_MASK_MIC (1 << MSND_MIXER_MIC)
+#define MSND_MASK_IMIX (1 << MSND_MIXER_IMIX)
+#define MSND_MASK_RECLEV (1 << MSND_MIXER_RECLEV)
+#define MSND_MASK_IGAIN (1 << MSND_MIXER_IGAIN)
+#define MSND_MASK_OGAIN (1 << MSND_MIXER_OGAIN)
+#define MSND_MASK_AUX (1 << MSND_MIXER_AUX)
+#define MSND_MASK_DIGITAL (1 << MSND_MIXER_DIGITAL)
+
+static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[3] = {
+ "Analog", "MASS", "SPDIF",
+ };
+ struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
+ unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = items;
+ if (uinfo->value.enumerated.item >= items)
+ uinfo->value.enumerated.item = items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
+ /* MSND_MASK_IMIX is the default */
+ ucontrol->value.enumerated.item[0] = 0;
+
+ if (chip->recsrc & MSND_MASK_SYNTH) {
+ ucontrol->value.enumerated.item[0] = 1;
+ } else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
+ test_bit(F_HAVEDIGITAL, &chip->flags)) {
+ ucontrol->value.enumerated.item[0] = 2;
+ }
+
+
+ return 0;
+}
+
+static int snd_msndmix_set_mux(struct snd_msnd *chip, int val)
+{
+ unsigned newrecsrc;
+ int change;
+ unsigned char msndbyte;
+
+ switch (val) {
+ case 0:
+ newrecsrc = MSND_MASK_IMIX;
+ msndbyte = HDEXAR_SET_ANA_IN;
+ break;
+ case 1:
+ newrecsrc = MSND_MASK_SYNTH;
+ msndbyte = HDEXAR_SET_SYNTH_IN;
+ break;
+ case 2:
+ newrecsrc = MSND_MASK_DIGITAL;
+ msndbyte = HDEXAR_SET_DAT_IN;
+ break;
+ default:
+ return -EINVAL;
+ }
+ change = newrecsrc != chip->recsrc;
+ if (change) {
+ change = 0;
+ if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
+ if (!snd_msnd_send_dsp_cmd(chip, HDEX_AUX_REQ)) {
+ chip->recsrc = newrecsrc;
+ change = 1;
+ }
+ }
+ return change;
+}
+
+static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
+}
+
+
+static int snd_msndmix_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 = 100;
+ return 0;
+}
+
+static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msnd->mixer_lock, flags);
+ ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
+ ucontrol->value.integer.value[0] /= 0xFFFF;
+ ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
+ ucontrol->value.integer.value[1] /= 0xFFFF;
+ spin_unlock_irqrestore(&msnd->mixer_lock, flags);
+ return 0;
+}
+
+#define update_volm(a, b) \
+ do { \
+ writew((dev->left_levels[a] >> 1) * \
+ readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##b##Left); \
+ writew((dev->right_levels[a] >> 1) * \
+ readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev->SMA + SMA_##b##Right); \
+ } while (0);
+
+#define update_potm(d, s, ar) \
+ do { \
+ writeb((dev->left_levels[d] >> 8) * \
+ readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##s##Left); \
+ writeb((dev->right_levels[d] >> 8) * \
+ readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev->SMA + SMA_##s##Right); \
+ if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
+ } while (0);
+
+#define update_pot(d, s, ar) \
+ do { \
+ writeb(dev->left_levels[d] >> 8, \
+ dev->SMA + SMA_##s##Left); \
+ writeb(dev->right_levels[d] >> 8, \
+ dev->SMA + SMA_##s##Right); \
+ if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
+ } while (0);
+
+
+static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
+{
+ int bLeft, bRight;
+ int wLeft, wRight;
+ int updatemaster = 0;
+
+ if (d >= LEVEL_ENTRIES)
+ return -EINVAL;
+
+ bLeft = left * 0xff / 100;
+ wLeft = left * 0xffff / 100;
+
+ bRight = right * 0xff / 100;
+ wRight = right * 0xffff / 100;
+
+ dev->left_levels[d] = wLeft;
+ dev->right_levels[d] = wRight;
+
+ switch (d) {
+ /* master volume unscaled controls */
+ case MSND_MIXER_LINE: /* line pot control */
+ /* scaled by IMIX in digital mix */
+ writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
+ writeb(bRight, dev->SMA + SMA_bInPotPosRight);
+ if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
+ break;
+ case MSND_MIXER_MIC: /* mic pot control */
+ if (dev->type == msndClassic)
+ return -EINVAL;
+ /* scaled by IMIX in digital mix */
+ writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
+ writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
+ if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
+ break;
+ case MSND_MIXER_VOLUME: /* master volume */
+ writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
+ writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
+ /* fall through */
+
+ case MSND_MIXER_AUX: /* aux pot control */
+ /* scaled by master volume */
+ /* fall through */
+
+ /* digital controls */
+ case MSND_MIXER_SYNTH: /* synth vol (dsp mix) */
+ case MSND_MIXER_PCM: /* pcm vol (dsp mix) */
+ case MSND_MIXER_IMIX: /* input monitor (dsp mix) */
+ /* scaled by master volume */
+ updatemaster = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (updatemaster) {
+ /* update master volume scaled controls */
+ update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+ update_volm(MSND_MIXER_IMIX, wCurrInVol);
+ if (dev->type == msndPinnacle)
+ update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+ update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+ }
+
+ return 0;
+}
+
+static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ int change, addr = kcontrol->private_value;
+ int left, right;
+ unsigned long flags;
+
+ left = ucontrol->value.integer.value[0] % 101;
+ right = ucontrol->value.integer.value[1] % 101;
+ spin_lock_irqsave(&msnd->mixer_lock, flags);
+ change = msnd->left_levels[addr] != left
+ || msnd->right_levels[addr] != right;
+ snd_msndmix_set(msnd, addr, left, right);
+ spin_unlock_irqrestore(&msnd->mixer_lock, flags);
+ return change;
+}
+
+
+#define DUMMY_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_msndmix_volume_info, \
+ .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
+ .private_value = addr }
+
+
+static struct snd_kcontrol_new snd_msnd_controls[] = {
+DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
+DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
+DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
+DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
+DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
+DUMMY_VOLUME("Monitor", 0, MSND_MIXER_IMIX),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_msndmix_info_mux,
+ .get = snd_msndmix_get_mux,
+ .put = snd_msndmix_put_mux,
+}
+};
+
+
+int snd_msndmix_new(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ unsigned int idx;
+ int err;
+
+ if (snd_BUG_ON(!chip))
+ return -EINVAL;
+ spin_lock_init(&chip->mixer_lock);
+ strcpy(card->mixername, "MSND Pinnacle Mixer");
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
+ err = snd_ctl_add(card,
+ snd_ctl_new1(snd_msnd_controls + idx, chip));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+EXPORT_SYMBOL(snd_msndmix_new);
+
+void snd_msndmix_setup(struct snd_msnd *dev)
+{
+ update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
+ update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+ update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+ update_volm(MSND_MIXER_IMIX, wCurrInVol);
+ if (dev->type == msndPinnacle) {
+ update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
+ update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+ }
+}
+EXPORT_SYMBOL(snd_msndmix_setup);
+
+int snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
+{
+ dev->recsrc = -1;
+ return snd_msndmix_set_mux(dev, recsrc);
+}
+EXPORT_SYMBOL(snd_msndmix_force_recsrc);
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index ca359e0c674..a219bc37816 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -1,6 +1,6 @@
/*
* Driver for Yamaha OPL3-SA[2,3] soundcards
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,24 +19,23 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
-#include <linux/slab.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#include <sound/initval.h>
+#include <sound/tlv.h>
#include <asm/io.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Yamaha OPL3SA2+");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF719E-S},"
@@ -47,9 +46,9 @@ MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF719E-S},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
#ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#endif
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0xf86,0x370,0x100 */
static long sb_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
@@ -59,7 +58,7 @@ static long midi_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;/* 0x330,0x300 */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 0,1,3,5,9,11,12,15 */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */
-static int opl3sa3_ymode[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* 0,1,2,3 */ /*SL Added*/
+static int opl3sa3_ymode[SNDRV_CARDS]; /* 0,1,2,3 */ /*SL Added*/
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for OPL3-SA soundcard.");
@@ -90,9 +89,11 @@ MODULE_PARM_DESC(dma2, "DMA2 # for OPL3-SA driver.");
module_param_array(opl3sa3_ymode, int, NULL, 0444);
MODULE_PARM_DESC(opl3sa3_ymode, "Speaker size selection for 3D Enhancement mode: Desktop/Large Notebook/Small Notebook/HiFi.");
-static struct platform_device *platform_devices[SNDRV_CARDS];
+#ifdef CONFIG_PNP
+static int isa_registered;
static int pnp_registered;
static int pnpc_registered;
+#endif
/* control ports */
#define OPL3SA2_PM_CTRL 0x01
@@ -122,7 +123,6 @@ static int pnpc_registered;
#define OPL3SA2_PM_D3 (OPL3SA2_PM_ADOWN|OPL3SA2_PM_PSV|OPL3SA2_PM_PDN|OPL3SA2_PM_PDX)
struct snd_opl3sa2 {
- struct snd_card *card;
int version; /* 2 or 3 */
unsigned long port; /* control port */
struct resource *res_port; /* control port resource */
@@ -131,7 +131,7 @@ struct snd_opl3sa2 {
spinlock_t reg_lock;
struct snd_hwdep *synth;
struct snd_rawmidi *rmidi;
- struct snd_cs4231 *cs4231;
+ struct snd_wss *wss;
unsigned char ctlregs[0x20];
int ymode; /* SL added */
struct snd_kcontrol *master_switch;
@@ -161,6 +161,8 @@ static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
{ .id = "YMH0801", .devs = { { "YMH0021" } } },
/* NeoMagic MagicWave 3DX */
{ .id = "NMX2200", .devs = { { "YMH2210" } } },
+ /* NeoMagic MagicWave 3D */
+ { .id = "NMX2200", .devs = { { "NMX2210" } } },
/* --- */
{ .id = "" } /* end */
};
@@ -176,12 +178,13 @@ static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char
unsigned char result;
#if 0
outb(0x1d, port); /* password */
- printk("read [0x%lx] = 0x%x\n", port, inb(port));
+ printk(KERN_DEBUG "read [0x%lx] = 0x%x\n", port, inb(port));
#endif
outb(reg, chip->port); /* register */
result = inb(chip->port + 1);
#if 0
- printk("read [0x%lx] = 0x%x [0x%x]\n", port, result, inb(port));
+ printk(KERN_DEBUG "read [0x%lx] = 0x%x [0x%x]\n",
+ port, result, inb(port));
#endif
return result;
}
@@ -218,20 +221,22 @@ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsig
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
+static int snd_opl3sa2_detect(struct snd_card *card)
{
- struct snd_card *card;
+ struct snd_opl3sa2 *chip = card->private_data;
unsigned long port;
unsigned char tmp, tmp1;
char str[2];
- card = chip->card;
port = chip->port;
if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) {
snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port);
return -EBUSY;
}
- // snd_printk("REG 0A = 0x%x\n", snd_opl3sa2_read(chip, 0x0a));
+ /*
+ snd_printk(KERN_DEBUG "REG 0A = 0x%x\n",
+ snd_opl3sa2_read(chip, 0x0a));
+ */
chip->version = 0;
tmp = snd_opl3sa2_read(chip, OPL3SA2_MISC);
if (tmp == 0xff) {
@@ -248,6 +253,7 @@ static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
/* 0x03 - YM715B */
/* 0x04 - YM719 - OPL-SA4? */
/* 0x05 - OPL3-SA3 - Libretto 100 */
+ /* 0x07 - unknown - Neomagic MagicWave 3D */
break;
}
str[0] = chip->version + '0';
@@ -258,7 +264,7 @@ static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
snd_printd("OPL3-SA [0x%lx] detect (1) = 0x%x (0x%x)\n", port, tmp, tmp1);
return -ENODEV;
}
- /* try if the MIC register is accesible */
+ /* try if the MIC register is accessible */
tmp = snd_opl3sa2_read(chip, OPL3SA2_MIC);
snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x8a);
if (((tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MIC)) & 0x9f) != 0x8a) {
@@ -290,15 +296,17 @@ static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
return 0;
}
-static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
{
unsigned short status;
- struct snd_opl3sa2 *chip = dev_id;
+ struct snd_card *card = dev_id;
+ struct snd_opl3sa2 *chip;
int handled = 0;
- if (chip == NULL || chip->card == NULL)
+ if (card == NULL)
return IRQ_NONE;
+ chip = card->private_data;
status = snd_opl3sa2_read(chip, OPL3SA2_IRQ_STATUS);
if (status & 0x20) {
@@ -308,12 +316,12 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *
if ((status & 0x10) && chip->rmidi != NULL) {
handled = 1;
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
}
if (status & 0x07) { /* TI,CI,PI */
handled = 1;
- snd_cs4231_interrupt(irq, chip->cs4231, regs);
+ snd_wss_interrupt(irq, chip->wss);
}
if (status & 0x40) { /* hardware volume change */
@@ -322,8 +330,10 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *
snd_opl3sa2_read(chip, OPL3SA2_MASTER_RIGHT);
snd_opl3sa2_read(chip, OPL3SA2_MASTER_LEFT);
if (chip->master_switch && chip->master_volume) {
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_switch->id);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_volume->id);
}
}
return IRQ_RETVAL(handled);
@@ -331,20 +341,17 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *
#define OPL3SA2_SINGLE(xname, xindex, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
- .info = snd_opl3sa2_info_single, \
+ .info = snd_wss_info_single, \
.get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
-
-static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 16) & 0xff;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
+#define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .name = xname, .index = xindex, \
+ .info = snd_wss_info_single, \
+ .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
+ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
+ .tlv = { .p = (xtlv) } }
static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -389,20 +396,17 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
#define OPL3SA2_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
- .info = snd_opl3sa2_info_double, \
+ .info = snd_wss_info_double, \
.get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
-
-static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 24) & 0xff;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
+#define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .name = xname, .index = xindex, \
+ .info = snd_wss_info_double, \
+ .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
+ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
+ .tlv = { .p = (xtlv) } }
static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -466,11 +470,17 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
return change;
}
+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),
-OPL3SA2_DOUBLE("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1),
+OPL3SA2_DOUBLE_TLV("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1,
+ db_scale_master),
OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1),
-OPL3SA2_SINGLE("Mic Playback Volume", 0, 0x09, 0, 31, 1)
+OPL3SA2_SINGLE_TLV("Mic Playback Volume", 0, 0x09, 0, 31, 1,
+ db_scale_5bit_12db_max),
+OPL3SA2_SINGLE("ZV Port Switch", 0, 0x02, 0, 1, 0),
};
static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = {
@@ -486,9 +496,9 @@ static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol)
chip->master_volume = NULL;
}
-static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
+static int snd_opl3sa2_mixer(struct snd_card *card)
{
- struct snd_card *card = chip->card;
+ struct snd_opl3sa2 *chip = card->private_data;
struct snd_ctl_elem_id id1, id2;
struct snd_kcontrol *kctl;
unsigned int idx;
@@ -544,21 +554,27 @@ static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
#ifdef CONFIG_PM
static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state)
{
- struct snd_opl3sa2 *chip = card->private_data;
+ if (card) {
+ struct snd_opl3sa2 *chip = card->private_data;
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- chip->cs4231->suspend(chip->cs4231);
- /* power down */
- snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ chip->wss->suspend(chip->wss);
+ /* power down */
+ snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
+ }
return 0;
}
static int snd_opl3sa2_resume(struct snd_card *card)
{
- struct snd_opl3sa2 *chip = card->private_data;
+ struct snd_opl3sa2 *chip;
int i;
+ if (!card)
+ return 0;
+
+ chip = card->private_data;
/* power up */
snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D0);
@@ -571,8 +587,8 @@ static int snd_opl3sa2_resume(struct snd_card *card)
for (i = 0x12; i <= 0x16; i++)
snd_opl3sa2_write(chip, i, chip->ctlregs[i]);
}
- /* restore cs4231 */
- chip->cs4231->resume(chip->cs4231);
+ /* restore wss */
+ chip->wss->resume(chip->wss);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
@@ -580,42 +596,11 @@ static int snd_opl3sa2_resume(struct snd_card *card)
#endif /* CONFIG_PM */
#ifdef CONFIG_PNP
-static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
- struct pnp_dev *pdev)
+static int snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
+ struct pnp_dev *pdev)
{
- struct pnp_resource_table * cfg;
- int err;
-
- cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
- if (!cfg) {
- snd_printk(KERN_ERR PFX "cannot allocate pnp cfg\n");
- return -ENOMEM;
- }
- /* PnP initialization */
- pnp_init_resource_table(cfg);
- if (sb_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], sb_port[dev], 16);
- if (wss_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], wss_port[dev], 8);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4);
- if (midi_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[3], midi_port[dev], 2);
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[4], port[dev], 2);
- if (dma1[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
- if (dma2[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
- snd_printk(KERN_WARNING "PnP manual resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
- kfree(cfg);
- snd_printk(KERN_ERR "PnP configure failure (out of resources?) err = %d\n", err);
+ if (pnp_activate_dev(pdev) < 0) {
+ snd_printk(KERN_ERR "PnP configure failure (out of resources?)\n");
return -EBUSY;
}
sb_port[dev] = pnp_port_start(pdev, 0);
@@ -630,7 +615,6 @@ static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
- kfree(cfg);
return 0;
}
#endif /* CONFIG_PNP */
@@ -639,33 +623,36 @@ static void snd_opl3sa2_free(struct snd_card *card)
{
struct snd_opl3sa2 *chip = card->private_data;
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, card);
release_and_free_resource(chip->res_port);
}
-static struct snd_card *snd_opl3sa2_card_new(int dev)
+static int snd_opl3sa2_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
struct snd_opl3sa2 *chip;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_opl3sa2));
- if (card == NULL)
- return NULL;
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_opl3sa2), &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "OPL3SA2");
- strcpy(card->shortname, "Yamaha OPL3-SA2");
+ strcpy(card->shortname, "Yamaha OPL3-SA");
chip = card->private_data;
spin_lock_init(&chip->reg_lock);
chip->irq = -1;
- chip->card = card;
card->private_free = snd_opl3sa2_free;
- return card;
+ *cardp = card;
+ return 0;
}
-static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
+static int snd_opl3sa2_probe(struct snd_card *card, int dev)
{
int xirq, xdma1, xdma2;
struct snd_opl3sa2 *chip;
- struct snd_cs4231 *cs4231;
+ struct snd_wss *wss;
struct snd_opl3 *opl3;
int err;
@@ -678,30 +665,36 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
xdma2 = dma2[dev];
if (xdma2 < 0)
chip->single_dma = 1;
- if ((err = snd_opl3sa2_detect(chip)) < 0)
+ err = snd_opl3sa2_detect(card);
+ if (err < 0)
return err;
- if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", chip)) {
+ err = request_irq(xirq, snd_opl3sa2_interrupt, 0,
+ "OPL3-SA2", card);
+ if (err) {
snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq);
return -ENODEV;
}
chip->irq = xirq;
- if ((err = snd_cs4231_create(card,
- wss_port[dev] + 4, -1,
- xirq, xdma1, xdma2,
- CS4231_HW_OPL3SA2,
- CS4231_HWSHARE_IRQ,
- &cs4231)) < 0) {
+ err = snd_wss_create(card,
+ wss_port[dev] + 4, -1,
+ xirq, xdma1, xdma2,
+ WSS_HW_OPL3SA2, WSS_HWSHARE_IRQ, &wss);
+ if (err < 0) {
snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4);
return err;
}
- chip->cs4231 = cs4231;
- if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0)
+ chip->wss = wss;
+ err = snd_wss_pcm(wss, 0, NULL);
+ if (err < 0)
return err;
- if ((err = snd_cs4231_mixer(cs4231)) < 0)
+ err = snd_wss_mixer(wss);
+ if (err < 0)
return err;
- if ((err = snd_opl3sa2_mixer(chip)) < 0)
+ err = snd_opl3sa2_mixer(card);
+ if (err < 0)
return err;
- if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0)
+ err = snd_wss_timer(wss, 0, NULL);
+ if (err < 0)
return err;
if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) {
if ((err = snd_opl3_create(card, fm_port[dev],
@@ -715,21 +708,22 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
}
if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2,
- midi_port[dev], 0,
- xirq, 0, &chip->rmidi)) < 0)
+ midi_port[dev],
+ MPU401_INFO_IRQ_HOOK, -1,
+ &chip->rmidi)) < 0)
return err;
}
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
card->shortname, chip->port, xirq, xdma1);
- if (dma2 >= 0)
+ if (xdma2 >= 0)
sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
return snd_card_register(card);
}
#ifdef CONFIG_PNP
-static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
- const struct pnp_device_id *id)
+static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
+ const struct pnp_device_id *id)
{
static int dev;
int err;
@@ -744,14 +738,13 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(&pdev->dev, dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -761,10 +754,9 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
return 0;
}
-static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev)
+static void snd_opl3sa2_pnp_remove(struct pnp_dev *pdev)
{
snd_card_free(pnp_get_drvdata(pdev));
- pnp_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM
@@ -779,18 +771,18 @@ static int snd_opl3sa2_pnp_resume(struct pnp_dev *pdev)
#endif
static struct pnp_driver opl3sa2_pnp_driver = {
- .name = "opl3sa2-pnpbios",
+ .name = "snd-opl3sa2-pnpbios",
.id_table = snd_opl3sa2_pnpbiosids,
.probe = snd_opl3sa2_pnp_detect,
- .remove = __devexit_p(snd_opl3sa2_pnp_remove),
+ .remove = snd_opl3sa2_pnp_remove,
#ifdef CONFIG_PM
.suspend = snd_opl3sa2_pnp_suspend,
.resume = snd_opl3sa2_pnp_resume,
#endif
};
-static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *id)
+static int snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *id)
{
static int dev;
struct pnp_dev *pdev;
@@ -810,14 +802,13 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(&pdev->dev, dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -827,7 +818,7 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
return 0;
}
-static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard)
+static void snd_opl3sa2_pnp_cremove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -846,10 +837,10 @@ static int snd_opl3sa2_pnp_cresume(struct pnp_card_link *pcard)
static struct pnp_card_driver opl3sa2_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
- .name = "opl3sa2",
+ .name = "snd-opl3sa2-cpnp",
.id_table = snd_opl3sa2_pnpids,
.probe = snd_opl3sa2_pnp_cdetect,
- .remove = __devexit_p(snd_opl3sa2_pnp_cremove),
+ .remove = snd_opl3sa2_pnp_cremove,
#ifdef CONFIG_PM
.suspend = snd_opl3sa2_pnp_csuspend,
.resume = snd_opl3sa2_pnp_cresume,
@@ -857,138 +848,119 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = {
};
#endif /* CONFIG_PNP */
-static int __init snd_opl3sa2_nonpnp_probe(struct platform_device *pdev)
+static int snd_opl3sa2_isa_match(struct device *pdev,
+ unsigned int dev)
{
- struct snd_card *card;
- int err;
- int dev = pdev->id;
-
+ if (!enable[dev])
+ return 0;
+#ifdef CONFIG_PNP
+ if (isapnp[dev])
+ return 0;
+#endif
if (port[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR PFX "specify port\n");
- return -EINVAL;
+ return 0;
}
if (wss_port[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR PFX "specify wss_port\n");
- return -EINVAL;
+ return 0;
}
if (fm_port[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR PFX "specify fm_port\n");
- return -EINVAL;
+ return 0;
}
if (midi_port[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR PFX "specify midi_port\n");
- return -EINVAL;
+ return 0;
}
+ return 1;
+}
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
- snd_card_set_dev(card, &pdev->dev);
+static int snd_opl3sa2_isa_probe(struct device *pdev,
+ unsigned int dev)
+{
+ struct snd_card *card;
+ int err;
+
+ err = snd_opl3sa2_card_new(pdev, dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
}
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(pdev, card);
return 0;
}
-static int snd_opl3sa2_nonpnp_remove(struct platform_device *devptr)
+static int snd_opl3sa2_isa_remove(struct device *devptr,
+ unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
return 0;
}
#ifdef CONFIG_PM
-static int snd_opl3sa2_nonpnp_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_opl3sa2_isa_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
{
- return snd_opl3sa2_suspend(platform_get_drvdata(dev), state);
+ return snd_opl3sa2_suspend(dev_get_drvdata(dev), state);
}
-static int snd_opl3sa2_nonpnp_resume(struct platform_device *dev)
+static int snd_opl3sa2_isa_resume(struct device *dev, unsigned int n)
{
- return snd_opl3sa2_resume(platform_get_drvdata(dev));
+ return snd_opl3sa2_resume(dev_get_drvdata(dev));
}
#endif
-#define OPL3SA2_DRIVER "snd_opl3sa2"
+#define DEV_NAME "opl3sa2"
-static struct platform_driver snd_opl3sa2_nonpnp_driver = {
- .probe = snd_opl3sa2_nonpnp_probe,
- .remove = snd_opl3sa2_nonpnp_remove,
+static struct isa_driver snd_opl3sa2_isa_driver = {
+ .match = snd_opl3sa2_isa_match,
+ .probe = snd_opl3sa2_isa_probe,
+ .remove = snd_opl3sa2_isa_remove,
#ifdef CONFIG_PM
- .suspend = snd_opl3sa2_nonpnp_suspend,
- .resume = snd_opl3sa2_nonpnp_resume,
+ .suspend = snd_opl3sa2_isa_suspend,
+ .resume = snd_opl3sa2_isa_resume,
#endif
.driver = {
- .name = OPL3SA2_DRIVER
+ .name = DEV_NAME
},
};
-static void __init_or_module snd_opl3sa2_unregister_all(void)
-{
- int i;
-
- if (pnpc_registered)
- pnp_unregister_card_driver(&opl3sa2_pnpc_driver);
- if (pnp_registered)
- pnp_unregister_driver(&opl3sa2_pnp_driver);
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&snd_opl3sa2_nonpnp_driver);
-}
-
static int __init alsa_card_opl3sa2_init(void)
{
- int i, err, cards = 0;
-
- if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0)
- return err;
+ int err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
+ err = isa_register_driver(&snd_opl3sa2_isa_driver, SNDRV_CARDS);
#ifdef CONFIG_PNP
- if (isapnp[i])
- continue;
-#endif
- device = platform_device_register_simple(OPL3SA2_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- cards++;
- }
+ if (!err)
+ isa_registered = 1;
err = pnp_register_driver(&opl3sa2_pnp_driver);
- if (err >= 0) {
+ if (!err)
pnp_registered = 1;
- cards += err;
- }
+
err = pnp_register_card_driver(&opl3sa2_pnpc_driver);
- if (err >= 0) {
+ if (!err)
pnpc_registered = 1;
- cards += err;
- }
- if (!cards) {
-#ifdef MODULE
- snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n");
+ if (isa_registered || pnp_registered)
+ err = 0;
#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_opl3sa2_unregister_all();
return err;
}
static void __exit alsa_card_opl3sa2_exit(void)
{
- snd_opl3sa2_unregister_all();
+#ifdef CONFIG_PNP
+ if (pnpc_registered)
+ pnp_unregister_card_driver(&opl3sa2_pnpc_driver);
+ if (pnp_registered)
+ pnp_unregister_driver(&opl3sa2_pnp_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_opl3sa2_isa_driver);
}
module_init(alsa_card_opl3sa2_init)
diff --git a/sound/isa/opti9xx/Makefile b/sound/isa/opti9xx/Makefile
index 28c64070cd5..b4d894db257 100644
--- a/sound/isa/opti9xx/Makefile
+++ b/sound/isa/opti9xx/Makefile
@@ -1,13 +1,15 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
snd-opti92x-ad1848-objs := opti92x-ad1848.o
snd-opti92x-cs4231-objs := opti92x-cs4231.o
snd-opti93x-objs := opti93x.o
+snd-miro-objs := miro.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opti92x-ad1848.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opti92x-cs4231.o
obj-$(CONFIG_SND_OPTI93X) += snd-opti93x.o
+obj-$(CONFIG_SND_MIRO) += snd-miro.o
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
new file mode 100644
index 00000000000..c2ca681ac51
--- /dev/null
+++ b/sound/isa/opti9xx/miro.c
@@ -0,0 +1,1662 @@
+/*
+ * ALSA soundcard driver for Miro miroSOUND PCM1 pro
+ * miroSOUND PCM12
+ * miroSOUND PCM20 Radio
+ *
+ * Copyright (C) 2004-2005 Martin Langer <martin-langer@gmx.de>
+ *
+ * Based on OSS ACI and ALSA OPTi9xx drivers
+ *
+ * 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 <linux/init.h>
+#include <linux/err.h>
+#include <linux/isa.h>
+#include <linux/pnp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/mpu401.h>
+#include <sound/opl4.h>
+#include <sound/control.h>
+#include <sound/info.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+#include <sound/aci.h>
+
+MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Miro miroSOUND PCM1 pro, PCM12, PCM20 Radio");
+MODULE_SUPPORTED_DEVICE("{{Miro,miroSOUND PCM1 pro}, "
+ "{Miro,miroSOUND PCM12}, "
+ "{Miro,miroSOUND PCM20 Radio}}");
+
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
+static long port = SNDRV_DEFAULT_PORT1; /* 0x530,0xe80,0xf40,0x604 */
+static long mpu_port = SNDRV_DEFAULT_PORT1; /* 0x300,0x310,0x320,0x330 */
+static long fm_port = SNDRV_DEFAULT_PORT1; /* 0x388 */
+static int irq = SNDRV_DEFAULT_IRQ1; /* 5,7,9,10,11 */
+static int mpu_irq = SNDRV_DEFAULT_IRQ1; /* 5,7,9,10 */
+static int dma1 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */
+static int dma2 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */
+static int wss;
+static int ide;
+#ifdef CONFIG_PNP
+static bool isapnp = 1; /* Enable ISA PnP detection */
+#endif
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for miro soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for miro soundcard.");
+module_param(port, long, 0444);
+MODULE_PARM_DESC(port, "WSS port # for miro driver.");
+module_param(mpu_port, long, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for miro driver.");
+module_param(fm_port, long, 0444);
+MODULE_PARM_DESC(fm_port, "FM Port # for miro driver.");
+module_param(irq, int, 0444);
+MODULE_PARM_DESC(irq, "WSS irq # for miro driver.");
+module_param(mpu_irq, int, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 irq # for miro driver.");
+module_param(dma1, int, 0444);
+MODULE_PARM_DESC(dma1, "1st dma # for miro driver.");
+module_param(dma2, int, 0444);
+MODULE_PARM_DESC(dma2, "2nd dma # for miro driver.");
+module_param(wss, int, 0444);
+MODULE_PARM_DESC(wss, "wss mode");
+module_param(ide, int, 0444);
+MODULE_PARM_DESC(ide, "enable ide port");
+#ifdef CONFIG_PNP
+module_param(isapnp, bool, 0444);
+MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
+#endif
+
+#define OPTi9XX_HW_DETECT 0
+#define OPTi9XX_HW_82C928 1
+#define OPTi9XX_HW_82C929 2
+#define OPTi9XX_HW_82C924 3
+#define OPTi9XX_HW_82C925 4
+#define OPTi9XX_HW_82C930 5
+#define OPTi9XX_HW_82C931 6
+#define OPTi9XX_HW_82C933 7
+#define OPTi9XX_HW_LAST OPTi9XX_HW_82C933
+
+#define OPTi9XX_MC_REG(n) n
+
+struct snd_miro {
+ unsigned short hardware;
+ unsigned char password;
+ char name[7];
+
+ struct resource *res_mc_base;
+ struct resource *res_aci_port;
+
+ unsigned long mc_base;
+ unsigned long mc_base_size;
+ unsigned long pwd_reg;
+
+ spinlock_t lock;
+ struct snd_pcm *pcm;
+
+ long wss_base;
+ int irq;
+ int dma1;
+ int dma2;
+
+ long mpu_port;
+ int mpu_irq;
+
+ struct snd_miro_aci *aci;
+};
+
+static struct snd_miro_aci aci_device;
+
+static char * snd_opti9xx_names[] = {
+ "unknown",
+ "82C928", "82C929",
+ "82C924", "82C925",
+ "82C930", "82C931", "82C933"
+};
+
+static int snd_miro_pnp_is_probed;
+
+#ifdef CONFIG_PNP
+
+static struct pnp_card_device_id snd_miro_pnpids[] = {
+ /* PCM20 and PCM12 in PnP mode */
+ { .id = "MIR0924",
+ .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, },
+ { .id = "" }
+};
+
+MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids);
+
+#endif /* CONFIG_PNP */
+
+/*
+ * ACI control
+ */
+
+static int aci_busy_wait(struct snd_miro_aci *aci)
+{
+ long timeout;
+ unsigned char byte;
+
+ for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) {
+ byte = inb(aci->aci_port + ACI_REG_BUSY);
+ if ((byte & 1) == 0) {
+ if (timeout >= ACI_MINTIME)
+ snd_printd("aci ready in round %ld.\n",
+ timeout-ACI_MINTIME);
+ return byte;
+ }
+ if (timeout >= ACI_MINTIME) {
+ long out=10*HZ;
+ switch (timeout-ACI_MINTIME) {
+ case 0 ... 9:
+ out /= 10;
+ case 10 ... 19:
+ out /= 10;
+ case 20 ... 30:
+ out /= 10;
+ default:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(out);
+ break;
+ }
+ }
+ }
+ snd_printk(KERN_ERR "aci_busy_wait() time out\n");
+ return -EBUSY;
+}
+
+static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte)
+{
+ if (aci_busy_wait(aci) >= 0) {
+ outb(byte, aci->aci_port + ACI_REG_COMMAND);
+ return 0;
+ } else {
+ snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte);
+ return -EBUSY;
+ }
+}
+
+static inline int aci_read(struct snd_miro_aci *aci)
+{
+ unsigned char byte;
+
+ if (aci_busy_wait(aci) >= 0) {
+ byte = inb(aci->aci_port + ACI_REG_STATUS);
+ return byte;
+ } else {
+ snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n");
+ return -EBUSY;
+ }
+}
+
+int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3)
+{
+ int write[] = {write1, write2, write3};
+ int value, i;
+
+ if (mutex_lock_interruptible(&aci->aci_mutex))
+ return -EINTR;
+
+ for (i=0; i<3; i++) {
+ if (write[i]< 0 || write[i] > 255)
+ break;
+ else {
+ value = aci_write(aci, write[i]);
+ if (value < 0)
+ goto out;
+ }
+ }
+
+ value = aci_read(aci);
+
+out: mutex_unlock(&aci->aci_mutex);
+ return value;
+}
+EXPORT_SYMBOL(snd_aci_cmd);
+
+static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index)
+{
+ return snd_aci_cmd(aci, ACI_STATUS, index, -1);
+}
+
+static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index,
+ int value)
+{
+ return snd_aci_cmd(aci, index, value, -1);
+}
+
+struct snd_miro_aci *snd_aci_get_aci(void)
+{
+ if (aci_device.aci_port == 0)
+ return NULL;
+ return &aci_device;
+}
+EXPORT_SYMBOL(snd_aci_get_aci);
+
+/*
+ * MIXER part
+ */
+
+#define snd_miro_info_capture snd_ctl_boolean_mono_info
+
+static int snd_miro_get_capture(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int value;
+
+ value = aci_getvalue(miro->aci, ACI_S_GENERAL);
+ if (value < 0) {
+ snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n",
+ value);
+ return value;
+ }
+
+ ucontrol->value.integer.value[0] = value & 0x20;
+
+ return 0;
+}
+
+static int snd_miro_put_capture(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int change, value, error;
+
+ value = !(ucontrol->value.integer.value[0]);
+
+ error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value);
+ if (error < 0) {
+ snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n",
+ error);
+ return error;
+ }
+
+ change = (value != miro->aci->aci_solomode);
+ miro->aci->aci_solomode = value;
+
+ return change;
+}
+
+static int snd_miro_info_preamp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 3;
+
+ return 0;
+}
+
+static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int value;
+
+ if (miro->aci->aci_version <= 176) {
+
+ /*
+ OSS says it's not readable with versions < 176.
+ But it doesn't work on my card,
+ which is a PCM12 with aci_version = 176.
+ */
+
+ ucontrol->value.integer.value[0] = miro->aci->aci_preamp;
+ return 0;
+ }
+
+ value = aci_getvalue(miro->aci, ACI_GET_PREAMP);
+ if (value < 0) {
+ snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n",
+ value);
+ return value;
+ }
+
+ ucontrol->value.integer.value[0] = value;
+
+ return 0;
+}
+
+static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int error, value, change;
+
+ value = ucontrol->value.integer.value[0];
+
+ error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value);
+ if (error < 0) {
+ snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n",
+ error);
+ return error;
+ }
+
+ change = (value != miro->aci->aci_preamp);
+ miro->aci->aci_preamp = value;
+
+ return change;
+}
+
+#define snd_miro_info_amp snd_ctl_boolean_mono_info
+
+static int snd_miro_get_amp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = miro->aci->aci_amp;
+
+ return 0;
+}
+
+static int snd_miro_put_amp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int error, value, change;
+
+ value = ucontrol->value.integer.value[0];
+
+ error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value);
+ if (error < 0) {
+ snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error);
+ return error;
+ }
+
+ change = (value != miro->aci->aci_amp);
+ miro->aci->aci_amp = value;
+
+ return change;
+}
+
+#define MIRO_DOUBLE(ctl_name, ctl_index, get_right_reg, set_right_reg) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = ctl_name, \
+ .index = ctl_index, \
+ .info = snd_miro_info_double, \
+ .get = snd_miro_get_double, \
+ .put = snd_miro_put_double, \
+ .private_value = get_right_reg | (set_right_reg << 8) \
+}
+
+static int snd_miro_info_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int reg = kcontrol->private_value & 0xff;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+
+ if ((reg >= ACI_GET_EQ1) && (reg <= ACI_GET_EQ7)) {
+
+ /* equalizer elements */
+
+ uinfo->value.integer.min = - 0x7f;
+ uinfo->value.integer.max = 0x7f;
+ } else {
+
+ /* non-equalizer elements */
+
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x20;
+ }
+
+ return 0;
+}
+
+static int snd_miro_get_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ int left_val, right_val;
+
+ int right_reg = kcontrol->private_value & 0xff;
+ int left_reg = right_reg + 1;
+
+ right_val = aci_getvalue(miro->aci, right_reg);
+ if (right_val < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val);
+ return right_val;
+ }
+
+ left_val = aci_getvalue(miro->aci, left_reg);
+ if (left_val < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val);
+ return left_val;
+ }
+
+ if ((right_reg >= ACI_GET_EQ1) && (right_reg <= ACI_GET_EQ7)) {
+
+ /* equalizer elements */
+
+ if (left_val < 0x80) {
+ uinfo->value.integer.value[0] = left_val;
+ } else {
+ uinfo->value.integer.value[0] = 0x80 - left_val;
+ }
+
+ if (right_val < 0x80) {
+ uinfo->value.integer.value[1] = right_val;
+ } else {
+ uinfo->value.integer.value[1] = 0x80 - right_val;
+ }
+
+ } else {
+
+ /* non-equalizer elements */
+
+ uinfo->value.integer.value[0] = 0x20 - left_val;
+ uinfo->value.integer.value[1] = 0x20 - right_val;
+ }
+
+ return 0;
+}
+
+static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
+ struct snd_miro_aci *aci = miro->aci;
+ int left, right, left_old, right_old;
+ int setreg_left, setreg_right, getreg_left, getreg_right;
+ int change, error;
+
+ left = ucontrol->value.integer.value[0];
+ right = ucontrol->value.integer.value[1];
+
+ setreg_right = (kcontrol->private_value >> 8) & 0xff;
+ setreg_left = setreg_right + 8;
+ if (setreg_right == ACI_SET_MASTER)
+ setreg_left -= 7;
+
+ getreg_right = kcontrol->private_value & 0xff;
+ getreg_left = getreg_right + 1;
+
+ left_old = aci_getvalue(aci, getreg_left);
+ if (left_old < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old);
+ return left_old;
+ }
+
+ right_old = aci_getvalue(aci, getreg_right);
+ if (right_old < 0) {
+ snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old);
+ return right_old;
+ }
+
+ if ((getreg_right >= ACI_GET_EQ1) && (getreg_right <= ACI_GET_EQ7)) {
+
+ /* equalizer elements */
+
+ if (left < -0x7f || left > 0x7f ||
+ right < -0x7f || right > 0x7f)
+ return -EINVAL;
+
+ if (left_old > 0x80)
+ left_old = 0x80 - left_old;
+ if (right_old > 0x80)
+ right_old = 0x80 - right_old;
+
+ if (left >= 0) {
+ error = aci_setvalue(aci, setreg_left, left);
+ if (error < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ left, error);
+ return error;
+ }
+ } else {
+ error = aci_setvalue(aci, setreg_left, 0x80 - left);
+ if (error < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x80 - left, error);
+ return error;
+ }
+ }
+
+ if (right >= 0) {
+ error = aci_setvalue(aci, setreg_right, right);
+ if (error < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ right, error);
+ return error;
+ }
+ } else {
+ error = aci_setvalue(aci, setreg_right, 0x80 - right);
+ if (error < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x80 - right, error);
+ return error;
+ }
+ }
+
+ } else {
+
+ /* non-equalizer elements */
+
+ if (left < 0 || left > 0x20 ||
+ right < 0 || right > 0x20)
+ return -EINVAL;
+
+ left_old = 0x20 - left_old;
+ right_old = 0x20 - right_old;
+
+ error = aci_setvalue(aci, setreg_left, 0x20 - left);
+ if (error < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x20 - left, error);
+ return error;
+ }
+ error = aci_setvalue(aci, setreg_right, 0x20 - right);
+ if (error < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ 0x20 - right, error);
+ return error;
+ }
+ }
+
+ change = (left != left_old) || (right != right_old);
+
+ return change;
+}
+
+static struct snd_kcontrol_new snd_miro_controls[] = {
+MIRO_DOUBLE("Master Playback Volume", 0, ACI_GET_MASTER, ACI_SET_MASTER),
+MIRO_DOUBLE("Mic Playback Volume", 1, ACI_GET_MIC, ACI_SET_MIC),
+MIRO_DOUBLE("Line Playback Volume", 1, ACI_GET_LINE, ACI_SET_LINE),
+MIRO_DOUBLE("CD Playback Volume", 0, ACI_GET_CD, ACI_SET_CD),
+MIRO_DOUBLE("Synth Playback Volume", 0, ACI_GET_SYNTH, ACI_SET_SYNTH),
+MIRO_DOUBLE("PCM Playback Volume", 1, ACI_GET_PCM, ACI_SET_PCM),
+MIRO_DOUBLE("Aux Playback Volume", 2, ACI_GET_LINE2, ACI_SET_LINE2),
+};
+
+/* Equalizer with seven bands (only PCM20)
+ from -12dB up to +12dB on each band */
+static struct snd_kcontrol_new snd_miro_eq_controls[] = {
+MIRO_DOUBLE("Tone Control - 28 Hz", 0, ACI_GET_EQ1, ACI_SET_EQ1),
+MIRO_DOUBLE("Tone Control - 160 Hz", 0, ACI_GET_EQ2, ACI_SET_EQ2),
+MIRO_DOUBLE("Tone Control - 400 Hz", 0, ACI_GET_EQ3, ACI_SET_EQ3),
+MIRO_DOUBLE("Tone Control - 1 kHz", 0, ACI_GET_EQ4, ACI_SET_EQ4),
+MIRO_DOUBLE("Tone Control - 2.5 kHz", 0, ACI_GET_EQ5, ACI_SET_EQ5),
+MIRO_DOUBLE("Tone Control - 6.3 kHz", 0, ACI_GET_EQ6, ACI_SET_EQ6),
+MIRO_DOUBLE("Tone Control - 16 kHz", 0, ACI_GET_EQ7, ACI_SET_EQ7),
+};
+
+static struct snd_kcontrol_new snd_miro_radio_control[] = {
+MIRO_DOUBLE("Radio Playback Volume", 0, ACI_GET_LINE1, ACI_SET_LINE1),
+};
+
+static struct snd_kcontrol_new snd_miro_line_control[] = {
+MIRO_DOUBLE("Line Playback Volume", 2, ACI_GET_LINE1, ACI_SET_LINE1),
+};
+
+static struct snd_kcontrol_new snd_miro_preamp_control[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mic Boost",
+ .index = 1,
+ .info = snd_miro_info_preamp,
+ .get = snd_miro_get_preamp,
+ .put = snd_miro_put_preamp,
+}};
+
+static struct snd_kcontrol_new snd_miro_amp_control[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line Boost",
+ .index = 0,
+ .info = snd_miro_info_amp,
+ .get = snd_miro_get_amp,
+ .put = snd_miro_put_amp,
+}};
+
+static struct snd_kcontrol_new snd_miro_capture_control[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Switch",
+ .index = 0,
+ .info = snd_miro_info_capture,
+ .get = snd_miro_get_capture,
+ .put = snd_miro_put_capture,
+}};
+
+static unsigned char aci_init_values[][2] = {
+ { ACI_SET_MUTE, 0x00 },
+ { ACI_SET_POWERAMP, 0x00 },
+ { ACI_SET_PREAMP, 0x00 },
+ { ACI_SET_SOLOMODE, 0x00 },
+ { ACI_SET_MIC + 0, 0x20 },
+ { ACI_SET_MIC + 8, 0x20 },
+ { ACI_SET_LINE + 0, 0x20 },
+ { ACI_SET_LINE + 8, 0x20 },
+ { ACI_SET_CD + 0, 0x20 },
+ { ACI_SET_CD + 8, 0x20 },
+ { ACI_SET_PCM + 0, 0x20 },
+ { ACI_SET_PCM + 8, 0x20 },
+ { ACI_SET_LINE1 + 0, 0x20 },
+ { ACI_SET_LINE1 + 8, 0x20 },
+ { ACI_SET_LINE2 + 0, 0x20 },
+ { ACI_SET_LINE2 + 8, 0x20 },
+ { ACI_SET_SYNTH + 0, 0x20 },
+ { ACI_SET_SYNTH + 8, 0x20 },
+ { ACI_SET_MASTER + 0, 0x20 },
+ { ACI_SET_MASTER + 1, 0x20 },
+};
+
+static int snd_set_aci_init_values(struct snd_miro *miro)
+{
+ int idx, error;
+ struct snd_miro_aci *aci = miro->aci;
+
+ /* enable WSS on PCM1 */
+
+ if ((aci->aci_product == 'A') && wss) {
+ error = aci_setvalue(aci, ACI_SET_WSS, wss);
+ if (error < 0) {
+ snd_printk(KERN_ERR "enabling WSS mode failed\n");
+ return error;
+ }
+ }
+
+ /* enable IDE port */
+
+ if (ide) {
+ error = aci_setvalue(aci, ACI_SET_IDE, ide);
+ if (error < 0) {
+ snd_printk(KERN_ERR "enabling IDE port failed\n");
+ return error;
+ }
+ }
+
+ /* set common aci values */
+
+ for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) {
+ error = aci_setvalue(aci, aci_init_values[idx][0],
+ aci_init_values[idx][1]);
+ if (error < 0) {
+ snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
+ aci_init_values[idx][0], error);
+ return error;
+ }
+ }
+ aci->aci_amp = 0;
+ aci->aci_preamp = 0;
+ aci->aci_solomode = 1;
+
+ return 0;
+}
+
+static int snd_miro_mixer(struct snd_card *card,
+ struct snd_miro *miro)
+{
+ unsigned int idx;
+ int err;
+
+ if (snd_BUG_ON(!miro || !card))
+ return -EINVAL;
+
+ switch (miro->hardware) {
+ case OPTi9XX_HW_82C924:
+ strcpy(card->mixername, "ACI & OPTi924");
+ break;
+ case OPTi9XX_HW_82C929:
+ strcpy(card->mixername, "ACI & OPTi929");
+ break;
+ default:
+ snd_BUG();
+ break;
+ }
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_miro_controls); idx++) {
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_controls[idx], miro))) < 0)
+ return err;
+ }
+
+ if ((miro->aci->aci_product == 'A') ||
+ (miro->aci->aci_product == 'B')) {
+ /* PCM1/PCM12 with power-amp and Line 2 */
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0)
+ return err;
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_amp_control[0], miro))) < 0)
+ return err;
+ }
+
+ if ((miro->aci->aci_product == 'B') ||
+ (miro->aci->aci_product == 'C')) {
+ /* PCM12/PCM20 with mic-preamp */
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0)
+ return err;
+ if (miro->aci->aci_version >= 176)
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0)
+ return err;
+ }
+
+ if (miro->aci->aci_product == 'C') {
+ /* PCM20 with radio and 7 band equalizer */
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0)
+ return err;
+ for (idx = 0; idx < ARRAY_SIZE(snd_miro_eq_controls); idx++) {
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_eq_controls[idx], miro))) < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int snd_miro_init(struct snd_miro *chip,
+ unsigned short hardware)
+{
+ static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
+
+ chip->hardware = hardware;
+ strcpy(chip->name, snd_opti9xx_names[hardware]);
+
+ chip->mc_base_size = opti9xx_mc_size[hardware];
+
+ spin_lock_init(&chip->lock);
+
+ chip->wss_base = -1;
+ chip->irq = -1;
+ chip->dma1 = -1;
+ chip->dma2 = -1;
+ chip->mpu_port = -1;
+ chip->mpu_irq = -1;
+
+ chip->pwd_reg = 3;
+
+#ifdef CONFIG_PNP
+ if (isapnp && chip->mc_base)
+ /* PnP resource gives the least 10 bits */
+ chip->mc_base |= 0xc00;
+ else
+#endif
+ chip->mc_base = 0xf8c;
+
+ switch (hardware) {
+ case OPTi9XX_HW_82C929:
+ chip->password = 0xe3;
+ break;
+
+ case OPTi9XX_HW_82C924:
+ chip->password = 0xe5;
+ break;
+
+ default:
+ snd_printk(KERN_ERR "sorry, no support for %d\n", hardware);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static unsigned char snd_miro_read(struct snd_miro *chip,
+ unsigned char reg)
+{
+ unsigned long flags;
+ unsigned char retval = 0xff;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+
+ switch (chip->hardware) {
+ case OPTi9XX_HW_82C924:
+ if (reg > 7) {
+ outb(reg, chip->mc_base + 8);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+ retval = inb(chip->mc_base + 9);
+ break;
+ }
+
+ case OPTi9XX_HW_82C929:
+ retval = inb(chip->mc_base + reg);
+ break;
+
+ default:
+ snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
+ }
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+ return retval;
+}
+
+static void snd_miro_write(struct snd_miro *chip, unsigned char reg,
+ unsigned char value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+
+ switch (chip->hardware) {
+ case OPTi9XX_HW_82C924:
+ if (reg > 7) {
+ outb(reg, chip->mc_base + 8);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+ outb(value, chip->mc_base + 9);
+ break;
+ }
+
+ case OPTi9XX_HW_82C929:
+ outb(value, chip->mc_base + reg);
+ break;
+
+ default:
+ snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
+ }
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+
+#define snd_miro_write_mask(chip, reg, value, mask) \
+ snd_miro_write(chip, reg, \
+ (snd_miro_read(chip, reg) & ~(mask)) | ((value) & (mask)))
+
+/*
+ * Proc Interface
+ */
+
+static void snd_miro_proc_read(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_miro *miro = (struct snd_miro *) entry->private_data;
+ struct snd_miro_aci *aci = miro->aci;
+ char* model = "unknown";
+
+ /* miroSOUND PCM1 pro, early PCM12 */
+
+ if ((miro->hardware == OPTi9XX_HW_82C929) &&
+ (aci->aci_vendor == 'm') &&
+ (aci->aci_product == 'A')) {
+ switch (aci->aci_version) {
+ case 3:
+ model = "miroSOUND PCM1 pro";
+ break;
+ default:
+ model = "miroSOUND PCM1 pro / (early) PCM12";
+ break;
+ }
+ }
+
+ /* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */
+
+ if ((miro->hardware == OPTi9XX_HW_82C924) &&
+ (aci->aci_vendor == 'm') &&
+ (aci->aci_product == 'B')) {
+ switch (aci->aci_version) {
+ case 4:
+ model = "miroSOUND PCM12";
+ break;
+ case 176:
+ model = "miroSOUND PCM12 (Rev. E)";
+ break;
+ default:
+ model = "miroSOUND PCM12 / PCM12 pnp";
+ break;
+ }
+ }
+
+ /* miroSOUND PCM20 radio */
+
+ if ((miro->hardware == OPTi9XX_HW_82C924) &&
+ (aci->aci_vendor == 'm') &&
+ (aci->aci_product == 'C')) {
+ switch (aci->aci_version) {
+ case 7:
+ model = "miroSOUND PCM20 radio (Rev. E)";
+ break;
+ default:
+ model = "miroSOUND PCM20 radio";
+ break;
+ }
+ }
+
+ snd_iprintf(buffer, "\nGeneral information:\n");
+ snd_iprintf(buffer, " model : %s\n", model);
+ snd_iprintf(buffer, " opti : %s\n", miro->name);
+ snd_iprintf(buffer, " codec : %s\n", miro->pcm->name);
+ snd_iprintf(buffer, " port : 0x%lx\n", miro->wss_base);
+ snd_iprintf(buffer, " irq : %d\n", miro->irq);
+ snd_iprintf(buffer, " dma : %d,%d\n\n", miro->dma1, miro->dma2);
+
+ snd_iprintf(buffer, "MPU-401:\n");
+ snd_iprintf(buffer, " port : 0x%lx\n", miro->mpu_port);
+ snd_iprintf(buffer, " irq : %d\n\n", miro->mpu_irq);
+
+ snd_iprintf(buffer, "ACI information:\n");
+ snd_iprintf(buffer, " vendor : ");
+ switch (aci->aci_vendor) {
+ case 'm':
+ snd_iprintf(buffer, "Miro\n");
+ break;
+ default:
+ snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor);
+ break;
+ }
+
+ snd_iprintf(buffer, " product : ");
+ switch (aci->aci_product) {
+ case 'A':
+ snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n");
+ break;
+ case 'B':
+ snd_iprintf(buffer, "miroSOUND PCM12\n");
+ break;
+ case 'C':
+ snd_iprintf(buffer, "miroSOUND PCM20 radio\n");
+ break;
+ default:
+ snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product);
+ break;
+ }
+
+ snd_iprintf(buffer, " firmware: %d (0x%x)\n",
+ aci->aci_version, aci->aci_version);
+ snd_iprintf(buffer, " port : 0x%lx-0x%lx\n",
+ aci->aci_port, aci->aci_port+2);
+ snd_iprintf(buffer, " wss : 0x%x\n", wss);
+ snd_iprintf(buffer, " ide : 0x%x\n", ide);
+ snd_iprintf(buffer, " solomode: 0x%x\n", aci->aci_solomode);
+ snd_iprintf(buffer, " amp : 0x%x\n", aci->aci_amp);
+ snd_iprintf(buffer, " preamp : 0x%x\n", aci->aci_preamp);
+}
+
+static void snd_miro_proc_init(struct snd_card *card,
+ struct snd_miro *miro)
+{
+ struct snd_info_entry *entry;
+
+ if (!snd_card_proc_new(card, "miro", &entry))
+ snd_info_set_text_ops(entry, miro, snd_miro_proc_read);
+}
+
+/*
+ * Init
+ */
+
+static int snd_miro_configure(struct snd_miro *chip)
+{
+ unsigned char wss_base_bits;
+ unsigned char irq_bits;
+ unsigned char dma_bits;
+ unsigned char mpu_port_bits = 0;
+ unsigned char mpu_irq_bits;
+ unsigned long flags;
+
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
+
+ switch (chip->hardware) {
+ case OPTi9XX_HW_82C924:
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
+ break;
+ case OPTi9XX_HW_82C929:
+ /* untested init commands for OPTi929 */
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c);
+ break;
+ default:
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
+ return -EINVAL;
+ }
+
+ /* PnP resource says it decodes only 10 bits of address */
+ switch (chip->wss_base & 0x3ff) {
+ case 0x130:
+ chip->wss_base = 0x530;
+ wss_base_bits = 0x00;
+ break;
+ case 0x204:
+ chip->wss_base = 0x604;
+ wss_base_bits = 0x03;
+ break;
+ case 0x280:
+ chip->wss_base = 0xe80;
+ wss_base_bits = 0x01;
+ break;
+ case 0x340:
+ chip->wss_base = 0xf40;
+ wss_base_bits = 0x02;
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS port 0x%lx not valid\n", chip->wss_base);
+ goto __skip_base;
+ }
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
+
+__skip_base:
+ switch (chip->irq) {
+ case 5:
+ irq_bits = 0x05;
+ break;
+ case 7:
+ irq_bits = 0x01;
+ break;
+ case 9:
+ irq_bits = 0x02;
+ break;
+ case 10:
+ irq_bits = 0x03;
+ break;
+ case 11:
+ irq_bits = 0x04;
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS irq # %d not valid\n", chip->irq);
+ goto __skip_resources;
+ }
+
+ switch (chip->dma1) {
+ case 0:
+ dma_bits = 0x01;
+ break;
+ case 1:
+ dma_bits = 0x02;
+ break;
+ case 3:
+ dma_bits = 0x03;
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS dma1 # %d not valid\n", chip->dma1);
+ goto __skip_resources;
+ }
+
+ if (chip->dma1 == chip->dma2) {
+ snd_printk(KERN_ERR "don't want to share dmas\n");
+ return -EBUSY;
+ }
+
+ switch (chip->dma2) {
+ case 0:
+ case 1:
+ break;
+ default:
+ snd_printk(KERN_ERR "WSS dma2 # %d not valid\n", chip->dma2);
+ goto __skip_resources;
+ }
+ dma_bits |= 0x04;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(irq_bits << 3 | dma_bits, chip->wss_base);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+__skip_resources:
+ if (chip->hardware > OPTi9XX_HW_82C928) {
+ switch (chip->mpu_port) {
+ case 0:
+ case -1:
+ break;
+ case 0x300:
+ mpu_port_bits = 0x03;
+ break;
+ case 0x310:
+ mpu_port_bits = 0x02;
+ break;
+ case 0x320:
+ mpu_port_bits = 0x01;
+ break;
+ case 0x330:
+ mpu_port_bits = 0x00;
+ break;
+ default:
+ snd_printk(KERN_ERR "MPU-401 port 0x%lx not valid\n",
+ chip->mpu_port);
+ goto __skip_mpu;
+ }
+
+ switch (chip->mpu_irq) {
+ case 5:
+ mpu_irq_bits = 0x02;
+ break;
+ case 7:
+ mpu_irq_bits = 0x03;
+ break;
+ case 9:
+ mpu_irq_bits = 0x00;
+ break;
+ case 10:
+ mpu_irq_bits = 0x01;
+ break;
+ default:
+ snd_printk(KERN_ERR "MPU-401 irq # %d not valid\n",
+ chip->mpu_irq);
+ goto __skip_mpu;
+ }
+
+ snd_miro_write_mask(chip, OPTi9XX_MC_REG(6),
+ (chip->mpu_port <= 0) ? 0x00 :
+ 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
+ 0xf8);
+ }
+__skip_mpu:
+
+ return 0;
+}
+
+static int snd_miro_opti_check(struct snd_miro *chip)
+{
+ unsigned char value;
+
+ chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size,
+ "OPTi9xx MC");
+ if (chip->res_mc_base == NULL)
+ return -ENOMEM;
+
+ value = snd_miro_read(chip, OPTi9XX_MC_REG(1));
+ if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1)))
+ if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1)))
+ return 0;
+
+ release_and_free_resource(chip->res_mc_base);
+ chip->res_mc_base = NULL;
+
+ return -ENODEV;
+}
+
+static int snd_card_miro_detect(struct snd_card *card,
+ struct snd_miro *chip)
+{
+ int i, err;
+
+ for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) {
+
+ if ((err = snd_miro_init(chip, i)) < 0)
+ return err;
+
+ err = snd_miro_opti_check(chip);
+ if (err == 0)
+ return 1;
+ }
+
+ return -ENODEV;
+}
+
+static int snd_card_miro_aci_detect(struct snd_card *card,
+ struct snd_miro *miro)
+{
+ unsigned char regval;
+ int i;
+ struct snd_miro_aci *aci = &aci_device;
+
+ miro->aci = aci;
+
+ mutex_init(&aci->aci_mutex);
+
+ /* get ACI port from OPTi9xx MC 4 */
+
+ regval=inb(miro->mc_base + 4);
+ aci->aci_port = (regval & 0x10) ? 0x344 : 0x354;
+
+ miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci");
+ if (miro->res_aci_port == NULL) {
+ snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n",
+ aci->aci_port, aci->aci_port+2);
+ return -ENOMEM;
+ }
+
+ /* force ACI into a known state */
+ for (i = 0; i < 3; i++)
+ if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) {
+ snd_printk(KERN_ERR "can't force aci into known state.\n");
+ return -ENXIO;
+ }
+
+ aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
+ aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
+ if (aci->aci_vendor < 0 || aci->aci_product < 0) {
+ snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n",
+ aci->aci_port);
+ return -ENXIO;
+ }
+
+ aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1);
+ if (aci->aci_version < 0) {
+ snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n",
+ aci->aci_port);
+ return -ENXIO;
+ }
+
+ if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 ||
+ snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
+ snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
+ snd_printk(KERN_ERR "can't initialize aci.\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void snd_card_miro_free(struct snd_card *card)
+{
+ struct snd_miro *miro = card->private_data;
+
+ release_and_free_resource(miro->res_aci_port);
+ if (miro->aci)
+ miro->aci->aci_port = 0;
+ release_and_free_resource(miro->res_mc_base);
+}
+
+static int snd_miro_probe(struct snd_card *card)
+{
+ int error;
+ struct snd_miro *miro = card->private_data;
+ struct snd_wss *codec;
+ struct snd_timer *timer;
+ struct snd_pcm *pcm;
+ struct snd_rawmidi *rmidi;
+
+ if (!miro->res_mc_base) {
+ miro->res_mc_base = request_region(miro->mc_base,
+ miro->mc_base_size,
+ "miro (OPTi9xx MC)");
+ if (miro->res_mc_base == NULL) {
+ snd_printk(KERN_ERR "request for OPTI9xx MC failed\n");
+ return -ENOMEM;
+ }
+ }
+
+ error = snd_card_miro_aci_detect(card, miro);
+ if (error < 0) {
+ snd_printk(KERN_ERR "unable to detect aci chip\n");
+ return -ENODEV;
+ }
+
+ miro->wss_base = port;
+ miro->mpu_port = mpu_port;
+ miro->irq = irq;
+ miro->mpu_irq = mpu_irq;
+ miro->dma1 = dma1;
+ miro->dma2 = dma2;
+
+ /* init proc interface */
+ snd_miro_proc_init(card, miro);
+
+ error = snd_miro_configure(miro);
+ if (error)
+ return error;
+
+ error = snd_wss_create(card, miro->wss_base + 4, -1,
+ miro->irq, miro->dma1, miro->dma2,
+ WSS_HW_DETECT, 0, &codec);
+ if (error < 0)
+ return error;
+
+ error = snd_wss_pcm(codec, 0, &pcm);
+ if (error < 0)
+ return error;
+
+ error = snd_wss_mixer(codec);
+ if (error < 0)
+ return error;
+
+ error = snd_wss_timer(codec, 0, &timer);
+ if (error < 0)
+ return error;
+
+ miro->pcm = pcm;
+
+ error = snd_miro_mixer(card, miro);
+ if (error < 0)
+ return error;
+
+ if (miro->aci->aci_vendor == 'm') {
+ /* It looks like a miro sound card. */
+ switch (miro->aci->aci_product) {
+ case 'A':
+ sprintf(card->shortname,
+ "miroSOUND PCM1 pro / PCM12");
+ break;
+ case 'B':
+ sprintf(card->shortname,
+ "miroSOUND PCM12");
+ break;
+ case 'C':
+ sprintf(card->shortname,
+ "miroSOUND PCM20 radio");
+ break;
+ default:
+ sprintf(card->shortname,
+ "unknown miro");
+ snd_printk(KERN_INFO "unknown miro aci id\n");
+ break;
+ }
+ } else {
+ snd_printk(KERN_INFO "found unsupported aci card\n");
+ sprintf(card->shortname, "unknown Cardinal Technologies");
+ }
+
+ strcpy(card->driver, "miro");
+ sprintf(card->longname, "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
+ card->shortname, miro->name, pcm->name, miro->wss_base + 4,
+ miro->irq, miro->dma1, miro->dma2);
+
+ if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
+ rmidi = NULL;
+ else {
+ error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_port, 0, miro->mpu_irq, &rmidi);
+ if (error < 0)
+ snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
+ mpu_port);
+ }
+
+ if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
+ struct snd_opl3 *opl3 = NULL;
+ struct snd_opl4 *opl4;
+
+ if (snd_opl4_create(card, fm_port, fm_port - 8,
+ 2, &opl3, &opl4) < 0)
+ snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n",
+ fm_port);
+ }
+
+ error = snd_set_aci_init_values(miro);
+ if (error < 0)
+ return error;
+
+ return snd_card_register(card);
+}
+
+static int snd_miro_isa_match(struct device *devptr, unsigned int n)
+{
+#ifdef CONFIG_PNP
+ if (snd_miro_pnp_is_probed)
+ return 0;
+ if (isapnp)
+ return 0;
+#endif
+ return 1;
+}
+
+static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
+{
+ static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
+ static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1};
+ static int possible_irqs[] = {11, 9, 10, 7, -1};
+ static int possible_mpu_irqs[] = {10, 5, 9, 7, -1};
+ static int possible_dma1s[] = {3, 1, 0, -1};
+ static int possible_dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1},
+ {0, -1} };
+
+ int error;
+ struct snd_miro *miro;
+ struct snd_card *card;
+
+ error = snd_card_new(devptr, index, id, THIS_MODULE,
+ sizeof(struct snd_miro), &card);
+ if (error < 0)
+ return error;
+
+ card->private_free = snd_card_miro_free;
+ miro = card->private_data;
+
+ error = snd_card_miro_detect(card, miro);
+ if (error < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n");
+ return -ENODEV;
+ }
+
+ if (port == SNDRV_AUTO_PORT) {
+ port = snd_legacy_find_free_ioport(possible_ports, 4);
+ if (port < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free WSS port\n");
+ return -EBUSY;
+ }
+ }
+
+ if (mpu_port == SNDRV_AUTO_PORT) {
+ mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2);
+ if (mpu_port < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR
+ "unable to find a free MPU401 port\n");
+ return -EBUSY;
+ }
+ }
+
+ if (irq == SNDRV_AUTO_IRQ) {
+ irq = snd_legacy_find_free_irq(possible_irqs);
+ if (irq < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ return -EBUSY;
+ }
+ }
+ if (mpu_irq == SNDRV_AUTO_IRQ) {
+ mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs);
+ if (mpu_irq < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR
+ "unable to find a free MPU401 IRQ\n");
+ return -EBUSY;
+ }
+ }
+ if (dma1 == SNDRV_AUTO_DMA) {
+ dma1 = snd_legacy_find_free_dma(possible_dma1s);
+ if (dma1 < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free DMA1\n");
+ return -EBUSY;
+ }
+ }
+ if (dma2 == SNDRV_AUTO_DMA) {
+ dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]);
+ if (dma2 < 0) {
+ snd_card_free(card);
+ snd_printk(KERN_ERR "unable to find a free DMA2\n");
+ return -EBUSY;
+ }
+ }
+
+ error = snd_miro_probe(card);
+ if (error < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
+ dev_set_drvdata(devptr, card);
+ return 0;
+}
+
+static int snd_miro_isa_remove(struct device *devptr,
+ unsigned int dev)
+{
+ snd_card_free(dev_get_drvdata(devptr));
+ return 0;
+}
+
+#define DEV_NAME "miro"
+
+static struct isa_driver snd_miro_driver = {
+ .match = snd_miro_isa_match,
+ .probe = snd_miro_isa_probe,
+ .remove = snd_miro_isa_remove,
+ /* FIXME: suspend/resume */
+ .driver = {
+ .name = DEV_NAME
+ },
+};
+
+#ifdef CONFIG_PNP
+
+static int snd_card_miro_pnp(struct snd_miro *chip,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *pid)
+{
+ struct pnp_dev *pdev;
+ int err;
+ struct pnp_dev *devmpu;
+ struct pnp_dev *devmc;
+
+ pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
+ if (pdev == NULL)
+ return -EBUSY;
+
+ devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
+ if (devmpu == NULL)
+ return -EBUSY;
+
+ devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
+ if (devmc == NULL)
+ return -EBUSY;
+
+ err = pnp_activate_dev(pdev);
+ if (err < 0) {
+ snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
+ return err;
+ }
+
+ err = pnp_activate_dev(devmc);
+ if (err < 0) {
+ snd_printk(KERN_ERR "MC pnp configure failure: %d\n",
+ err);
+ return err;
+ }
+
+ port = pnp_port_start(pdev, 1);
+ fm_port = pnp_port_start(pdev, 2) + 8;
+
+ /*
+ * The MC(0) is never accessed and the miroSOUND PCM20 card does not
+ * include it in the PnP resource range. OPTI93x include it.
+ */
+ chip->mc_base = pnp_port_start(devmc, 0) - 1;
+ chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
+
+ irq = pnp_irq(pdev, 0);
+ dma1 = pnp_dma(pdev, 0);
+ dma2 = pnp_dma(pdev, 1);
+
+ if (mpu_port > 0) {
+ err = pnp_activate_dev(devmpu);
+ if (err < 0) {
+ snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
+ mpu_port = -1;
+ return err;
+ }
+ mpu_port = pnp_port_start(devmpu, 0);
+ mpu_irq = pnp_irq(devmpu, 0);
+ }
+ return 0;
+}
+
+static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
+{
+ struct snd_card *card;
+ int err;
+ struct snd_miro *miro;
+
+ if (snd_miro_pnp_is_probed)
+ return -EBUSY;
+ if (!isapnp)
+ return -ENODEV;
+ err = snd_card_new(&pcard->card->dev, index, id, THIS_MODULE,
+ sizeof(struct snd_miro), &card);
+ if (err < 0)
+ return err;
+
+ card->private_free = snd_card_miro_free;
+ miro = card->private_data;
+
+ err = snd_card_miro_pnp(miro, pcard, pid);
+ if (err) {
+ snd_card_free(card);
+ return err;
+ }
+
+ /* only miroSOUND PCM20 and PCM12 == OPTi924 */
+ err = snd_miro_init(miro, OPTi9XX_HW_82C924);
+ if (err) {
+ snd_card_free(card);
+ return err;
+ }
+
+ err = snd_miro_opti_check(miro);
+ if (err) {
+ snd_printk(KERN_ERR "OPTI chip not found\n");
+ snd_card_free(card);
+ return err;
+ }
+
+ err = snd_miro_probe(card);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ pnp_set_card_drvdata(pcard, card);
+ snd_miro_pnp_is_probed = 1;
+ return 0;
+}
+
+static void snd_miro_pnp_remove(struct pnp_card_link *pcard)
+{
+ snd_card_free(pnp_get_card_drvdata(pcard));
+ pnp_set_card_drvdata(pcard, NULL);
+ snd_miro_pnp_is_probed = 0;
+}
+
+static struct pnp_card_driver miro_pnpc_driver = {
+ .flags = PNP_DRIVER_RES_DISABLE,
+ .name = "miro",
+ .id_table = snd_miro_pnpids,
+ .probe = snd_miro_pnp_probe,
+ .remove = snd_miro_pnp_remove,
+};
+#endif
+
+static int __init alsa_card_miro_init(void)
+{
+#ifdef CONFIG_PNP
+ pnp_register_card_driver(&miro_pnpc_driver);
+ if (snd_miro_pnp_is_probed)
+ return 0;
+ pnp_unregister_card_driver(&miro_pnpc_driver);
+#endif
+ return isa_register_driver(&snd_miro_driver, 1);
+}
+
+static void __exit alsa_card_miro_exit(void)
+{
+ if (!snd_miro_pnp_is_probed) {
+ isa_unregister_driver(&snd_miro_driver);
+ return;
+ }
+#ifdef CONFIG_PNP
+ pnp_unregister_card_driver(&miro_pnpc_driver);
+#endif
+}
+
+module_init(alsa_card_miro_init)
+module_exit(alsa_card_miro_exit)
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 1ea3944ef7a..c9b58284860 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -23,32 +23,23 @@
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <sound/core.h>
-#ifdef CS4231
-#include <sound/cs4231.h>
-#else
-#ifndef OPTi93X
-#include <sound/ad1848.h>
-#else
-#include <sound/control.h>
-#include <sound/pcm.h>
-#endif /* OPTi93X */
-#endif /* CS4231 */
+#include <sound/tlv.h>
+#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#ifndef OPTi93X
#include <sound/opl4.h>
#endif
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
@@ -73,8 +64,10 @@ MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (AD1848)},"
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
-//static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */
-static int isapnp = 1; /* Enable ISA PnP detection */
+//static bool enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */
+#ifdef CONFIG_PNP
+static bool isapnp = true; /* Enable ISA PnP detection */
+#endif
static long port = SNDRV_DEFAULT_PORT1; /* 0x530,0xe80,0xf40,0x604 */
static long mpu_port = SNDRV_DEFAULT_PORT1; /* 0x300,0x310,0x320,0x330 */
static long fm_port = SNDRV_DEFAULT_PORT1; /* 0x388 */
@@ -91,8 +84,10 @@ module_param(id, charp, 0444);
MODULE_PARM_DESC(id, "ID string for opti9xx based soundcard.");
//module_param(enable, bool, 0444);
//MODULE_PARM_DESC(enable, "Enable opti9xx soundcard.");
+#ifdef CONFIG_PNP
module_param(isapnp, bool, 0444);
MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
+#endif
module_param(port, long, 0444);
MODULE_PARM_DESC(port, "WSS port # for opti9xx driver.");
module_param(mpu_port, long, 0444);
@@ -110,7 +105,6 @@ module_param(dma2, int, 0444);
MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
#endif /* CS4231 || OPTi93X */
-#define OPTi9XX_HW_DETECT 0
#define OPTi9XX_HW_82C928 1
#define OPTi9XX_HW_82C929 2
#define OPTi9XX_HW_82C924 3
@@ -124,105 +118,12 @@ MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
#ifdef OPTi93X
-#define OPTi93X_INDEX 0x00
-#define OPTi93X_DATA 0x01
#define OPTi93X_STATUS 0x02
-#define OPTi93X_DDATA 0x03
#define OPTi93X_PORT(chip, r) ((chip)->port + OPTi93X_##r)
-#define OPTi93X_MIXOUT_LEFT 0x00
-#define OPTi93X_MIXOUT_RIGHT 0x01
-#define OPTi93X_CD_LEFT_INPUT 0x02
-#define OPTi93X_CD_RIGHT_INPUT 0x03
-#define OPTi930_AUX_LEFT_INPUT 0x04
-#define OPTi930_AUX_RIGHT_INPUT 0x05
-#define OPTi931_FM_LEFT_INPUT 0x04
-#define OPTi931_FM_RIGHT_INPUT 0x05
-#define OPTi93X_DAC_LEFT 0x06
-#define OPTi93X_DAC_RIGHT 0x07
-#define OPTi93X_PLAY_FORMAT 0x08
-#define OPTi93X_IFACE_CONF 0x09
-#define OPTi93X_PIN_CTRL 0x0a
-#define OPTi93X_ERR_INIT 0x0b
-#define OPTi93X_ID 0x0c
-#define OPTi93X_PLAY_UPR_CNT 0x0e
-#define OPTi93X_PLAY_LWR_CNT 0x0f
-#define OPTi931_AUX_LEFT_INPUT 0x10
-#define OPTi931_AUX_RIGHT_INPUT 0x11
-#define OPTi93X_LINE_LEFT_INPUT 0x12
-#define OPTi93X_LINE_RIGHT_INPUT 0x13
-#define OPTi93X_MIC_LEFT_INPUT 0x14
-#define OPTi93X_MIC_RIGHT_INPUT 0x15
-#define OPTi93X_OUT_LEFT 0x16
-#define OPTi93X_OUT_RIGHT 0x17
-#define OPTi93X_CAPT_FORMAT 0x1c
-#define OPTi93X_CAPT_UPR_CNT 0x1e
-#define OPTi93X_CAPT_LWR_CNT 0x1f
-
-#define OPTi93X_TRD 0x20
-#define OPTi93X_MCE 0x40
-#define OPTi93X_INIT 0x80
-
-#define OPTi93X_MIXOUT_MIC_GAIN 0x20
-#define OPTi93X_MIXOUT_LINE 0x00
-#define OPTi93X_MIXOUT_CD 0x40
-#define OPTi93X_MIXOUT_MIC 0x80
-#define OPTi93X_MIXOUT_MIXER 0xc0
-
-#define OPTi93X_STEREO 0x10
-#define OPTi93X_LINEAR_8 0x00
-#define OPTi93X_ULAW_8 0x20
-#define OPTi93X_LINEAR_16_LIT 0x40
-#define OPTi93X_ALAW_8 0x60
-#define OPTi93X_ADPCM_16 0xa0
-#define OPTi93X_LINEAR_16_BIG 0xc0
-
-#define OPTi93X_CAPTURE_PIO 0x80
-#define OPTi93X_PLAYBACK_PIO 0x40
-#define OPTi93X_AUTOCALIB 0x08
-#define OPTi93X_SINGLE_DMA 0x04
-#define OPTi93X_CAPTURE_ENABLE 0x02
-#define OPTi93X_PLAYBACK_ENABLE 0x01
-
-#define OPTi93X_IRQ_ENABLE 0x02
-
-#define OPTi93X_DMA_REQUEST 0x10
-#define OPTi93X_CALIB_IN_PROGRESS 0x20
-
#define OPTi93X_IRQ_PLAYBACK 0x04
#define OPTi93X_IRQ_CAPTURE 0x08
-
-struct snd_opti93x {
- unsigned long port;
- struct resource *res_port;
- int irq;
- int dma1;
- int dma2;
-
- struct snd_opti9xx *chip;
- unsigned short hardware;
- unsigned char image[32];
-
- unsigned char mce_bit;
- unsigned short mode;
- int mute;
-
- spinlock_t lock;
-
- struct snd_card *card;
- struct snd_pcm *pcm;
- struct snd_pcm_substream *playback_substream;
- struct snd_pcm_substream *capture_substream;
- unsigned int p_dma_size;
- unsigned int c_dma_size;
-};
-
-#define OPTi93X_MODE_NONE 0x00
-#define OPTi93X_MODE_PLAY 0x01
-#define OPTi93X_MODE_CAPTURE 0x02
-#define OPTi93X_MODE_OPEN (OPTi93X_MODE_PLAY | OPTi93X_MODE_CAPTURE)
-
#endif /* OPTi93X */
struct snd_opti9xx {
@@ -235,43 +136,35 @@ struct snd_opti9xx {
unsigned long mc_base_size;
#ifdef OPTi93X
unsigned long mc_indir_index;
+ struct resource *res_mc_indir;
#endif /* OPTi93X */
+ struct snd_wss *codec;
unsigned long pwd_reg;
spinlock_t lock;
long wss_base;
int irq;
- int dma1;
-#if defined(CS4231) || defined(OPTi93X)
- int dma2;
-#endif /* CS4231 || OPTi93X */
-
- long fm_port;
-
- long mpu_port;
- int mpu_irq;
-
-#ifdef CONFIG_PNP
- struct pnp_dev *dev;
- struct pnp_dev *devmpu;
-#endif /* CONFIG_PNP */
};
static int snd_opti9xx_pnp_is_probed;
-static struct platform_device *snd_opti9xx_platform_device;
#ifdef CONFIG_PNP
static struct pnp_card_device_id snd_opti9xx_pnpids[] = {
#ifndef OPTi93X
/* OPTi 82C924 */
- { .id = "OPT0924", .devs = { { "OPT0000" }, { "OPT0002" } }, .driver_data = 0x0924 },
+ { .id = "OPT0924",
+ .devs = { { "OPT0000" }, { "OPT0002" }, { "OPT0005" } },
+ .driver_data = 0x0924 },
/* OPTi 82C925 */
- { .id = "OPT0925", .devs = { { "OPT9250" }, { "OPT0002" } }, .driver_data = 0x0925 },
+ { .id = "OPT0925",
+ .devs = { { "OPT9250" }, { "OPT0002" }, { "OPT0005" } },
+ .driver_data = 0x0925 },
#else
/* OPTi 82C931/3 */
- { .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, .driver_data = 0x0931 },
+ { .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } },
+ .driver_data = 0x0931 },
#endif /* OPTi93X */
{ .id = "" }
};
@@ -280,65 +173,52 @@ MODULE_DEVICE_TABLE(pnp_card, snd_opti9xx_pnpids);
#endif /* CONFIG_PNP */
-#ifdef OPTi93X
-#define DRIVER_NAME "snd-card-opti93x"
-#else
-#define DRIVER_NAME "snd-card-opti92x"
-#endif /* OPTi93X */
+#define DEV_NAME KBUILD_MODNAME
static char * snd_opti9xx_names[] = {
- "unkown",
+ "unknown",
"82C928", "82C929",
"82C924", "82C925",
"82C930", "82C931", "82C933"
};
-
-static long __init snd_legacy_find_free_ioport(long *port_table, long size)
-{
- while (*port_table != -1) {
- if (request_region(*port_table, size, "ALSA test")) {
- release_region(*port_table, size);
- return *port_table;
- }
- port_table++;
- }
- return -1;
-}
-
-static int __init snd_opti9xx_init(struct snd_opti9xx *chip, unsigned short hardware)
+static int snd_opti9xx_init(struct snd_opti9xx *chip,
+ unsigned short hardware)
{
static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
chip->hardware = hardware;
strcpy(chip->name, snd_opti9xx_names[hardware]);
- chip->mc_base_size = opti9xx_mc_size[hardware];
-
spin_lock_init(&chip->lock);
- chip->wss_base = -1;
chip->irq = -1;
- chip->dma1 = -1;
-#if defined(CS4231) || defined (OPTi93X)
- chip->dma2 = -1;
-#endif /* CS4231 || OPTi93X */
- chip->fm_port = -1;
- chip->mpu_port = -1;
- chip->mpu_irq = -1;
+
+#ifndef OPTi93X
+#ifdef CONFIG_PNP
+ if (isapnp && chip->mc_base)
+ /* PnP resource gives the least 10 bits */
+ chip->mc_base |= 0xc00;
+ else
+#endif /* CONFIG_PNP */
+ {
+ chip->mc_base = 0xf8c;
+ chip->mc_base_size = opti9xx_mc_size[hardware];
+ }
+#else
+ chip->mc_base_size = opti9xx_mc_size[hardware];
+#endif
switch (hardware) {
#ifndef OPTi93X
case OPTi9XX_HW_82C928:
case OPTi9XX_HW_82C929:
- chip->mc_base = 0xf8c;
chip->password = (hardware == OPTi9XX_HW_82C928) ? 0xe2 : 0xe3;
chip->pwd_reg = 3;
break;
case OPTi9XX_HW_82C924:
case OPTi9XX_HW_82C925:
- chip->mc_base = 0xf8c;
chip->password = 0xe5;
chip->pwd_reg = 3;
break;
@@ -348,14 +228,15 @@ static int __init snd_opti9xx_init(struct snd_opti9xx *chip, unsigned short hard
case OPTi9XX_HW_82C931:
case OPTi9XX_HW_82C933:
chip->mc_base = (hardware == OPTi9XX_HW_82C930) ? 0xf8f : 0xf8d;
- chip->mc_indir_index = 0xe0e;
+ if (!chip->mc_indir_index)
+ chip->mc_indir_index = 0xe0e;
chip->password = 0xe4;
chip->pwd_reg = 0;
break;
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", hardware);
return -ENODEV;
}
return 0;
@@ -397,13 +278,13 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
}
spin_unlock_irqrestore(&chip->lock, flags);
return retval;
}
-
+
static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
unsigned char value)
{
@@ -439,7 +320,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
}
spin_unlock_irqrestore(&chip->lock, flags);
@@ -451,7 +332,10 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
(snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask)))
-static int __init snd_opti9xx_configure(struct snd_opti9xx *chip)
+static int snd_opti9xx_configure(struct snd_opti9xx *chip,
+ long port,
+ int irq, int dma1, int dma2,
+ long mpu_port, int mpu_irq)
{
unsigned char wss_base_bits;
unsigned char irq_bits;
@@ -462,16 +346,23 @@ static int __init snd_opti9xx_configure(struct snd_opti9xx *chip)
switch (chip->hardware) {
#ifndef OPTi93X
case OPTi9XX_HW_82C924:
+ /* opti 929 mode (?), OPL3 clock output, audio enable */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc);
+ /* enable wave audio */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
case OPTi9XX_HW_82C925:
+ /* enable WSS mode */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
+ /* OPL3 FM synthesis */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20);
+ /* disable Sound Blaster IRQ and DMA */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
#ifdef CS4231
+ /* cs4231/4248 fix enabled */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
#else
+ /* cs4231/4248 fix disabled */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02);
#endif /* CS4231 */
break;
@@ -492,9 +383,21 @@ static int __init snd_opti9xx_configure(struct snd_opti9xx *chip)
break;
#else /* OPTi93X */
- case OPTi9XX_HW_82C930:
case OPTi9XX_HW_82C931:
- case OPTi9XX_HW_82C933:
+ /* disable 3D sound (set GPIO1 as output, low) */
+ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c);
+ case OPTi9XX_HW_82C933: /* FALL THROUGH */
+ /*
+ * The BTC 1817DW has QS1000 wavetable which is connected
+ * to the serial digital input of the OPTI931.
+ */
+ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(21), 0x82, 0xff);
+ /*
+ * This bit sets OPTI931 to automaticaly select FM
+ * or digital input signal.
+ */
+ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
+ case OPTi9XX_HW_82C930: /* FALL THROUGH */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
@@ -505,31 +408,36 @@ static int __init snd_opti9xx_configure(struct snd_opti9xx *chip)
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
return -EINVAL;
}
- switch (chip->wss_base) {
- case 0x530:
+ /* PnP resource says it decodes only 10 bits of address */
+ switch (port & 0x3ff) {
+ case 0x130:
+ chip->wss_base = 0x530;
wss_base_bits = 0x00;
break;
- case 0x604:
+ case 0x204:
+ chip->wss_base = 0x604;
wss_base_bits = 0x03;
break;
- case 0xe80:
+ case 0x280:
+ chip->wss_base = 0xe80;
wss_base_bits = 0x01;
break;
- case 0xf40:
+ case 0x340:
+ chip->wss_base = 0xf40;
wss_base_bits = 0x02;
break;
default:
- snd_printk("WSS port 0x%lx not valid\n", chip->wss_base);
+ snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", port);
goto __skip_base;
}
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
__skip_base:
- switch (chip->irq) {
+ switch (irq) {
//#ifdef OPTi93X
case 5:
irq_bits = 0x05;
@@ -548,11 +456,11 @@ __skip_base:
irq_bits = 0x04;
break;
default:
- snd_printk("WSS irq # %d not valid\n", chip->irq);
+ snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq);
goto __skip_resources;
}
- switch (chip->dma1) {
+ switch (dma1) {
case 0:
dma_bits = 0x01;
break;
@@ -563,22 +471,22 @@ __skip_base:
dma_bits = 0x03;
break;
default:
- snd_printk("WSS dma1 # %d not valid\n", chip->dma1);
+ snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1);
goto __skip_resources;
}
#if defined(CS4231) || defined(OPTi93X)
- if (chip->dma1 == chip->dma2) {
- snd_printk("don't want to share dmas\n");
+ if (dma1 == dma2) {
+ snd_printk(KERN_ERR "don't want to share dmas\n");
return -EBUSY;
}
- switch (chip->dma2) {
+ switch (dma2) {
case 0:
case 1:
break;
default:
- snd_printk("WSS dma2 # %d not valid\n", chip->dma2);
+ snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2);
goto __skip_resources;
}
dma_bits |= 0x04;
@@ -592,7 +500,7 @@ __skip_base:
__skip_resources:
if (chip->hardware > OPTi9XX_HW_82C928) {
- switch (chip->mpu_port) {
+ switch (mpu_port) {
case 0:
case -1:
break;
@@ -609,12 +517,12 @@ __skip_resources:
mpu_port_bits = 0x00;
break;
default:
- snd_printk("MPU-401 port 0x%lx not valid\n",
- chip->mpu_port);
+ snd_printk(KERN_WARNING
+ "MPU-401 port 0x%lx not valid\n", mpu_port);
goto __skip_mpu;
}
- switch (chip->mpu_irq) {
+ switch (mpu_irq) {
case 5:
mpu_irq_bits = 0x02;
break;
@@ -628,13 +536,13 @@ __skip_resources:
mpu_irq_bits = 0x01;
break;
default:
- snd_printk("MPU-401 irq # %d not valid\n",
- chip->mpu_irq);
+ snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
+ mpu_irq);
goto __skip_mpu;
}
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6),
- (chip->mpu_port <= 0) ? 0x00 :
+ (mpu_port <= 0) ? 0x00 :
0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
0xf8);
}
@@ -645,1096 +553,227 @@ __skip_mpu:
#ifdef OPTi93X
-static unsigned char snd_opti93x_default_image[32] =
-{
- 0x00, /* 00/00 - l_mixout_outctrl */
- 0x00, /* 01/01 - r_mixout_outctrl */
- 0x88, /* 02/02 - l_cd_inctrl */
- 0x88, /* 03/03 - r_cd_inctrl */
- 0x88, /* 04/04 - l_a1/fm_inctrl */
- 0x88, /* 05/05 - r_a1/fm_inctrl */
- 0x80, /* 06/06 - l_dac_inctrl */
- 0x80, /* 07/07 - r_dac_inctrl */
- 0x00, /* 08/08 - ply_dataform_reg */
- 0x00, /* 09/09 - if_conf */
- 0x00, /* 0a/10 - pin_ctrl */
- 0x00, /* 0b/11 - err_init_reg */
- 0x0a, /* 0c/12 - id_reg */
- 0x00, /* 0d/13 - reserved */
- 0x00, /* 0e/14 - ply_upcount_reg */
- 0x00, /* 0f/15 - ply_lowcount_reg */
- 0x88, /* 10/16 - reserved/l_a1_inctrl */
- 0x88, /* 11/17 - reserved/r_a1_inctrl */
- 0x88, /* 12/18 - l_line_inctrl */
- 0x88, /* 13/19 - r_line_inctrl */
- 0x88, /* 14/20 - l_mic_inctrl */
- 0x88, /* 15/21 - r_mic_inctrl */
- 0x80, /* 16/22 - l_out_outctrl */
- 0x80, /* 17/23 - r_out_outctrl */
- 0x00, /* 18/24 - reserved */
- 0x00, /* 19/25 - reserved */
- 0x00, /* 1a/26 - reserved */
- 0x00, /* 1b/27 - reserved */
- 0x00, /* 1c/28 - cap_dataform_reg */
- 0x00, /* 1d/29 - reserved */
- 0x00, /* 1e/30 - cap_upcount_reg */
- 0x00 /* 1f/31 - cap_lowcount_reg */
-};
-
-
-static int snd_opti93x_busy_wait(struct snd_opti93x *chip)
-{
- int timeout;
-
- for (timeout = 250; timeout-- > 0; udelay(10))
- if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_INIT))
- return 0;
-
- snd_printk("chip still busy.\n");
- return -EBUSY;
-}
-
-static unsigned char snd_opti93x_in(struct snd_opti93x *chip, unsigned char reg)
-{
- snd_opti93x_busy_wait(chip);
- outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX));
- return inb(OPTi93X_PORT(chip, DATA));
-}
-
-static void snd_opti93x_out(struct snd_opti93x *chip, unsigned char reg,
- unsigned char value)
-{
- snd_opti93x_busy_wait(chip);
- outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX));
- outb(value, OPTi93X_PORT(chip, DATA));
-}
-
-static void snd_opti93x_out_image(struct snd_opti93x *chip, unsigned char reg,
- unsigned char value)
-{
- snd_opti93x_out(chip, reg, chip->image[reg] = value);
-}
-
-static void snd_opti93x_out_mask(struct snd_opti93x *chip, unsigned char reg,
- unsigned char mask, unsigned char value)
-{
- snd_opti93x_out_image(chip, reg,
- (chip->image[reg] & ~mask) | (value & mask));
-}
-
-
-static void snd_opti93x_mce_up(struct snd_opti93x *chip)
-{
- snd_opti93x_busy_wait(chip);
-
- chip->mce_bit = OPTi93X_MCE;
- if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE))
- outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX));
-}
-
-static void snd_opti93x_mce_down(struct snd_opti93x *chip)
-{
- snd_opti93x_busy_wait(chip);
-
- chip->mce_bit = 0;
- if (inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE)
- outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX));
-}
-
-#define snd_opti93x_mute_reg(chip, reg, mute) \
- snd_opti93x_out(chip, reg, mute ? 0x80 : chip->image[reg]);
-
-static void snd_opti93x_mute(struct snd_opti93x *chip, int mute)
-{
- mute = mute ? 1 : 0;
- if (chip->mute == mute)
- return;
-
- chip->mute = mute;
-
- snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_CD_RIGHT_INPUT, mute);
- switch (chip->hardware) {
- case OPTi9XX_HW_82C930:
- snd_opti93x_mute_reg(chip, OPTi930_AUX_LEFT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi930_AUX_RIGHT_INPUT, mute);
- break;
- case OPTi9XX_HW_82C931:
- case OPTi9XX_HW_82C933:
- snd_opti93x_mute_reg(chip, OPTi931_FM_LEFT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi931_FM_RIGHT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi931_AUX_LEFT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi931_AUX_RIGHT_INPUT, mute);
- }
- snd_opti93x_mute_reg(chip, OPTi93X_DAC_LEFT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_DAC_RIGHT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_LINE_LEFT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_LINE_RIGHT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_MIC_LEFT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute);
- snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute);
-}
-
-
-static unsigned int snd_opti93x_get_count(unsigned char format,
- unsigned int size)
-{
- switch (format & 0xe0) {
- case OPTi93X_LINEAR_16_LIT:
- case OPTi93X_LINEAR_16_BIG:
- size >>= 1;
- break;
- case OPTi93X_ADPCM_16:
- return size >> 2;
- }
- return (format & OPTi93X_STEREO) ? (size >> 1) : size;
-}
-
-static unsigned int rates[] = { 5512, 6615, 8000, 9600, 11025, 16000,
- 18900, 22050, 27428, 32000, 33075, 37800,
- 44100, 48000 };
-#define RATES ARRAY_SIZE(rates)
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0);
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
- .count = RATES,
- .list = rates,
- .mask = 0,
+static struct snd_kcontrol_new snd_opti93x_controls[] = {
+WSS_DOUBLE("Master Playback Switch", 0,
+ OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Master Playback Volume", 0,
+ OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
+ db_scale_5bit_3db_step),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1,
+ db_scale_5bit),
+WSS_DOUBLE_TLV("FM Playback Volume", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1,
+ db_scale_4bit_12db_max),
+WSS_DOUBLE("Line Playback Switch", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Line Playback Volume", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1,
+ db_scale_4bit_12db_max),
+WSS_DOUBLE("Mic Playback Switch", 0,
+ OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Mic Playback Volume", 0,
+ OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1,
+ db_scale_4bit_12db_max),
+WSS_DOUBLE_TLV("CD Playback Volume", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1,
+ db_scale_4bit_12db_max),
+WSS_DOUBLE("Aux Playback Switch", 0,
+ OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 0,
+ OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1,
+ db_scale_4bit_12db_max),
};
-static unsigned char bits[] = { 0x01, 0x0f, 0x00, 0x0e, 0x03, 0x02,
- 0x05, 0x07, 0x04, 0x06, 0x0d, 0x09,
- 0x0b, 0x0c};
-
-static unsigned char snd_opti93x_get_freq(unsigned int rate)
-{
- unsigned int i;
-
- for (i = 0; i < RATES; i++) {
- if (rate == rates[i])
- return bits[i];
- }
- snd_BUG();
- return bits[RATES-1];
-}
-
-static unsigned char snd_opti93x_get_format(struct snd_opti93x *chip,
- unsigned int format, int channels)
+static int snd_opti93x_mixer(struct snd_wss *chip)
{
- unsigned char retval = OPTi93X_LINEAR_8;
-
- switch (format) {
- case SNDRV_PCM_FORMAT_MU_LAW:
- retval = OPTi93X_ULAW_8;
- break;
- case SNDRV_PCM_FORMAT_A_LAW:
- retval = OPTi93X_ALAW_8;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- retval = OPTi93X_LINEAR_16_LIT;
- break;
- case SNDRV_PCM_FORMAT_S16_BE:
- retval = OPTi93X_LINEAR_16_BIG;
- break;
- case SNDRV_PCM_FORMAT_IMA_ADPCM:
- retval = OPTi93X_ADPCM_16;
- }
- return (channels > 1) ? (retval | OPTi93X_STEREO) : retval;
-}
-
-
-static void snd_opti93x_playback_format(struct snd_opti93x *chip, unsigned char fmt)
-{
- unsigned char mask;
-
- snd_opti93x_mute(chip, 1);
-
- snd_opti93x_mce_up(chip);
- mask = (chip->mode & OPTi93X_MODE_CAPTURE) ? 0xf0 : 0xff;
- snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, mask, fmt);
- snd_opti93x_mce_down(chip);
-
- snd_opti93x_mute(chip, 0);
-}
-
-static void snd_opti93x_capture_format(struct snd_opti93x *chip, unsigned char fmt)
-{
- snd_opti93x_mute(chip, 1);
-
- snd_opti93x_mce_up(chip);
- if (!(chip->mode & OPTi93X_MODE_PLAY))
- snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, 0x0f, fmt);
- else
- fmt = chip->image[OPTi93X_PLAY_FORMAT] & 0xf0;
- snd_opti93x_out_image(chip, OPTi93X_CAPT_FORMAT, fmt);
- snd_opti93x_mce_down(chip);
-
- snd_opti93x_mute(chip, 0);
-}
-
+ struct snd_card *card;
+ unsigned int idx;
+ struct snd_ctl_elem_id id1, id2;
+ int err;
-static int snd_opti93x_open(struct snd_opti93x *chip, unsigned int mode)
-{
- unsigned long flags;
+ if (snd_BUG_ON(!chip || !chip->pcm))
+ return -EINVAL;
- spin_lock_irqsave(&chip->lock, flags);
+ card = chip->card;
- if (chip->mode & mode) {
- spin_unlock_irqrestore(&chip->lock, flags);
- return -EAGAIN;
- }
+ strcpy(card->mixername, chip->pcm->name);
- if (!(chip->mode & OPTi93X_MODE_OPEN)) {
- outb(0x00, OPTi93X_PORT(chip, STATUS));
- snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL,
- OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE);
- chip->mode = mode;
+ memset(&id1, 0, sizeof(id1));
+ memset(&id2, 0, sizeof(id2));
+ id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ /* reassign AUX0 switch to CD */
+ strcpy(id1.name, "Aux Playback Switch");
+ strcpy(id2.name, "CD Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "Cannot rename opti93x control\n");
+ return err;
}
- else
- chip->mode |= mode;
-
- spin_unlock_irqrestore(&chip->lock, flags);
- return 0;
-}
-
-static void snd_opti93x_close(struct snd_opti93x *chip, unsigned int mode)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
-
- chip->mode &= ~mode;
- if (chip->mode & OPTi93X_MODE_OPEN) {
- spin_unlock_irqrestore(&chip->lock, flags);
- return;
+ /* reassign AUX1 switch to FM */
+ strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+ strcpy(id2.name, "FM Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0) {
+ snd_printk(KERN_ERR "Cannot rename opti93x control\n");
+ return err;
}
+ /* remove AUX1 volume */
+ strcpy(id1.name, "Aux Playback Volume"); id1.index = 1;
+ snd_ctl_remove_id(card, &id1);
- snd_opti93x_mute(chip, 1);
-
- outb(0, OPTi93X_PORT(chip, STATUS));
- snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE,
- ~OPTi93X_IRQ_ENABLE);
-
- snd_opti93x_mce_up(chip);
- snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00);
- snd_opti93x_mce_down(chip);
- chip->mode = 0;
-
- snd_opti93x_mute(chip, 0);
- spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static int snd_opti93x_trigger(struct snd_pcm_substream *substream,
- unsigned char what, int cmd)
-{
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
+ /* Replace WSS volume controls with OPTi93x volume controls */
+ id1.index = 0;
+ for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
+ strcpy(id1.name, snd_opti93x_controls[idx].name);
+ snd_ctl_remove_id(card, &id1);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_STOP:
- {
- unsigned int what = 0;
- struct list_head *pos;
- struct snd_pcm_substream *s;
- snd_pcm_group_for_each(pos, substream) {
- s = snd_pcm_group_substream_entry(pos);
- if (s == chip->playback_substream) {
- what |= OPTi93X_PLAYBACK_ENABLE;
- snd_pcm_trigger_done(s, substream);
- } else if (s == chip->capture_substream) {
- what |= OPTi93X_CAPTURE_ENABLE;
- snd_pcm_trigger_done(s, substream);
- }
- }
- spin_lock(&chip->lock);
- if (cmd == SNDRV_PCM_TRIGGER_START) {
- snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what);
- if (what & OPTi93X_CAPTURE_ENABLE)
- udelay(50);
- } else
- snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00);
- spin_unlock(&chip->lock);
- break;
- }
- default:
- return -EINVAL;
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_opti93x_controls[idx], chip));
+ if (err < 0)
+ return err;
}
return 0;
}
-static int snd_opti93x_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- return snd_opti93x_trigger(substream,
- OPTi93X_PLAYBACK_ENABLE, cmd);
-}
-
-static int snd_opti93x_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- return snd_opti93x_trigger(substream,
- OPTi93X_CAPTURE_ENABLE, cmd);
-}
-
-static int snd_opti93x_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
-}
-
-
-static int snd_opti93x_hw_free(struct snd_pcm_substream *substream)
-{
- snd_pcm_lib_free_pages(substream);
- return 0;
-}
-
-
-static int snd_opti93x_playback_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- unsigned char format;
- unsigned int count = snd_pcm_lib_period_bytes(substream);
- unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-
- spin_lock_irqsave(&chip->lock, flags);
-
- chip->p_dma_size = size;
- snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF,
- OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO,
- ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO));
-
- snd_dma_program(chip->dma1, runtime->dma_addr, size,
- DMA_MODE_WRITE | DMA_AUTOINIT);
-
- format = snd_opti93x_get_freq(runtime->rate);
- format |= snd_opti93x_get_format(chip, runtime->format,
- runtime->channels);
- snd_opti93x_playback_format(chip, format);
- format = chip->image[OPTi93X_PLAY_FORMAT];
-
- count = snd_opti93x_get_count(format, count) - 1;
- snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count);
- snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8);
-
- spin_unlock_irqrestore(&chip->lock, flags);
- return 0;
-}
-
-static int snd_opti93x_capture_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- unsigned char format;
- unsigned int count = snd_pcm_lib_period_bytes(substream);
- unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-
- spin_lock_irqsave(&chip->lock, flags);
-
- chip->c_dma_size = size;
- snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF,
- OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0);
-
- snd_dma_program(chip->dma2, runtime->dma_addr, size,
- DMA_MODE_READ | DMA_AUTOINIT);
-
- format = snd_opti93x_get_freq(runtime->rate);
- format |= snd_opti93x_get_format(chip, runtime->format,
- runtime->channels);
- snd_opti93x_capture_format(chip, format);
- format = chip->image[OPTi93X_CAPT_FORMAT];
-
- count = snd_opti93x_get_count(format, count) - 1;
- snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count);
- snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8);
-
- spin_unlock_irqrestore(&chip->lock, flags);
- return 0;
-}
-
-static snd_pcm_uframes_t snd_opti93x_playback_pointer(struct snd_pcm_substream *substream)
+static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
{
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
- size_t ptr;
-
- if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE))
- return 0;
-
- ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
- return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_opti93x_capture_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
- size_t ptr;
-
- if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_CAPTURE_ENABLE))
- return 0;
-
- ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
- return bytes_to_frames(substream->runtime, ptr);
-}
-
-
-static void snd_opti93x_overrange(struct snd_opti93x *chip)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
-
- if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02))
- chip->capture_substream->runtime->overrange++;
-
- spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct snd_opti93x *codec = dev_id;
+ struct snd_opti9xx *chip = dev_id;
+ struct snd_wss *codec = chip->codec;
unsigned char status;
- status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11));
+ if (!codec)
+ return IRQ_HANDLED;
+
+ status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11));
if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream)
snd_pcm_period_elapsed(codec->playback_substream);
if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) {
- snd_opti93x_overrange(codec);
+ snd_wss_overrange(codec);
snd_pcm_period_elapsed(codec->capture_substream);
}
outb(0x00, OPTi93X_PORT(codec, STATUS));
return IRQ_HANDLED;
}
+#endif /* OPTi93X */
-static struct snd_pcm_hardware snd_opti93x_playback = {
- .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
- .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
- SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
- .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 5512,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = (128*1024),
- .period_bytes_min = 64,
- .period_bytes_max = (128*1024),
- .periods_min = 1,
- .periods_max = 1024,
- .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware snd_opti93x_capture = {
- .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
- .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
- SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
- .rates = SNDRV_PCM_RATE_8000_48000,
- .rate_min = 5512,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = (128*1024),
- .period_bytes_min = 64,
- .period_bytes_max = (128*1024),
- .periods_min = 1,
- .periods_max = 1024,
- .fifo_size = 0,
-};
-
-static int snd_opti93x_playback_open(struct snd_pcm_substream *substream)
-{
- int error;
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0)
- return error;
- snd_pcm_set_sync(substream);
- chip->playback_substream = substream;
- runtime->hw = snd_opti93x_playback;
- snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
- return error;
-}
-
-static int snd_opti93x_capture_open(struct snd_pcm_substream *substream)
-{
- int error;
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0)
- return error;
- runtime->hw = snd_opti93x_capture;
- snd_pcm_set_sync(substream);
- chip->capture_substream = substream;
- snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
- return error;
-}
-
-static int snd_opti93x_playback_close(struct snd_pcm_substream *substream)
-{
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-
- chip->playback_substream = NULL;
- snd_opti93x_close(chip, OPTi93X_MODE_PLAY);
- return 0;
-}
-
-static int snd_opti93x_capture_close(struct snd_pcm_substream *substream)
-{
- struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-
- chip->capture_substream = NULL;
- snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE);
- return 0;
-}
-
-
-static void snd_opti93x_init(struct snd_opti93x *chip)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&chip->lock, flags);
- snd_opti93x_mce_up(chip);
-
- for (i = 0; i < 32; i++)
- snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]);
-
- snd_opti93x_mce_down(chip);
- spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static int snd_opti93x_probe(struct snd_opti93x *chip)
+static int snd_opti9xx_read_check(struct snd_opti9xx *chip)
{
+ unsigned char value;
+#ifdef OPTi93X
unsigned long flags;
- unsigned char val;
-
- spin_lock_irqsave(&chip->lock, flags);
- val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f;
- spin_unlock_irqrestore(&chip->lock, flags);
-
- return (val == 0x0a) ? 0 : -ENODEV;
-}
-
-static int snd_opti93x_free(struct snd_opti93x *chip)
-{
- release_and_free_resource(chip->res_port);
- if (chip->dma1 >= 0) {
- disable_dma(chip->dma1);
- free_dma(chip->dma1);
- }
- if (chip->dma2 >= 0) {
- disable_dma(chip->dma2);
- free_dma(chip->dma2);
- }
- if (chip->irq >= 0) {
- free_irq(chip->irq, chip);
- }
- kfree(chip);
- return 0;
-}
-
-static int snd_opti93x_dev_free(struct snd_device *device)
-{
- struct snd_opti93x *chip = device->device_data;
- return snd_opti93x_free(chip);
-}
-
-static const char *snd_opti93x_chip_id(struct snd_opti93x *codec)
-{
- switch (codec->hardware) {
- case OPTi9XX_HW_82C930: return "82C930";
- case OPTi9XX_HW_82C931: return "82C931";
- case OPTi9XX_HW_82C933: return "82C933";
- default: return "???";
- }
-}
+#endif
-static int snd_opti93x_create(struct snd_card *card, struct snd_opti9xx *chip,
- int dma1, int dma2,
- struct snd_opti93x **rcodec)
-{
- static struct snd_device_ops ops = {
- .dev_free = snd_opti93x_dev_free,
- };
- int error;
- struct snd_opti93x *codec;
-
- *rcodec = NULL;
- codec = kzalloc(sizeof(*codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
- codec->irq = -1;
- codec->dma1 = -1;
- codec->dma2 = -1;
-
- if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) {
- snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4);
- snd_opti93x_free(codec);
- return -EBUSY;
- }
- if (request_dma(dma1, "OPTI93x - 1")) {
- snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1);
- snd_opti93x_free(codec);
+ chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size,
+ "OPTi9xx MC");
+ if (chip->res_mc_base == NULL)
return -EBUSY;
- }
- codec->dma1 = chip->dma1;
- if (request_dma(dma2, "OPTI93x - 2")) {
- snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2);
- snd_opti93x_free(codec);
- return -EBUSY;
- }
- codec->dma2 = chip->dma2;
-
- if (request_irq(chip->irq, snd_opti93x_interrupt, SA_INTERRUPT, DRIVER_NAME" - WSS", codec)) {
- snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);
- snd_opti93x_free(codec);
+#ifndef OPTi93X
+ value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1));
+ if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1)))
+ if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)))
+ return 0;
+#else /* OPTi93X */
+ chip->res_mc_indir = request_region(chip->mc_indir_index, 2,
+ "OPTi93x MC");
+ if (chip->res_mc_indir == NULL)
return -EBUSY;
- }
-
- codec->card = card;
- codec->port = chip->wss_base + 4;
- codec->irq = chip->irq;
-
- spin_lock_init(&codec->lock);
- codec->hardware = chip->hardware;
- codec->chip = chip;
-
- if ((error = snd_opti93x_probe(codec))) {
- snd_opti93x_free(codec);
- return error;
- }
-
- snd_opti93x_init(codec);
-
- /* Register device */
- if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) {
- snd_opti93x_free(codec);
- return error;
- }
-
- *rcodec = codec;
- return 0;
-}
-
-static struct snd_pcm_ops snd_opti93x_playback_ops = {
- .open = snd_opti93x_playback_open,
- .close = snd_opti93x_playback_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_opti93x_hw_params,
- .hw_free = snd_opti93x_hw_free,
- .prepare = snd_opti93x_playback_prepare,
- .trigger = snd_opti93x_playback_trigger,
- .pointer = snd_opti93x_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_opti93x_capture_ops = {
- .open = snd_opti93x_capture_open,
- .close = snd_opti93x_capture_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_opti93x_hw_params,
- .hw_free = snd_opti93x_hw_free,
- .prepare = snd_opti93x_capture_prepare,
- .trigger = snd_opti93x_capture_trigger,
- .pointer = snd_opti93x_capture_pointer,
-};
-
-static int snd_opti93x_pcm(struct snd_opti93x *codec, int device, struct snd_pcm **rpcm)
-{
- int error;
- struct snd_pcm *pcm;
-
- if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm)))
- return error;
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops);
-
- pcm->private_data = codec;
- pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
-
- strcpy(pcm->name, snd_opti93x_chip_id(codec));
-
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_isa_data(),
- 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024);
-
- codec->pcm = pcm;
- if (rpcm)
- *rpcm = pcm;
- return 0;
-}
-
-/*
- * MIXER part
- */
-
-static int snd_opti93x_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- static char *texts[4] = {
- "Line1", "Aux", "Mic", "Mix"
- };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- 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_opti93x_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
- ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6;
- ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6;
- spin_unlock_irqrestore(&chip->lock, flags);
- return 0;
-}
-
-static int snd_opti93x_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- unsigned short left, right;
- int change;
-
- if (ucontrol->value.enumerated.item[0] > 3 ||
- ucontrol->value.enumerated.item[1] > 3)
- return -EINVAL;
- left = ucontrol->value.enumerated.item[0] << 6;
- right = ucontrol->value.enumerated.item[1] << 6;
- spin_lock_irqsave(&chip->lock, flags);
- left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left;
- right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right;
- change = left != chip->image[OPTi93X_MIXOUT_LEFT] ||
- right != chip->image[OPTi93X_MIXOUT_RIGHT];
- snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left);
- snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right);
- spin_unlock_irqrestore(&chip->lock, flags);
- return change;
-}
-
-#if 0
-
-#define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
- .info = snd_opti93x_info_single, \
- .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \
- .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
-
-static int snd_opti93x_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 16) & 0xff;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-static int snd_opti93x_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int reg = kcontrol->private_value & 0xff;
- int shift = (kcontrol->private_value >> 8) & 0xff;
- int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
-
- spin_lock_irqsave(&chip->lock, flags);
- ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
- spin_unlock_irqrestore(&chip->lock, flags);
- if (invert)
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- return 0;
-}
-
-static int snd_opti93x_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int reg = kcontrol->private_value & 0xff;
- int shift = (kcontrol->private_value >> 8) & 0xff;
- int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
- int change;
- unsigned short val;
-
- val = (ucontrol->value.integer.value[0] & mask);
- if (invert)
- val = mask - val;
- val <<= shift;
- spin_lock_irqsave(&chip->lock, flags);
- val = (chip->image[reg] & ~(mask << shift)) | val;
- change = val != chip->image[reg];
- snd_opti93x_out(chip, reg, val);
- spin_unlock_irqrestore(&chip->lock, flags);
- return change;
-}
-
-#endif /* single */
-
-#define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
- .info = snd_opti93x_info_double, \
- .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \
- .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
-
-#define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \
- do { xctl.private_value ^= 22; } while (0)
-#define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \
- do { xctl.private_value &= ~0x0000ffff; \
- xctl.private_value |= left_reg | (right_reg << 8); } while (0)
-
-static int snd_opti93x_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 24) & 0xff;
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-static int snd_opti93x_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
- int mask = (kcontrol->private_value >> 24) & 0xff;
- int invert = (kcontrol->private_value >> 22) & 1;
-
- spin_lock_irqsave(&chip->lock, flags);
- ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
- ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->lock, flags);
- if (invert) {
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
- }
- return 0;
-}
-
-static int snd_opti93x_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
- int mask = (kcontrol->private_value >> 24) & 0xff;
- int invert = (kcontrol->private_value >> 22) & 1;
- int change;
- unsigned short val1, val2;
-
- val1 = ucontrol->value.integer.value[0] & mask;
- val2 = ucontrol->value.integer.value[1] & mask;
- if (invert) {
- val1 = mask - val1;
- val2 = mask - val2;
- }
- val1 <<= shift_left;
- val2 <<= shift_right;
spin_lock_irqsave(&chip->lock, flags);
- val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
- val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
- change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
- snd_opti93x_out_image(chip, left_reg, val1);
- snd_opti93x_out_image(chip, right_reg, val2);
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+ outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base);
spin_unlock_irqrestore(&chip->lock, flags);
- return change;
-}
-static struct snd_kcontrol_new snd_opti93x_controls[] = {
-OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
-OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1),
-OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1),
-OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1),
-OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
-OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1),
-OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1),
-OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
-OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0),
-{
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = snd_opti93x_info_mux,
- .get = snd_opti93x_get_mux,
- .put = snd_opti93x_put_mux,
-}
-};
-
-static int snd_opti93x_mixer(struct snd_opti93x *chip)
-{
- struct snd_card *card;
- struct snd_kcontrol_new knew;
- int err;
- unsigned int idx;
-
- snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
-
- card = chip->card;
+ value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7));
+ snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value);
+ if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value)
+ return 0;
- strcpy(card->mixername, snd_opti93x_chip_id(chip));
+ release_and_free_resource(chip->res_mc_indir);
+ chip->res_mc_indir = NULL;
+#endif /* OPTi93X */
+ release_and_free_resource(chip->res_mc_base);
+ chip->res_mc_base = NULL;
- for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
- knew = snd_opti93x_controls[idx];
- if (chip->hardware == OPTi9XX_HW_82C930) {
- if (strstr(knew.name, "FM")) /* skip FM controls */
- continue;
- else if (strcmp(knew.name, "Mic Playback Volume"))
- OPTi93X_DOUBLE_INVERT_INVERT(knew);
- else if (strstr(knew.name, "Aux"))
- OPTi93X_DOUBLE_CHANGE_REGS(knew, OPTi930_AUX_LEFT_INPUT, OPTi930_AUX_RIGHT_INPUT);
- else if (strcmp(knew.name, "PCM Playback Volume"))
- OPTi93X_DOUBLE_INVERT_INVERT(knew);
- else if (strcmp(knew.name, "Master Playback Volume"))
- OPTi93X_DOUBLE_INVERT_INVERT(knew);
- }
- if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opti93x_controls[idx], chip))) < 0)
- return err;
- }
- return 0;
+ return -ENODEV;
}
-#endif /* OPTi93X */
-
-static int __init snd_card_opti9xx_detect(struct snd_card *card, struct snd_opti9xx *chip)
+static int snd_card_opti9xx_detect(struct snd_card *card,
+ struct snd_opti9xx *chip)
{
int i, err;
#ifndef OPTi93X
for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) {
- unsigned char value;
-
- if ((err = snd_opti9xx_init(chip, i)) < 0)
- return err;
-
- if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL)
- continue;
-
- value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1));
- if ((value != 0xff) && (value != inb(chip->mc_base + 1)))
- if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)))
- return 1;
-
- release_and_free_resource(chip->res_mc_base);
- chip->res_mc_base = NULL;
-
- }
-#else /* OPTi93X */
+#else
for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) {
- unsigned long flags;
- unsigned char value;
-
- if ((err = snd_opti9xx_init(chip, i)) < 0)
+#endif
+ err = snd_opti9xx_init(chip, i);
+ if (err < 0)
return err;
- if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL)
- continue;
-
- spin_lock_irqsave(&chip->lock, flags);
- outb(chip->password, chip->mc_base + chip->pwd_reg);
- outb(((chip->mc_indir_index & (1 << 8)) >> 4) |
- ((chip->mc_indir_index & 0xf0) >> 4), chip->mc_base);
- spin_unlock_irqrestore(&chip->lock, flags);
-
- value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7));
- snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value);
- if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value)
+ err = snd_opti9xx_read_check(chip);
+ if (err == 0)
return 1;
-
- release_and_free_resource(chip->res_mc_base);
- chip->res_mc_base = NULL;
+#ifdef OPTi93X
+ chip->mc_indir_index = 0;
+#endif
}
-#endif /* OPTi93X */
-
return -ENODEV;
}
#ifdef CONFIG_PNP
-static int __init snd_card_opti9xx_pnp(struct snd_opti9xx *chip, struct pnp_card_link *card,
- const struct pnp_card_device_id *pid)
+static int snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *pid)
{
struct pnp_dev *pdev;
- struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
int err;
+ struct pnp_dev *devmpu;
+#ifndef OPTi93X
+ struct pnp_dev *devmc;
+#endif
- chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
- if (chip->dev == NULL) {
- kfree(cfg);
+ pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
+ if (pdev == NULL)
return -EBUSY;
- }
- chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
- pdev = chip->dev;
- pnp_init_resource_table(cfg);
-
-#ifdef OPTi93X
- if (port != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port + 4, 4);
-#else
- if (pid->driver_data != 0x0924 && port != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], port, 4);
-#endif /* OPTi93X */
- if (irq != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq, 1);
- if (dma1 != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1, 1);
-#if defined(CS4231) || defined(OPTi93X)
- if (dma2 != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2, 1);
-#else
-#ifdef snd_opti9xx_fixup_dma2
- snd_opti9xx_fixup_dma2(pdev);
-#endif
-#endif /* CS4231 || OPTi93X */
-#ifdef OPTi93X
- if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], fm_port, 4);
-#else
- if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[2], fm_port, 4);
-#endif
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
- kfree(cfg);
return err;
}
#ifdef OPTi93X
port = pnp_port_start(pdev, 0) - 4;
- fm_port = pnp_port_start(pdev, 1);
+ fm_port = pnp_port_start(pdev, 1) + 8;
+ /* adjust mc_indir_index - some cards report it at 0xe?d,
+ other at 0xe?c but it really is always at 0xe?e */
+ chip->mc_indir_index = (pnp_port_start(pdev, 3) & ~0xf) | 0xe;
#else
- if (pid->driver_data != 0x0924)
- port = pnp_port_start(pdev, 1);
- fm_port = pnp_port_start(pdev, 2);
+ devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
+ if (devmc == NULL)
+ return -EBUSY;
+
+ err = pnp_activate_dev(devmc);
+ if (err < 0) {
+ snd_printk(KERN_ERR "MC pnp configure failure: %d\n", err);
+ return err;
+ }
+
+ port = pnp_port_start(pdev, 1);
+ fm_port = pnp_port_start(pdev, 2) + 8;
+ /*
+ * The MC(0) is never accessed and card does not
+ * include it in the PnP resource range. OPTI93x include it.
+ */
+ chip->mc_base = pnp_port_start(devmc, 0) - 1;
+ chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
#endif /* OPTi93X */
irq = pnp_irq(pdev, 0);
dma1 = pnp_dma(pdev, 0);
@@ -1742,28 +781,18 @@ static int __init snd_card_opti9xx_pnp(struct snd_opti9xx *chip, struct pnp_card
dma2 = pnp_dma(pdev, 1);
#endif /* CS4231 || OPTi93X */
- pdev = chip->devmpu;
- if (pdev && mpu_port > 0) {
- pnp_init_resource_table(cfg);
+ devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
- if (mpu_port != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], mpu_port, 2);
- if (mpu_irq != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], mpu_irq, 1);
-
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
+ if (devmpu && mpu_port > 0) {
+ err = pnp_activate_dev(devmpu);
if (err < 0) {
- snd_printk(KERN_ERR "AUDIO pnp configure failure\n");
+ snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
mpu_port = -1;
- chip->devmpu = NULL;
} else {
- mpu_port = pnp_port_start(pdev, 0);
- mpu_irq = pnp_irq(pdev, 0);
+ mpu_port = pnp_port_start(devmpu, 0);
+ mpu_irq = pnp_irq(devmpu, 0);
}
}
- kfree(cfg);
return pid->driver_data;
}
#endif /* CONFIG_PNP */
@@ -1771,104 +800,108 @@ static int __init snd_card_opti9xx_pnp(struct snd_opti9xx *chip, struct pnp_card
static void snd_card_opti9xx_free(struct snd_card *card)
{
struct snd_opti9xx *chip = card->private_data;
-
- if (chip)
+
+ if (chip) {
+#ifdef OPTi93X
+ if (chip->irq > 0) {
+ disable_irq(chip->irq);
+ free_irq(chip->irq, chip);
+ }
+ release_and_free_resource(chip->res_mc_indir);
+#endif
release_and_free_resource(chip->res_mc_base);
+ }
}
-static int __init snd_opti9xx_probe(struct snd_card *card)
+static int snd_opti9xx_probe(struct snd_card *card)
{
static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
int error;
+ int xdma2;
struct snd_opti9xx *chip = card->private_data;
-#if defined(OPTi93X)
- struct snd_opti93x *codec;
-#elif defined(CS4231)
- struct snd_cs4231 *codec;
+ struct snd_wss *codec;
+#ifdef CS4231
struct snd_timer *timer;
-#else
- struct snd_ad1848 *codec;
#endif
struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
struct snd_hwdep *synth;
- if (! chip->res_mc_base &&
- (chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size,
- "OPTi9xx MC")) == NULL)
- return -ENOMEM;
-
- chip->wss_base = port;
- chip->fm_port = fm_port;
- chip->mpu_port = mpu_port;
- chip->irq = irq;
- chip->mpu_irq = mpu_irq;
- chip->dma1 = dma1;
#if defined(CS4231) || defined(OPTi93X)
- chip->dma2 = dma2;
+ xdma2 = dma2;
+#else
+ xdma2 = -1;
#endif
- if (chip->wss_base == SNDRV_AUTO_PORT) {
- if ((chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) {
- snd_printk("unable to find a free WSS port\n");
+ if (port == SNDRV_AUTO_PORT) {
+ port = snd_legacy_find_free_ioport(possible_ports, 4);
+ if (port < 0) {
+ snd_printk(KERN_ERR "unable to find a free WSS port\n");
return -EBUSY;
}
}
- if ((error = snd_opti9xx_configure(chip)))
+ error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2,
+ mpu_port, mpu_irq);
+ if (error)
return error;
-#if defined(OPTi93X)
- if ((error = snd_opti93x_create(card, chip, chip->dma1, chip->dma2, &codec)))
- return error;
- if ((error = snd_opti93x_pcm(codec, 0, &pcm)) < 0)
- return error;
- if ((error = snd_opti93x_mixer(codec)) < 0)
- return error;
-#elif defined(CS4231)
- if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1,
- chip->irq, chip->dma1, chip->dma2,
- CS4231_HW_DETECT,
- 0,
- &codec)) < 0)
- return error;
- if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0)
+ error = snd_wss_create(card, chip->wss_base + 4, -1, irq, dma1, xdma2,
+#ifdef OPTi93X
+ WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
+#else
+ WSS_HW_DETECT, 0,
+#endif
+ &codec);
+ if (error < 0)
return error;
- if ((error = snd_cs4231_mixer(codec)) < 0)
+ chip->codec = codec;
+ error = snd_wss_pcm(codec, 0, &pcm);
+ if (error < 0)
return error;
- if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0)
+ error = snd_wss_mixer(codec);
+ if (error < 0)
return error;
-#else
- if ((error = snd_ad1848_create(card, chip->wss_base + 4,
- chip->irq, chip->dma1,
- AD1848_HW_DETECT, &codec)) < 0)
+#ifdef OPTi93X
+ error = snd_opti93x_mixer(codec);
+ if (error < 0)
return error;
- if ((error = snd_ad1848_pcm(codec, 0, &pcm)) < 0)
+#endif
+#ifdef CS4231
+ error = snd_wss_timer(codec, 0, &timer);
+ if (error < 0)
return error;
- if ((error = snd_ad1848_mixer(codec)) < 0)
+#endif
+#ifdef OPTi93X
+ error = request_irq(irq, snd_opti93x_interrupt,
+ 0, DEV_NAME" - WSS", chip);
+ if (error < 0) {
+ snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", irq);
return error;
+ }
#endif
+ chip->irq = irq;
strcpy(card->driver, chip->name);
sprintf(card->shortname, "OPTi %s", card->driver);
#if defined(CS4231) || defined(OPTi93X)
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, pcm->name, chip->wss_base + 4,
- chip->irq, chip->dma1, chip->dma2);
+ card->shortname, pcm->name,
+ chip->wss_base + 4, irq, dma1, xdma2);
#else
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
- card->shortname, pcm->name, chip->wss_base + 4,
- chip->irq, chip->dma1);
+ card->shortname, pcm->name, chip->wss_base + 4, irq, dma1);
#endif /* CS4231 || OPTi93X */
- if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT)
+ if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
rmidi = NULL;
- else
- if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
- chip->mpu_port, 0, chip->mpu_irq, SA_INTERRUPT,
- &rmidi)))
+ else {
+ error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_port, 0, mpu_irq, &rmidi);
+ if (error)
snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
- chip->mpu_port);
+ mpu_port);
+ }
- if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
+ if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
struct snd_opl3 *opl3 = NULL;
#ifndef OPTi93X
if (chip->hardware == OPTi9XX_HW_82C928 ||
@@ -1878,9 +911,7 @@ static int __init snd_opti9xx_probe(struct snd_card *card)
/* assume we have an OPL4 */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
0x20, 0x20);
- if (snd_opl4_create(card,
- chip->fm_port,
- chip->fm_port - 8,
+ if (snd_opl4_create(card, fm_port, fm_port - 8,
2, &opl3, &opl4) < 0) {
/* no luck, use OPL3 instead */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
@@ -1888,22 +919,14 @@ static int __init snd_opti9xx_probe(struct snd_card *card)
}
}
#endif /* !OPTi93X */
- if (!opl3 && snd_opl3_create(card,
- chip->fm_port,
- chip->fm_port + 2,
+ if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
- chip->fm_port, chip->fm_port + 4 - 1);
+ fm_port, fm_port + 4 - 1);
}
if (opl3) {
-#ifdef CS4231
- const int t1dev = 1;
-#else
- const int t1dev = 0;
-#endif
- if ((error = snd_opl3_timer_new(opl3, t1dev, t1dev+1)) < 0)
- return error;
- if ((error = snd_opl3_hwdep_new(opl3, 0, 1, &synth)) < 0)
+ error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
+ if (error < 0)
return error;
}
}
@@ -1911,18 +934,34 @@ static int __init snd_opti9xx_probe(struct snd_card *card)
return snd_card_register(card);
}
-static struct snd_card *snd_opti9xx_card_new(void)
+static int snd_opti9xx_card_new(struct device *pdev, struct snd_card **cardp)
{
struct snd_card *card;
+ int err;
- card = snd_card_new(index, id, THIS_MODULE, sizeof(struct snd_opti9xx));
- if (! card)
- return NULL;
+ err = snd_card_new(pdev, index, id, THIS_MODULE,
+ sizeof(struct snd_opti9xx), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_card_opti9xx_free;
- return card;
+ *cardp = card;
+ return 0;
}
-static int __init snd_opti9xx_nonpnp_probe(struct platform_device *devptr)
+static int snd_opti9xx_isa_match(struct device *devptr,
+ unsigned int dev)
+{
+#ifdef CONFIG_PNP
+ if (snd_opti9xx_pnp_is_probed)
+ return 0;
+ if (isapnp)
+ return 0;
+#endif
+ return 1;
+}
+
+static int snd_opti9xx_isa_probe(struct device *devptr,
+ unsigned int dev)
{
struct snd_card *card;
int error;
@@ -1938,9 +977,6 @@ static int __init snd_opti9xx_nonpnp_probe(struct platform_device *devptr)
static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}};
#endif /* CS4231 || OPTi93X */
- if (snd_opti9xx_pnp_is_probed)
- return -EBUSY;
-
if (mpu_port == SNDRV_AUTO_PORT) {
if ((mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) {
snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
@@ -1968,48 +1004,92 @@ static int __init snd_opti9xx_nonpnp_probe(struct platform_device *devptr)
#if defined(CS4231) || defined(OPTi93X)
if (dma2 == SNDRV_AUTO_DMA) {
if ((dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4])) < 0) {
- snd_printk("unable to find a free DMA2\n");
+ snd_printk(KERN_ERR "unable to find a free DMA2\n");
return -EBUSY;
}
}
#endif
- card = snd_opti9xx_card_new();
- if (! card)
- return -ENOMEM;
+ error = snd_opti9xx_card_new(devptr, &card);
+ if (error < 0)
+ return error;
if ((error = snd_card_opti9xx_detect(card, card->private_data)) < 0) {
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &devptr->dev);
if ((error = snd_opti9xx_probe(card)) < 0) {
snd_card_free(card);
return error;
}
- platform_set_drvdata(devptr, card);
+ dev_set_drvdata(devptr, card);
return 0;
}
-static int __devexit snd_opti9xx_nonpnp_remove(struct platform_device *devptr)
+static int snd_opti9xx_isa_remove(struct device *devptr,
+ unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_opti9xx_suspend(struct snd_card *card)
+{
+ struct snd_opti9xx *chip = card->private_data;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ chip->codec->suspend(chip->codec);
+ return 0;
+}
+
+static int snd_opti9xx_resume(struct snd_card *card)
+{
+ struct snd_opti9xx *chip = card->private_data;
+ int error, xdma2;
+#if defined(CS4231) || defined(OPTi93X)
+ xdma2 = dma2;
+#else
+ xdma2 = -1;
+#endif
+
+ error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2,
+ mpu_port, mpu_irq);
+ if (error)
+ return error;
+ chip->codec->resume(chip->codec);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
-static struct platform_driver snd_opti9xx_driver = {
- .probe = snd_opti9xx_nonpnp_probe,
- .remove = __devexit_p(snd_opti9xx_nonpnp_remove),
- /* FIXME: suspend/resume */
+static int snd_opti9xx_isa_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
+{
+ return snd_opti9xx_suspend(dev_get_drvdata(dev));
+}
+
+static int snd_opti9xx_isa_resume(struct device *dev, unsigned int n)
+{
+ return snd_opti9xx_resume(dev_get_drvdata(dev));
+}
+#endif
+
+static struct isa_driver snd_opti9xx_driver = {
+ .match = snd_opti9xx_isa_match,
+ .probe = snd_opti9xx_isa_probe,
+ .remove = snd_opti9xx_isa_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_opti9xx_isa_suspend,
+ .resume = snd_opti9xx_isa_resume,
+#endif
.driver = {
- .name = DRIVER_NAME
+ .name = DEV_NAME
},
};
#ifdef CONFIG_PNP
-static int __init snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
struct snd_card *card;
int error, hw;
@@ -2019,9 +1099,9 @@ static int __init snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
return -EBUSY;
if (! isapnp)
return -ENODEV;
- card = snd_opti9xx_card_new();
- if (! card)
- return -ENOMEM;
+ error = snd_opti9xx_card_new(&pcard->card->dev, &card);
+ if (error < 0)
+ return error;
chip = card->private_data;
hw = snd_card_opti9xx_pnp(chip, pcard, pid);
@@ -2044,9 +1124,12 @@ static int __init snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
snd_card_free(card);
return error;
}
- if (hw <= OPTi9XX_HW_82C930)
- chip->mc_base -= 0x80;
- snd_card_set_dev(card, &pcard->card->dev);
+ error = snd_opti9xx_read_check(chip);
+ if (error) {
+ snd_printk(KERN_ERR "OPTI chip not found\n");
+ snd_card_free(card);
+ return error;
+ }
if ((error = snd_opti9xx_probe(card)) < 0) {
snd_card_free(card);
return error;
@@ -2056,27 +1139,39 @@ static int __init snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
return 0;
}
-static void __devexit snd_opti9xx_pnp_remove(struct pnp_card_link * pcard)
+static void snd_opti9xx_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
snd_opti9xx_pnp_is_probed = 0;
}
+#ifdef CONFIG_PM
+static int snd_opti9xx_pnp_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ return snd_opti9xx_suspend(pnp_get_card_drvdata(pcard));
+}
+
+static int snd_opti9xx_pnp_resume(struct pnp_card_link *pcard)
+{
+ return snd_opti9xx_resume(pnp_get_card_drvdata(pcard));
+}
+#endif
+
static struct pnp_card_driver opti9xx_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
- .name = "opti9xx",
+ .name = DEV_NAME,
.id_table = snd_opti9xx_pnpids,
.probe = snd_opti9xx_pnp_probe,
- .remove = __devexit_p(snd_opti9xx_pnp_remove),
+ .remove = snd_opti9xx_pnp_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_opti9xx_pnp_suspend,
+ .resume = snd_opti9xx_pnp_resume,
+#endif
};
#endif
-#ifdef CONFIG_PNP
-#define is_isapnp_selected() isapnp
-#else
-#define is_isapnp_selected() 0
-#endif
#ifdef OPTi93X
#define CHIP_NAME "82C93x"
#else
@@ -2085,37 +1180,24 @@ static struct pnp_card_driver opti9xx_pnpc_driver = {
static int __init alsa_card_opti9xx_init(void)
{
- int error;
- struct platform_device *device;
-
+#ifdef CONFIG_PNP
pnp_register_card_driver(&opti9xx_pnpc_driver);
if (snd_opti9xx_pnp_is_probed)
return 0;
- if (! is_isapnp_selected()) {
- error = platform_driver_register(&snd_opti9xx_driver);
- if (error < 0)
- return error;
- device = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
- if (!IS_ERR(device)) {
- snd_opti9xx_platform_device = device;
- return 0;
- }
- platform_driver_unregister(&snd_opti9xx_driver);
- }
pnp_unregister_card_driver(&opti9xx_pnpc_driver);
-#ifdef MODULE
- printk(KERN_ERR "no OPTi " CHIP_NAME " soundcard found\n");
#endif
- return -ENODEV;
+ return isa_register_driver(&snd_opti9xx_driver, 1);
}
static void __exit alsa_card_opti9xx_exit(void)
{
if (!snd_opti9xx_pnp_is_probed) {
- platform_device_unregister(snd_opti9xx_platform_device);
- platform_driver_unregister(&snd_opti9xx_driver);
+ isa_unregister_driver(&snd_opti9xx_driver);
+ return;
}
+#ifdef CONFIG_PNP
pnp_unregister_card_driver(&opti9xx_pnpc_driver);
+#endif
}
module_init(alsa_card_opti9xx_init)
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
index fd9d9c5726f..08b9fb97465 100644
--- a/sound/isa/sb/Makefile
+++ b/sound/isa/sb/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
snd-sb-common-objs := sb_common.o sb_mixer.o
@@ -11,29 +11,18 @@ snd-sb8-objs := sb8.o
snd-sb16-objs := sb16.o
snd-sbawe-objs := sbawe.o emu8000.o
snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
-snd-es968-objs := es968.o
-
-#
-# this function returns:
-# "m" - CONFIG_SND_SEQUENCER is m
-# <empty string> - CONFIG_SND_SEQUENCER is undefined
-# otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
+snd-jazz16-objs := jazz16.o
# Toplevel Module Dependency
-obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
+obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
+obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o
+obj-$(CONFIG_SND_SB8_DSP) += snd-sb8-dsp.o
+obj-$(CONFIG_SND_SB8) += snd-sb8.o
+obj-$(CONFIG_SND_SB16) += snd-sb16.o
+obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
+obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o
ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
endif
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o
-
-obj-m := $(sort $(obj-m))
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emu8000-synth.o
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index c0b8d61b75e..45fcdff611f 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
* Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
*
@@ -20,11 +20,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
+#include <linux/export.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/emu8000.h>
@@ -131,7 +131,7 @@ snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode)
/*
*/
-static void __init
+static void
snd_emu8000_read_wait(struct snd_emu8000 *emu)
{
while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
@@ -143,7 +143,7 @@ snd_emu8000_read_wait(struct snd_emu8000 *emu)
/*
*/
-static void __init
+static void
snd_emu8000_write_wait(struct snd_emu8000 *emu)
{
while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
@@ -156,7 +156,7 @@ snd_emu8000_write_wait(struct snd_emu8000 *emu)
/*
* detect a card at the given port
*/
-static int __init
+static int
snd_emu8000_detect(struct snd_emu8000 *emu)
{
/* Initialise */
@@ -182,7 +182,7 @@ snd_emu8000_detect(struct snd_emu8000 *emu)
/*
* intiailize audio channels
*/
-static void __init
+static void
init_audio(struct snd_emu8000 *emu)
{
int ch;
@@ -223,7 +223,7 @@ init_audio(struct snd_emu8000 *emu)
/*
* initialize DMA address
*/
-static void __init
+static void
init_dma(struct snd_emu8000 *emu)
{
EMU8000_SMALR_WRITE(emu, 0);
@@ -235,7 +235,7 @@ init_dma(struct snd_emu8000 *emu)
/*
* initialization arrays; from ADIP
*/
-static unsigned short init1[128] /*__devinitdata*/ = {
+static unsigned short init1[128] = {
0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
@@ -257,7 +257,7 @@ static unsigned short init1[128] /*__devinitdata*/ = {
0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
};
-static unsigned short init2[128] /*__devinitdata*/ = {
+static unsigned short init2[128] = {
0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
@@ -279,7 +279,7 @@ static unsigned short init2[128] /*__devinitdata*/ = {
0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
};
-static unsigned short init3[128] /*__devinitdata*/ = {
+static unsigned short init3[128] = {
0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
@@ -301,7 +301,7 @@ static unsigned short init3[128] /*__devinitdata*/ = {
0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
};
-static unsigned short init4[128] /*__devinitdata*/ = {
+static unsigned short init4[128] = {
0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
@@ -327,7 +327,7 @@ static unsigned short init4[128] /*__devinitdata*/ = {
* Taken from the oss driver, not obvious from the doc how this
* is meant to work
*/
-static void __init
+static void
send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
{
int i;
@@ -349,7 +349,7 @@ send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
* Send initialization arrays to start up, this just follows the
* initialisation sequence in the adip.
*/
-static void __init
+static void
init_arrays(struct snd_emu8000 *emu)
{
send_array(emu, init1, ARRAY_SIZE(init1)/4);
@@ -371,19 +371,20 @@ init_arrays(struct snd_emu8000 *emu)
/*
* Size the onboard memory.
- * This is written so as not to need arbitary delays after the write. It
+ * This is written so as not to need arbitrary delays after the write. It
* seems that the only way to do this is to use the one channel and keep
* reallocating between read and write.
*/
-static void __init
+static void
size_dram(struct snd_emu8000 *emu)
{
- int i, size;
+ int i, size, detected_size;
if (emu->dram_checked)
return;
size = 0;
+ detected_size = 0;
/* write out a magic number */
snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
@@ -415,8 +416,7 @@ size_dram(struct snd_emu8000 *emu)
/*snd_emu8000_read_wait(emu);*/
EMU8000_SMLD_READ(emu); /* discard stale data */
if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
- break; /* we must have wrapped around */
-
+ break; /* no memory at this address */
snd_emu8000_read_wait(emu);
/*
@@ -429,6 +429,18 @@ size_dram(struct snd_emu8000 *emu)
if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
break; /* we must have wrapped around */
snd_emu8000_read_wait(emu);
+
+ /* Otherwise, it's valid memory. */
+ detected_size = size + 512 * 1024;
+ }
+
+ /* Distinguish 512 KiB from 0. */
+ if (detected_size == 0) {
+ snd_emu8000_read_wait(emu);
+ EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
+ EMU8000_SMLD_READ(emu); /* discard stale data */
+ if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1)
+ detected_size = 512 * 1024;
}
/* wait until FULL bit in SMAxW register is false */
@@ -443,9 +455,9 @@ size_dram(struct snd_emu8000 *emu)
snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
- emu->port1, size/1024);
+ emu->port1, detected_size/1024);
- emu->mem_size = size;
+ emu->mem_size = detected_size;
emu->dram_checked = 1;
}
@@ -500,7 +512,7 @@ snd_emu8000_init_fm(struct snd_emu8000 *emu)
/*
* The main initialization routine.
*/
-static void __init
+static void
snd_emu8000_init_hw(struct snd_emu8000 *emu)
{
int i;
@@ -1019,12 +1031,13 @@ static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
/*
* create and attach mixer elements for WaveTable treble/bass controls
*/
-static int __init
+static int
snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
{
int i, err = 0;
- snd_assert(emu != NULL && card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!emu || !card))
+ return -EINVAL;
spin_lock_init(&emu->control_lock);
@@ -1069,7 +1082,7 @@ static int snd_emu8000_dev_free(struct snd_device *device)
/*
* initialize and register emu8000 synth device.
*/
-int __init
+int
snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
struct snd_seq_device **awe_ret)
{
diff --git a/sound/isa/sb/emu8000_callback.c b/sound/isa/sb/emu8000_callback.c
index 9a3c71cc2e0..72a9ac5efb4 100644
--- a/sound/isa/sb/emu8000_callback.c
+++ b/sound/isa/sb/emu8000_callback.c
@@ -20,6 +20,7 @@
*/
#include "emu8000_local.h"
+#include <linux/export.h>
#include <sound/asoundef.h>
/*
@@ -174,7 +175,7 @@ get_voice(struct snd_emux *emu, struct snd_emux_port *port)
hw = emu->hw;
for (i = 0; i < END; i++) {
- best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */;
+ best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */
best[i].voice = -1;
}
diff --git a/sound/isa/sb/emu8000_local.h b/sound/isa/sb/emu8000_local.h
index 2ac77f10bb4..7e87c349272 100644
--- a/sound/isa/sb/emu8000_local.h
+++ b/sound/isa/sb/emu8000_local.h
@@ -21,7 +21,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 80b1cf84a1a..c99c6078be3 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -23,7 +23,7 @@
#include <asm/uaccess.h>
#include <linux/moduleparam.h>
-static int emu8000_reset_addr = 0;
+static int emu8000_reset_addr;
module_param(emu8000_reset_addr, int, 0444);
MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)");
@@ -156,7 +156,8 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
struct snd_emu8000 *emu;
emu = rec->hw;
- snd_assert(sp != NULL, return -EINVAL);
+ if (snd_BUG_ON(!sp))
+ return -EINVAL;
if (sp->v.size == 0)
return 0;
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
index 91dc3d83e2c..2f85c66f8e3 100644
--- a/sound/isa/sb/emu8000_pcm.c
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -20,6 +20,7 @@
#include "emu8000_local.h"
#include <linux/init.h>
+#include <linux/slab.h>
#include <sound/initval.h>
#include <sound/pcm.h>
@@ -432,7 +433,8 @@ static int emu8k_transfer_block(struct snd_emu8000 *emu, int offset, unsigned sh
while (count > 0) {
unsigned short sval;
CHECK_SCHEDULER();
- get_user(sval, buf);
+ if (get_user(sval, buf))
+ return -EFAULT;
EMU8000_SMLD_WRITE(emu, sval);
buf++;
count--;
@@ -524,12 +526,14 @@ static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
while (count-- > 0) {
unsigned short sval;
CHECK_SCHEDULER();
- get_user(sval, buf);
+ if (get_user(sval, buf))
+ return -EFAULT;
EMU8000_SMLD_WRITE(emu, sval);
buf++;
if (rec->voices > 1) {
CHECK_SCHEDULER();
- get_user(sval, buf);
+ if (get_user(sval, buf))
+ return -EFAULT;
EMU8000_SMRD_WRITE(emu, sval);
buf++;
}
diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c
index 3d72742b342..4e3fcfb15ad 100644
--- a/sound/isa/sb/emu8000_synth.c
+++ b/sound/isa/sb/emu8000_synth.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
* Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
*
@@ -22,6 +22,7 @@
#include "emu8000_local.h"
#include <linux/init.h>
+#include <linux/module.h>
#include <sound/initval.h>
MODULE_AUTHOR("Takashi Iwai, Steve Ratcliffe");
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
deleted file mode 100644
index 9da80bfa302..00000000000
--- a/sound/isa/sb/es968.c
+++ /dev/null
@@ -1,266 +0,0 @@
-
-/*
- card-es968.c - driver for ESS AudioDrive ES968 based soundcards.
- Copyright (C) 1999 by Massimo Piccioni <dafastidio@libero.it>
-
- Thanks to Pierfrancesco 'qM2' Passerini.
-
- 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 <linux/init.h>
-#include <linux/time.h>
-#include <linux/pnp.h>
-#include <linux/moduleparam.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/sb.h>
-
-#define PFX "es968: "
-
-MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
-MODULE_DESCRIPTION("ESS AudioDrive ES968");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESS,AudioDrive ES968}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
-static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
-static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for es968 based soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for es968 based soundcard.");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable es968 based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for es968 driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for es968 driver.");
-module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for es968 driver.");
-
-struct snd_card_es968 {
- struct pnp_dev *dev;
- struct snd_sb *chip;
-};
-
-static struct pnp_card_device_id snd_es968_pnpids[] = {
- { .id = "ESS0968", .devs = { { "@@@0968" }, } },
- { .id = "", } /* end */
-};
-
-MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids);
-
-#define DRIVER_NAME "snd-card-es968"
-
-static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
-{
- struct snd_sb *chip = dev_id;
-
- if (chip->open & SB_OPEN_PCM) {
- return snd_sb8dsp_interrupt(chip);
- } else {
- return snd_sb8dsp_midi_interrupt(chip);
- }
-}
-
-static int __devinit snd_card_es968_pnp(int dev, struct snd_card_es968 *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
-{
- struct pnp_dev *pdev;
- struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
- int err;
- if (!cfg)
- return -ENOMEM;
- acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->dev == NULL) {
- kfree(cfg);
- return -ENODEV;
- }
-
- pdev = acard->dev;
-
- pnp_init_resource_table(cfg);
-
- /* override resources */
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
- if (dma8[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
- err = pnp_activate_dev(pdev);
- if (err < 0) {
- snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
- kfree(cfg);
- return err;
- }
- port[dev] = pnp_port_start(pdev, 0);
- dma8[dev] = pnp_dma(pdev, 1);
- irq[dev] = pnp_irq(pdev, 0);
-
- kfree(cfg);
- return 0;
-}
-
-static int __init snd_card_es968_probe(int dev,
- struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
-{
- int error;
- struct snd_sb *chip;
- struct snd_card *card;
- struct snd_card_es968 *acard;
-
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_es968))) == NULL)
- return -ENOMEM;
- acard = card->private_data;
- if ((error = snd_card_es968_pnp(dev, acard, pcard, pid))) {
- snd_card_free(card);
- return error;
- }
- snd_card_set_dev(card, &pcard->card->dev);
-
- if ((error = snd_sbdsp_create(card, port[dev],
- irq[dev],
- snd_card_es968_interrupt,
- dma8[dev],
- -1,
- SB_HW_AUTO, &chip)) < 0) {
- snd_card_free(card);
- return error;
- }
- acard->chip = chip;
-
- if ((error = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) {
- snd_card_free(card);
- return error;
- }
-
- if ((error = snd_sbmixer_new(chip)) < 0) {
- snd_card_free(card);
- return error;
- }
-
- if ((error = snd_sb8dsp_midi(chip, 0, NULL)) < 0) {
- snd_card_free(card);
- return error;
- }
-
- strcpy(card->driver, "ES968");
- strcpy(card->shortname, "ESS ES968");
- sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d",
- card->shortname, chip->name, chip->port, irq[dev], dma8[dev]);
-
- if ((error = snd_card_register(card)) < 0) {
- snd_card_free(card);
- return error;
- }
- pnp_set_card_drvdata(pcard, card);
- return 0;
-}
-
-static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
-{
- static int dev;
- int res;
-
- for ( ; dev < SNDRV_CARDS; dev++) {
- if (!enable[dev])
- continue;
- res = snd_card_es968_probe(dev, card, id);
- if (res < 0)
- return res;
- dev++;
- return 0;
- }
- return -ENODEV;
-}
-
-static void __devexit snd_es968_pnp_remove(struct pnp_card_link * pcard)
-{
- snd_card_free(pnp_get_card_drvdata(pcard));
- pnp_set_card_drvdata(pcard, NULL);
-}
-
-#ifdef CONFIG_PM
-static int snd_es968_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
-{
- struct snd_card *card = pnp_get_card_drvdata(pcard);
- struct snd_card_es968 *acard = card->private_data;
- struct snd_sb *chip = acard->chip;
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- snd_pcm_suspend_all(chip->pcm);
- snd_sbmixer_suspend(chip);
- return 0;
-}
-
-static int snd_es968_pnp_resume(struct pnp_card_link *pcard)
-{
- struct snd_card *card = pnp_get_card_drvdata(pcard);
- struct snd_card_es968 *acard = card->private_data;
- struct snd_sb *chip = acard->chip;
-
- snd_sbdsp_reset(chip);
- snd_sbmixer_resume(chip);
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-#endif
-
-static struct pnp_card_driver es968_pnpc_driver = {
- .flags = PNP_DRIVER_RES_DISABLE,
- .name = "es968",
- .id_table = snd_es968_pnpids,
- .probe = snd_es968_pnp_detect,
- .remove = __devexit_p(snd_es968_pnp_remove),
-#ifdef CONFIG_PM
- .suspend = snd_es968_pnp_suspend,
- .resume = snd_es968_pnp_resume,
-#endif
-};
-
-static int __init alsa_card_es968_init(void)
-{
- int cards = pnp_register_card_driver(&es968_pnpc_driver);
- if (cards <= 0) {
- pnp_unregister_card_driver(&es968_pnpc_driver);
-#ifdef MODULE
- snd_printk(KERN_ERR "no ES968 based soundcards found\n");
-#endif
- return -ENODEV;
- }
- return 0;
-}
-
-static void __exit alsa_card_es968_exit(void)
-{
- pnp_unregister_card_driver(&es968_pnpc_driver);
-}
-
-module_init(alsa_card_es968_init)
-module_exit(alsa_card_es968_exit)
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c
new file mode 100644
index 00000000000..90d2eba549e
--- /dev/null
+++ b/sound/isa/sb/jazz16.c
@@ -0,0 +1,401 @@
+
+/*
+ * jazz16.c - driver for Media Vision Jazz16 based soundcards.
+ * Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
+ * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman.
+ * Based on OSS Sound Blaster driver.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <asm/dma.h>
+#include <linux/isa.h>
+#include <sound/core.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+#include <sound/sb.h>
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+
+#define PFX "jazz16: "
+
+MODULE_DESCRIPTION("Media Vision Jazz16");
+MODULE_SUPPORTED_DEVICE("{{Media Vision ??? },"
+ "{RTL,RTL3000}}");
+
+MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for jazz16 driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver.");
+module_param_array(dma8, int, NULL, 0444);
+MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver.");
+module_param_array(dma16, int, NULL, 0444);
+MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver.");
+
+#define SB_JAZZ16_WAKEUP 0xaf
+#define SB_JAZZ16_SET_PORTS 0x50
+#define SB_DSP_GET_JAZZ_BRD_REV 0xfa
+#define SB_JAZZ16_SET_DMAINTR 0xfb
+#define SB_DSP_GET_JAZZ_MODEL 0xfe
+
+struct snd_card_jazz16 {
+ struct snd_sb *chip;
+};
+
+static irqreturn_t jazz16_interrupt(int irq, void *chip)
+{
+ return snd_sb8dsp_interrupt(chip);
+}
+
+static int jazz16_configure_ports(unsigned long port,
+ unsigned long mpu_port, int idx)
+{
+ unsigned char val;
+
+ if (!request_region(0x201, 1, "jazz16 config")) {
+ snd_printk(KERN_ERR "config port region is already in use.\n");
+ return -EBUSY;
+ }
+ outb(SB_JAZZ16_WAKEUP - idx, 0x201);
+ udelay(100);
+ outb(SB_JAZZ16_SET_PORTS + idx, 0x201);
+ udelay(100);
+ val = port & 0x70;
+ val |= (mpu_port & 0x30) >> 4;
+ outb(val, 0x201);
+
+ release_region(0x201, 1);
+ return 0;
+}
+
+static int jazz16_detect_board(unsigned long port,
+ unsigned long mpu_port)
+{
+ int err;
+ int val;
+ struct snd_sb chip;
+
+ if (!request_region(port, 0x10, "jazz16")) {
+ snd_printk(KERN_ERR "I/O port region is already in use.\n");
+ return -EBUSY;
+ }
+ /* just to call snd_sbdsp_command/reset/get_byte() */
+ chip.port = port;
+
+ err = snd_sbdsp_reset(&chip);
+ if (err < 0)
+ for (val = 0; val < 4; val++) {
+ err = jazz16_configure_ports(port, mpu_port, val);
+ if (err < 0)
+ break;
+
+ err = snd_sbdsp_reset(&chip);
+ if (!err)
+ break;
+ }
+ if (err < 0) {
+ err = -ENODEV;
+ goto err_unmap;
+ }
+ if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) {
+ err = -EBUSY;
+ goto err_unmap;
+ }
+ val = snd_sbdsp_get_byte(&chip);
+ if (val >= 0x30)
+ snd_sbdsp_get_byte(&chip);
+
+ if ((val & 0xf0) != 0x10) {
+ err = -ENODEV;
+ goto err_unmap;
+ }
+ if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) {
+ err = -EBUSY;
+ goto err_unmap;
+ }
+ snd_sbdsp_get_byte(&chip);
+ err = snd_sbdsp_get_byte(&chip);
+ snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
+ val, err);
+
+ err = 0;
+
+err_unmap:
+ release_region(port, 0x10);
+ return err;
+}
+
+static int jazz16_configure_board(struct snd_sb *chip, int mpu_irq)
+{
+ static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4,
+ 0, 2, 5, 0, 0, 0, 0, 6 };
+ static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 };
+
+ if (jazz_dma_bits[chip->dma8] == 0 ||
+ jazz_dma_bits[chip->dma16] == 0 ||
+ jazz_irq_bits[chip->irq] == 0)
+ return -EINVAL;
+
+ if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR))
+ return -EBUSY;
+
+ if (!snd_sbdsp_command(chip,
+ jazz_dma_bits[chip->dma8] |
+ (jazz_dma_bits[chip->dma16] << 4)))
+ return -EBUSY;
+
+ if (!snd_sbdsp_command(chip,
+ jazz_irq_bits[chip->irq] |
+ (jazz_irq_bits[mpu_irq] << 4)))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int snd_jazz16_match(struct device *devptr, unsigned int dev)
+{
+ if (!enable[dev])
+ return 0;
+ if (port[dev] == SNDRV_AUTO_PORT) {
+ snd_printk(KERN_ERR "please specify port\n");
+ return 0;
+ } else if (port[dev] == 0x200 || (port[dev] & ~0x270)) {
+ snd_printk(KERN_ERR "incorrect port specified\n");
+ return 0;
+ }
+ if (dma8[dev] != SNDRV_AUTO_DMA &&
+ dma8[dev] != 1 && dma8[dev] != 3) {
+ snd_printk(KERN_ERR "dma8 must be 1 or 3\n");
+ return 0;
+ }
+ if (dma16[dev] != SNDRV_AUTO_DMA &&
+ dma16[dev] != 5 && dma16[dev] != 7) {
+ snd_printk(KERN_ERR "dma16 must be 5 or 7\n");
+ return 0;
+ }
+ if (mpu_port[dev] != SNDRV_AUTO_PORT &&
+ (mpu_port[dev] & ~0x030) != 0x300) {
+ snd_printk(KERN_ERR "incorrect mpu_port specified\n");
+ return 0;
+ }
+ if (mpu_irq[dev] != SNDRV_AUTO_DMA &&
+ mpu_irq[dev] != 2 && mpu_irq[dev] != 3 &&
+ mpu_irq[dev] != 5 && mpu_irq[dev] != 7) {
+ snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n");
+ return 0;
+ }
+ return 1;
+}
+
+static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
+{
+ struct snd_card *card;
+ struct snd_card_jazz16 *jazz16;
+ struct snd_sb *chip;
+ struct snd_opl3 *opl3;
+ static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1};
+ static int possible_dmas8[] = {1, 3, -1};
+ static int possible_dmas16[] = {5, 7, -1};
+ int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
+
+ err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_jazz16), &card);
+ if (err < 0)
+ return err;
+
+ jazz16 = card->private_data;
+
+ xirq = irq[dev];
+ if (xirq == SNDRV_AUTO_IRQ) {
+ xirq = snd_legacy_find_free_irq(possible_irqs);
+ if (xirq < 0) {
+ snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ err = -EBUSY;
+ goto err_free;
+ }
+ }
+ xdma8 = dma8[dev];
+ if (xdma8 == SNDRV_AUTO_DMA) {
+ xdma8 = snd_legacy_find_free_dma(possible_dmas8);
+ if (xdma8 < 0) {
+ snd_printk(KERN_ERR "unable to find a free DMA8\n");
+ err = -EBUSY;
+ goto err_free;
+ }
+ }
+ xdma16 = dma16[dev];
+ if (xdma16 == SNDRV_AUTO_DMA) {
+ xdma16 = snd_legacy_find_free_dma(possible_dmas16);
+ if (xdma16 < 0) {
+ snd_printk(KERN_ERR "unable to find a free DMA16\n");
+ err = -EBUSY;
+ goto err_free;
+ }
+ }
+
+ xmpu_port = mpu_port[dev];
+ if (xmpu_port == SNDRV_AUTO_PORT)
+ xmpu_port = 0;
+ err = jazz16_detect_board(port[dev], xmpu_port);
+ if (err < 0) {
+ printk(KERN_ERR "Media Vision Jazz16 board not detected\n");
+ goto err_free;
+ }
+ err = snd_sbdsp_create(card, port[dev], irq[dev],
+ jazz16_interrupt,
+ dma8[dev], dma16[dev],
+ SB_HW_JAZZ16,
+ &chip);
+ if (err < 0)
+ goto err_free;
+
+ xmpu_irq = mpu_irq[dev];
+ if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT)
+ xmpu_irq = 0;
+ err = jazz16_configure_board(chip, xmpu_irq);
+ if (err < 0) {
+ printk(KERN_ERR "Media Vision Jazz16 configuration failed\n");
+ goto err_free;
+ }
+
+ jazz16->chip = chip;
+
+ strcpy(card->driver, "jazz16");
+ strcpy(card->shortname, "Media Vision Jazz16");
+ sprintf(card->longname,
+ "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
+ port[dev], xirq, xdma8, xdma16);
+
+ err = snd_sb8dsp_pcm(chip, 0, NULL);
+ if (err < 0)
+ goto err_free;
+ err = snd_sbmixer_new(chip);
+ if (err < 0)
+ goto err_free;
+
+ err = snd_opl3_create(card, chip->port, chip->port + 2,
+ OPL3_HW_AUTO, 1, &opl3);
+ if (err < 0)
+ snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
+ chip->port, chip->port + 2);
+ else {
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ goto err_free;
+ }
+ if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
+ if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
+ mpu_irq[dev] = -1;
+
+ if (snd_mpu401_uart_new(card, 0,
+ MPU401_HW_MPU401,
+ mpu_port[dev], 0,
+ mpu_irq[dev],
+ NULL) < 0)
+ snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
+ mpu_port[dev]);
+ }
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto err_free;
+
+ dev_set_drvdata(devptr, card);
+ return 0;
+
+err_free:
+ snd_card_free(card);
+ return err;
+}
+
+static int snd_jazz16_remove(struct device *devptr, unsigned int dev)
+{
+ struct snd_card *card = dev_get_drvdata(devptr);
+
+ snd_card_free(card);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_jazz16_suspend(struct device *pdev, unsigned int n,
+ pm_message_t state)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_card_jazz16 *acard = card->private_data;
+ struct snd_sb *chip = acard->chip;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend_all(chip->pcm);
+ snd_sbmixer_suspend(chip);
+ return 0;
+}
+
+static int snd_jazz16_resume(struct device *pdev, unsigned int n)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct snd_card_jazz16 *acard = card->private_data;
+ struct snd_sb *chip = acard->chip;
+
+ snd_sbdsp_reset(chip);
+ snd_sbmixer_resume(chip);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
+static struct isa_driver snd_jazz16_driver = {
+ .match = snd_jazz16_match,
+ .probe = snd_jazz16_probe,
+ .remove = snd_jazz16_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_jazz16_suspend,
+ .resume = snd_jazz16_resume,
+#endif
+ .driver = {
+ .name = "jazz16"
+ },
+};
+
+static int __init alsa_card_jazz16_init(void)
+{
+ return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_jazz16_exit(void)
+{
+ isa_unregister_driver(&snd_jazz16_driver);
+}
+
+module_init(alsa_card_jazz16_init)
+module_exit(alsa_card_jazz16_exit)
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index c0be7a5a342..3f694543a7e 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -1,6 +1,6 @@
/*
* Driver for SoundBlaster 16/AWE32/AWE64 soundcards
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,14 +19,12 @@
*
*/
-#include <sound/driver.h>
#include <asm/dma.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/pnp.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/moduleparam.h>
+#include <linux/isa.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/sb16_csp.h>
@@ -44,7 +42,7 @@
#define PFX "sb16: "
#endif
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
#ifndef SNDRV_SBAWE
MODULE_DESCRIPTION("Sound Blaster 16");
@@ -70,9 +68,9 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32},"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
#ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#endif
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x330,0x300 */
@@ -85,7 +83,7 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */
static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
#ifdef CONFIG_SND_SB16_CSP
-static int csp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int csp[SNDRV_CARDS];
#endif
#ifdef SNDRV_SBAWE_EMU8000
static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
@@ -128,8 +126,8 @@ module_param_array(seq_ports, int, NULL, 0444);
MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth.");
#endif
-static struct platform_device *platform_devices[SNDRV_CARDS];
#ifdef CONFIG_PNP
+static int isa_registered;
static int pnp_registered;
#endif
@@ -179,6 +177,8 @@ static struct pnp_card_device_id snd_sb16_pnpids[] = {
{ .id = "CTL0086", .devs = { { "CTL0041" } } },
/* Sound Blaster Vibra16X */
{ .id = "CTL00f0", .devs = { { "CTL0043" } } },
+ /* Sound Blaster 16 (Virtual PC 2004) */
+ { .id = "tBA03b0", .devs = { {.id="PNPb003" } } },
#else /* SNDRV_SBAWE defined */
/* Sound Blaster AWE 32 PnP */
{ .id = "CTL0035", .devs = { { "CTL0031" }, { "CTL0021" } } },
@@ -235,8 +235,6 @@ static struct pnp_card_device_id snd_sb16_pnpids[] = {
{ .id = "CTLXXXX" , .devs = { { "CTL0044" }, { "CTL0023" } } },
{ .id = "CTLXXXX" , .devs = { { "CTL0045" }, { "CTL0022" } } },
#endif /* SNDRV_SBAWE */
- /* Sound Blaster 16 PnP (Virtual PC 2004)*/
- { .id = "tBA03b0", .devs = { { "PNPb003" } } },
{ .id = "", }
};
@@ -252,49 +250,26 @@ MODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids);
#ifdef CONFIG_PNP
-static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
int err;
- if (!cfg)
- return -ENOMEM;
acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->dev == NULL) {
- kfree(cfg);
+ if (acard->dev == NULL)
return -ENODEV;
- }
+
#ifdef SNDRV_SBAWE_EMU8000
acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev);
#endif
/* Audio initialization */
pdev = acard->dev;
- pnp_init_resource_table(cfg);
-
- /* override resources */
-
- if (port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
- if (mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], mpu_port[dev], 2);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4);
- if (dma8[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
- if (dma16[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1);
- if (irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
- kfree(cfg);
return err;
}
port[dev] = pnp_port_start(pdev, 0);
@@ -311,23 +286,13 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
/* WaveTable initialization */
pdev = acard->devwt;
if (pdev != NULL) {
- pnp_init_resource_table(cfg);
-
- /* override resources */
-
- if (awe_port[dev] != SNDRV_AUTO_PORT) {
- pnp_resource_change(&cfg->port_resource[0], awe_port[dev], 4);
- pnp_resource_change(&cfg->port_resource[1], awe_port[dev] + 0x400, 4);
- pnp_resource_change(&cfg->port_resource[2], awe_port[dev] + 0x800, 4);
- }
- if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
- snd_printk(KERN_ERR PFX "WaveTable the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
goto __wt_error;
}
awe_port[dev] = pnp_port_start(pdev, 0);
- snd_printdd("pnp SB16: wavetable port=0x%lx\n", pnp_port_start(pdev, 0));
+ snd_printdd("pnp SB16: wavetable port=0x%llx\n",
+ (unsigned long long)pnp_port_start(pdev, 0));
} else {
__wt_error:
if (pdev) {
@@ -338,7 +303,6 @@ __wt_error:
awe_port[dev] = -1;
}
#endif
- kfree(cfg);
return 0;
}
@@ -359,17 +323,22 @@ static void snd_sb16_free(struct snd_card *card)
#define is_isapnp_selected(dev) 0
#endif
-static struct snd_card *snd_sb16_card_new(int dev)
+static int snd_sb16_card_new(struct device *devptr, int dev,
+ struct snd_card **cardp)
{
- struct snd_card *card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_sb16));
- if (card == NULL)
- return NULL;
+ struct snd_card *card;
+ int err;
+
+ err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_sb16), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_sb16_free;
- return card;
+ *cardp = card;
+ return 0;
}
-static int __init snd_sb16_probe(struct snd_card *card, int dev)
+static int snd_sb16_probe(struct snd_card *card, int dev)
{
int xirq, xdma8, xdma16;
struct snd_sb *chip;
@@ -426,8 +395,9 @@ static int __init snd_sb16_probe(struct snd_card *card, int dev)
if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB,
- chip->mpu_port, 0,
- xirq, 0, &chip->rmidi)) < 0)
+ chip->mpu_port,
+ MPU401_INFO_IRQ_HOOK, -1,
+ &chip->rmidi)) < 0)
return err;
chip->rmidi_callback = snd_mpu401_uart_interrupt;
}
@@ -518,15 +488,15 @@ static int snd_sb16_resume(struct snd_card *card)
}
#endif
-static int __init snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr)
+static int snd_sb16_isa_probe1(int dev, struct device *pdev)
{
struct snd_card_sb16 *acard;
struct snd_card *card;
int err;
- card = snd_sb16_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_sb16_card_new(pdev, dev, &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
/* non-PnP FM port address is hardwired with base port address */
@@ -538,19 +508,22 @@ static int __init snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr
awe_port[dev] = port[dev] + 0x400;
#endif
- snd_card_set_dev(card, &devptr->dev);
if ((err = snd_sb16_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
}
- platform_set_drvdata(devptr, card);
+ dev_set_drvdata(pdev, card);
return 0;
}
-static int __init snd_sb16_nonpnp_probe(struct platform_device *pdev)
+static int snd_sb16_isa_match(struct device *pdev, unsigned int dev)
+{
+ return enable[dev] && !is_isapnp_selected(dev);
+}
+
+static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
{
- int dev = pdev->id;
int err;
static int possible_irqs[] = {5, 9, 10, 7, -1};
static int possible_dmas8[] = {1, 3, 0, -1};
@@ -576,13 +549,13 @@ static int __init snd_sb16_nonpnp_probe(struct platform_device *pdev)
}
if (port[dev] != SNDRV_AUTO_PORT)
- return snd_sb16_nonpnp_probe1(dev, pdev);
+ return snd_sb16_isa_probe1(dev, pdev);
else {
static int possible_ports[] = {0x220, 0x240, 0x260, 0x280};
int i;
for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
port[dev] = possible_ports[i];
- err = snd_sb16_nonpnp_probe1(dev, pdev);
+ err = snd_sb16_isa_probe1(dev, pdev);
if (! err)
return 0;
}
@@ -590,48 +563,48 @@ static int __init snd_sb16_nonpnp_probe(struct platform_device *pdev)
}
}
-static int __devexit snd_sb16_nonpnp_remove(struct platform_device *devptr)
+static int snd_sb16_isa_remove(struct device *pdev, unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(pdev));
return 0;
}
#ifdef CONFIG_PM
-static int snd_sb16_nonpnp_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_sb16_isa_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
{
- return snd_sb16_suspend(platform_get_drvdata(dev), state);
+ return snd_sb16_suspend(dev_get_drvdata(dev), state);
}
-static int snd_sb16_nonpnp_resume(struct platform_device *dev)
+static int snd_sb16_isa_resume(struct device *dev, unsigned int n)
{
- return snd_sb16_resume(platform_get_drvdata(dev));
+ return snd_sb16_resume(dev_get_drvdata(dev));
}
#endif
#ifdef SNDRV_SBAWE
-#define SND_SB16_DRIVER "snd_sbawe"
+#define DEV_NAME "sbawe"
#else
-#define SND_SB16_DRIVER "snd_sb16"
+#define DEV_NAME "sb16"
#endif
-static struct platform_driver snd_sb16_nonpnp_driver = {
- .probe = snd_sb16_nonpnp_probe,
- .remove = __devexit_p(snd_sb16_nonpnp_remove),
+static struct isa_driver snd_sb16_isa_driver = {
+ .match = snd_sb16_isa_match,
+ .probe = snd_sb16_isa_probe,
+ .remove = snd_sb16_isa_remove,
#ifdef CONFIG_PM
- .suspend = snd_sb16_nonpnp_suspend,
- .resume = snd_sb16_nonpnp_resume,
+ .suspend = snd_sb16_isa_suspend,
+ .resume = snd_sb16_isa_resume,
#endif
.driver = {
- .name = SND_SB16_DRIVER
+ .name = DEV_NAME
},
};
#ifdef CONFIG_PNP
-
-static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_sb16_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
static int dev;
struct snd_card *card;
@@ -640,10 +613,9 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard,
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev] || !isapnp[dev])
continue;
- card = snd_sb16_card_new(dev);
- if (! card)
- return -ENOMEM;
- snd_card_set_dev(card, &pcard->card->dev);
+ res = snd_sb16_card_new(&pcard->card->dev, dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 ||
(res = snd_sb16_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -657,7 +629,7 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard,
return -ENODEV;
}
-static void __devexit snd_sb16_pnp_remove(struct pnp_card_link * pcard)
+static void snd_sb16_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -683,7 +655,7 @@ static struct pnp_card_driver sb16_pnpc_driver = {
#endif
.id_table = snd_sb16_pnpids,
.probe = snd_sb16_pnp_detect,
- .remove = __devexit_p(snd_sb16_pnp_remove),
+ .remove = snd_sb16_pnp_remove,
#ifdef CONFIG_PM
.suspend = snd_sb16_pnp_suspend,
.resume = snd_sb16_pnp_resume,
@@ -692,70 +664,33 @@ static struct pnp_card_driver sb16_pnpc_driver = {
#endif /* CONFIG_PNP */
-static void __init_or_module snd_sb16_unregister_all(void)
-{
- int i;
-
-#ifdef CONFIG_PNP
- if (pnp_registered)
- pnp_unregister_card_driver(&sb16_pnpc_driver);
-#endif
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&snd_sb16_nonpnp_driver);
-}
-
static int __init alsa_card_sb16_init(void)
{
- int i, err, cards = 0;
-
- if ((err = platform_driver_register(&snd_sb16_nonpnp_driver)) < 0)
- return err;
+ int err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- if (is_isapnp_selected(i))
- continue;
- device = platform_device_register_simple(SND_SB16_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- cards++;
- }
+ err = isa_register_driver(&snd_sb16_isa_driver, SNDRV_CARDS);
#ifdef CONFIG_PNP
- /* PnP cards at last */
- i = pnp_register_card_driver(&sb16_pnpc_driver);
- if (i >= 0) {
+ if (!err)
+ isa_registered = 1;
+
+ err = pnp_register_card_driver(&sb16_pnpc_driver);
+ if (!err)
pnp_registered = 1;
- cards += i;
- }
-#endif
- if (!cards) {
-#ifdef MODULE
- snd_printk(KERN_ERR "Sound Blaster 16 soundcard not found or device busy\n");
-#ifdef SNDRV_SBAWE_EMU8000
- snd_printk(KERN_ERR "In case, if you have non-AWE card, try snd-sb16 module\n");
-#else
- snd_printk(KERN_ERR "In case, if you have AWE card, try snd-sbawe module\n");
-#endif
+ if (isa_registered)
+ err = 0;
#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_sb16_unregister_all();
return err;
}
static void __exit alsa_card_sb16_exit(void)
{
- snd_sb16_unregister_all();
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&sb16_pnpc_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_sb16_isa_driver);
}
module_init(alsa_card_sb16_init)
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 9c2b5efbacb..48da2276683 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -23,10 +23,10 @@
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
@@ -36,6 +36,11 @@
MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
MODULE_DESCRIPTION("ALSA driver for SB16 Creative Signal Processor");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("sb16/mulaw_main.csp");
+MODULE_FIRMWARE("sb16/alaw_main.csp");
+MODULE_FIRMWARE("sb16/ima_adpcm_init.csp");
+MODULE_FIRMWARE("sb16/ima_adpcm_playback.csp");
+MODULE_FIRMWARE("sb16/ima_adpcm_capture.csp");
#ifdef SNDRV_LITTLE_ENDIAN
#define CSP_HDR_VALUE(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
@@ -111,7 +116,8 @@ static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buff
int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
{
struct snd_sb_csp *p;
- int version, err;
+ int uninitialized_var(version);
+ int err;
struct snd_hwdep *hw;
if (rhwdep)
@@ -138,7 +144,7 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
p->ops.csp_stop = snd_sb_csp_stop;
p->ops.csp_qsound_transfer = snd_sb_csp_qsound_transfer;
- init_MUTEX(&p->access_mutex);
+ mutex_init(&p->access_mutex);
sprintf(hw->name, "CSP v%d.%d", (version >> 4), (version & 0x0f));
hw->iface = SNDRV_HWDEP_IFACE_SB16CSP;
hw->private_data = p;
@@ -161,10 +167,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);
}
}
@@ -190,7 +199,8 @@ static int snd_sb_csp_ioctl(struct snd_hwdep * hw, struct file *file, unsigned i
struct snd_sb_csp_start start_info;
int err;
- snd_assert(p != NULL, return -EINVAL);
+ if (snd_BUG_ON(!p))
+ return -EINVAL;
if (snd_sb_csp_check_version(p))
return -ENODEV;
@@ -198,6 +208,7 @@ static int snd_sb_csp_ioctl(struct snd_hwdep * hw, struct file *file, unsigned i
switch (cmd) {
/* get information */
case SNDRV_SB_CSP_IOCTL_INFO:
+ memset(&info, 0, sizeof(info));
*info.codec_name = *p->codec_name;
info.func_nr = p->func_nr;
info.acc_format = p->acc_format;
@@ -265,13 +276,13 @@ static int snd_sb_csp_release(struct snd_hwdep * hw, struct file *file)
*/
static int snd_sb_csp_use(struct snd_sb_csp * p)
{
- down(&p->access_mutex);
+ mutex_lock(&p->access_mutex);
if (p->used) {
- up(&p->access_mutex);
+ mutex_unlock(&p->access_mutex);
return -EAGAIN;
}
p->used++;
- up(&p->access_mutex);
+ mutex_unlock(&p->access_mutex);
return 0;
@@ -282,9 +293,9 @@ static int snd_sb_csp_use(struct snd_sb_csp * p)
*/
static int snd_sb_csp_unuse(struct snd_sb_csp * p)
{
- down(&p->access_mutex);
+ mutex_lock(&p->access_mutex);
p->used--;
- up(&p->access_mutex);
+ mutex_unlock(&p->access_mutex);
return 0;
}
@@ -317,7 +328,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
return -EFAULT;
if ((file_h.name != RIFF_HEADER) ||
(le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {
- snd_printd("%s: Invalid RIFF header\n", __FUNCTION__);
+ snd_printd("%s: Invalid RIFF header\n", __func__);
return -EINVAL;
}
data_ptr += sizeof(file_h);
@@ -326,7 +337,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
return -EFAULT;
if (item_type != CSP__HEADER) {
- snd_printd("%s: Invalid RIFF file type\n", __FUNCTION__);
+ snd_printd("%s: Invalid RIFF file type\n", __func__);
return -EINVAL;
}
data_ptr += sizeof (item_type);
@@ -381,7 +392,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
return -EFAULT;
if (code_h.name != MAIN_HEADER) {
- snd_printd("%s: Missing 'main' microcode\n", __FUNCTION__);
+ snd_printd("%s: Missing 'main' microcode\n", __func__);
return -EINVAL;
}
data_ptr += sizeof(code_h);
@@ -425,7 +436,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
p->acc_format = p->acc_width = p->acc_rates = 0;
p->mode = 0;
snd_printd("%s: Unsupported CSP codec type: 0x%04x\n",
- __FUNCTION__,
+ __func__,
le16_to_cpu(funcdesc_h.VOC_type));
return -EINVAL;
}
@@ -444,7 +455,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
return 0;
}
}
- snd_printd("%s: Function #%d not found\n", __FUNCTION__, info.func_req);
+ snd_printd("%s: Function #%d not found\n", __func__, info.func_req);
return -EINVAL;
}
@@ -598,7 +609,7 @@ static int get_version(struct snd_sb *chip)
static int snd_sb_csp_check_version(struct snd_sb_csp * p)
{
if (p->version < 0x10 || p->version > 0x1f) {
- snd_printd("%s: Invalid CSP version: 0x%x\n", __FUNCTION__, p->version);
+ snd_printd("%s: Invalid CSP version: 0x%x\n", __func__, p->version);
return 1;
}
return 0;
@@ -617,7 +628,7 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int
spin_lock_irqsave(&p->chip->reg_lock, flags);
snd_sbdsp_command(p->chip, 0x01); /* CSP download command */
if (snd_sbdsp_get_byte(p->chip)) {
- snd_printd("%s: Download command failed\n", __FUNCTION__);
+ snd_printd("%s: Download command failed\n", __func__);
goto __fail;
}
/* Send CSP low byte (size - 1) */
@@ -644,7 +655,7 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int
udelay (10);
}
if (status != 0x55) {
- snd_printd("%s: Microcode initialization failed\n", __FUNCTION__);
+ snd_printd("%s: Microcode initialization failed\n", __func__);
goto __fail;
}
} else {
@@ -675,19 +686,41 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int
static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags)
{
- int err = -ENOMEM;
- unsigned char *kbuf = kmalloc(size, GFP_KERNEL);
- if (kbuf) {
- if (copy_from_user(kbuf, buf, size))
- err = -EFAULT;
- else
- err = snd_sb_csp_load(p, kbuf, size, load_flags);
- kfree(kbuf);
- }
+ int err;
+ unsigned char *kbuf;
+
+ kbuf = memdup_user(buf, size);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
+
+ err = snd_sb_csp_load(p, kbuf, size, load_flags);
+
+ kfree(kbuf);
return err;
}
-#include "sb16_csp_codecs.h"
+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;
+
+ BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);
+ program = p->csp_programs[index];
+ if (!program) {
+ int err = request_firmware(&program, names[index],
+ p->chip->card->dev);
+ if (err < 0)
+ return err;
+ p->csp_programs[index] = program;
+ }
+ return snd_sb_csp_load(p, program->data, program->size, flags);
+}
/*
* autoload hardware codec if necessary
@@ -708,27 +741,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;
@@ -773,19 +806,19 @@ static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channel
unsigned long flags;
if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) {
- snd_printd("%s: Microcode not loaded\n", __FUNCTION__);
+ snd_printd("%s: Microcode not loaded\n", __func__);
return -ENXIO;
}
if (p->running & SNDRV_SB_CSP_ST_RUNNING) {
- snd_printd("%s: CSP already running\n", __FUNCTION__);
+ snd_printd("%s: CSP already running\n", __func__);
return -EBUSY;
}
if (!(sample_width & p->acc_width)) {
- snd_printd("%s: Unsupported PCM sample width\n", __FUNCTION__);
+ snd_printd("%s: Unsupported PCM sample width\n", __func__);
return -EINVAL;
}
if (!(channels & p->acc_channels)) {
- snd_printd("%s: Invalid number of channels\n", __FUNCTION__);
+ snd_printd("%s: Invalid number of channels\n", __func__);
return -EINVAL;
}
@@ -807,11 +840,11 @@ static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channel
s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */
if (set_codec_parameter(p->chip, 0x81, s_type)) {
- snd_printd("%s: Set sample type command failed\n", __FUNCTION__);
+ snd_printd("%s: Set sample type command failed\n", __func__);
goto __fail;
}
if (set_codec_parameter(p->chip, 0x80, 0x00)) {
- snd_printd("%s: Codec start command failed\n", __FUNCTION__);
+ snd_printd("%s: Codec start command failed\n", __func__);
goto __fail;
}
p->run_width = sample_width;
@@ -928,14 +961,7 @@ static int snd_sb_csp_restart(struct snd_sb_csp * p)
* QSound mixer control for PCM
*/
-static int snd_sb_qsound_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;
-}
+#define snd_sb_qsound_switch_info snd_ctl_boolean_mono_info
static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -1024,7 +1050,8 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p)
struct snd_card *card;
int err;
- snd_assert(p != NULL, return -EINVAL);
+ if (snd_BUG_ON(!p))
+ return -EINVAL;
card = p->chip->card;
p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2;
@@ -1049,7 +1076,8 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p)
struct snd_card *card;
unsigned long flags;
- snd_assert(p != NULL, return);
+ if (snd_BUG_ON(!p))
+ return;
card = p->chip->card;
@@ -1101,7 +1129,7 @@ static int init_proc_entry(struct snd_sb_csp * p, int device)
struct snd_info_entry *entry;
sprintf(name, "cspD%d", device);
if (! snd_card_proc_new(p->chip->card, name, &entry))
- snd_info_set_text_ops(entry, p, 1024, info_read);
+ snd_info_set_text_ops(entry, p, info_read);
return 0;
}
diff --git a/sound/isa/sb/sb16_csp_codecs.h b/sound/isa/sb/sb16_csp_codecs.h
deleted file mode 100644
index f0e8b0dcb57..00000000000
--- a/sound/isa/sb/sb16_csp_codecs.h
+++ /dev/null
@@ -1,949 +0,0 @@
-/*
- * Copyright (c) 1994 Creative Technology Ltd.
- * Microcode files for SB16 Advanced Signal Processor
- *
- * 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
- *
- */
-
-static unsigned char mulaw_main[] = {
- 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
- 0x00, 0xb1, 0x00, 0x44, 0x00, 0x61, 0x00, 0x44,
- 0x08, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
- 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
- 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
- 0x50, 0x05, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0f, 0xd4, 0x49,
- 0x20, 0x01, 0x09, 0x0e, 0x20, 0x00, 0x71, 0x8b,
- 0xa8, 0x01, 0xa8, 0x80, 0x88, 0x01, 0xa8, 0x80,
- 0xa8, 0x00, 0x00, 0x80, 0xd2, 0x00, 0x71, 0x8b,
- 0x88, 0x00, 0xa8, 0x80, 0xa8, 0x04, 0xb3, 0x80,
- 0x20, 0x07, 0xb3, 0x80, 0x88, 0x03, 0xb1, 0x80,
- 0xc0, 0x00, 0x09, 0x5c, 0xc2, 0x01, 0x00, 0x82,
- 0xa1, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x04, 0x19,
- 0xa2, 0x20, 0x71, 0x8b, 0xcf, 0x00, 0x04, 0x19,
- 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x00, 0x04, 0x19,
- 0x00, 0x40, 0x00, 0x14, 0x08, 0x40, 0x04, 0x24,
- 0x00, 0x00, 0x34, 0x49, 0x0c, 0x40, 0x00, 0x44,
- 0x44, 0x04, 0x04, 0x39, 0x00, 0x00, 0x40, 0x45,
- 0x32, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x0c, 0x39,
- 0x00, 0x00, 0x40, 0x45, 0x40, 0x40, 0x09, 0xef,
- 0xff, 0x20, 0x09, 0xcf, 0x00, 0x04, 0x63, 0xa1,
- 0x50, 0x03, 0x33, 0x80, 0x00, 0x04, 0xa3, 0x80,
- 0x00, 0xff, 0xc2, 0x8b, 0x00, 0xd0, 0x04, 0x54,
- 0x04, 0xe0, 0x00, 0xc4, 0x20, 0x03, 0x80, 0xc0,
- 0x30, 0x00, 0x00, 0x88, 0x00, 0x00, 0x7a, 0x0a,
- 0xd0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
- 0xc0, 0x00, 0x00, 0x99, 0x00, 0x60, 0x00, 0x44,
- 0x00, 0xff, 0xc2, 0x8b, 0x20, 0x00, 0x00, 0x80,
- 0x00, 0x0d, 0x42, 0x8b, 0x08, 0x32, 0x00, 0xc4,
- 0x00, 0x0e, 0x42, 0x8b, 0x00, 0xa2, 0x00, 0xc4,
- 0x00, 0x1e, 0x42, 0x8b, 0x0c, 0xb2, 0x00, 0xc4,
- 0x00, 0x8e, 0x42, 0x8b, 0x00, 0x62, 0x00, 0xc4,
- 0x00, 0x9e, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
- 0x00, 0xbe, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
- 0x00, 0x04, 0x42, 0x8b, 0x04, 0x72, 0x00, 0xc4,
- 0x00, 0x24, 0x42, 0x8b, 0x00, 0xd2, 0x00, 0xc4,
- 0x00, 0x55, 0x42, 0x8b, 0x00, 0x60, 0x00, 0xc4,
- 0x00, 0x00, 0x40, 0x45, 0x20, 0x01, 0x79, 0x80,
- 0x00, 0x30, 0x42, 0x8b, 0x08, 0x82, 0x00, 0xc4,
- 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x71, 0x8b,
- 0x40, 0x01, 0x00, 0x80, 0x00, 0x60, 0x00, 0x44,
- 0xff, 0x00, 0xe2, 0xab, 0x00, 0xb2, 0x00, 0xc4,
- 0x0f, 0xf2, 0xa8, 0xa8, 0x20, 0x00, 0xb1, 0x88,
- 0x00, 0x00, 0x41, 0x02, 0x4d, 0xf2, 0x00, 0x39,
- 0xc0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
- 0x0d, 0xf2, 0xa3, 0xa8, 0x4d, 0xf2, 0x00, 0x39,
- 0x00, 0x60, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
- 0x20, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x02,
- 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
- 0xff, 0x00, 0xe2, 0xab, 0xa0, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x61, 0x10, 0x4d, 0xf2, 0x04, 0x19,
- 0x00, 0x60, 0x00, 0x44, 0xff, 0x20, 0xe2, 0xab,
- 0x60, 0x00, 0x00, 0x88, 0x00, 0x00, 0x71, 0xc0,
- 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
- 0x00, 0x00, 0x79, 0x80, 0x00, 0xe2, 0x00, 0x84,
- 0x03, 0x03, 0x04, 0x49, 0x08, 0xc2, 0x00, 0x54,
- 0x00, 0x60, 0x04, 0x64, 0x00, 0x60, 0x00, 0x44,
- 0x00, 0x00, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
- 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
- 0x20, 0x01, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
- 0x00, 0x20, 0xe2, 0x8b, 0x0c, 0xf2, 0x00, 0x84,
- 0x3e, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
- 0x08, 0x01, 0x00, 0x44, 0x6c, 0x00, 0x51, 0x8b,
- 0xc0, 0x20, 0x00, 0x39, 0x00, 0x02, 0xe2, 0x8b,
- 0x04, 0x21, 0x00, 0x84, 0xfd, 0x00, 0x51, 0x8b,
- 0xc2, 0x20, 0x00, 0x39, 0x00, 0x11, 0x00, 0x44,
- 0xfe, 0x00, 0x51, 0x8b, 0xc2, 0x20, 0x00, 0x39,
- 0xe5, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x00, 0x39,
- 0x00, 0x00, 0xb1, 0x80, 0xc9, 0x20, 0x04, 0x19,
- 0xcb, 0x20, 0x04, 0x19, 0xc1, 0x20, 0x04, 0x19,
- 0xc3, 0x20, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
- 0xc7, 0x20, 0x04, 0x19, 0x5e, 0x00, 0x71, 0x8b,
- 0xcf, 0x00, 0x00, 0x39, 0x00, 0x00, 0xb1, 0x80,
- 0xc4, 0x20, 0x04, 0x19, 0xc6, 0x20, 0x04, 0x19,
- 0xc8, 0x20, 0x04, 0x19, 0xca, 0x20, 0x04, 0x19,
- 0x20, 0x00, 0x71, 0x8b, 0xcc, 0x20, 0x04, 0x19,
- 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
- 0x09, 0x04, 0x61, 0xa8, 0xc1, 0x00, 0x04, 0x19,
- 0x0b, 0x04, 0x61, 0xa8, 0xca, 0x00, 0x04, 0x19,
- 0x04, 0x60, 0x00, 0xd4, 0x0d, 0x00, 0x61, 0x0a,
- 0x90, 0x40, 0x09, 0x8f, 0x00, 0x01, 0x00, 0x45,
- 0x0f, 0x00, 0x61, 0x0a, 0x00, 0x40, 0x09, 0x8f,
- 0x00, 0x01, 0x00, 0x45, 0x82, 0x00, 0x09, 0x2e,
- 0x80, 0x40, 0x09, 0xcf, 0x02, 0x00, 0x61, 0x22,
- 0x43, 0x25, 0x61, 0x22, 0x40, 0x33, 0x00, 0x80,
- 0x08, 0xa8, 0x00, 0x44, 0x20, 0x31, 0x49, 0x5c,
- 0x92, 0x00, 0x09, 0x4e, 0x02, 0x03, 0x09, 0x2e,
- 0x00, 0x00, 0xa3, 0x02, 0xc0, 0x00, 0x71, 0xc0,
- 0x20, 0x00, 0xeb, 0x80, 0x00, 0x04, 0xc2, 0x8b,
- 0x20, 0x04, 0x61, 0x80, 0x00, 0x04, 0x7a, 0x02,
- 0xcb, 0x00, 0xa8, 0x58, 0xb0, 0x05, 0xf3, 0x80,
- 0x20, 0x04, 0xa8, 0x10, 0x00, 0x00, 0x10, 0x39,
- 0xb0, 0x00, 0xe0, 0x8b, 0x20, 0x01, 0x00, 0x80,
- 0x00, 0x00, 0x63, 0xcb, 0x00, 0x00, 0x7a, 0x02,
- 0x40, 0x00, 0x01, 0x5b, 0x20, 0x00, 0x00, 0x80,
- 0x00, 0x00, 0x4a, 0xcb, 0x20, 0x00, 0x13, 0x80,
- 0x20, 0x00, 0x7a, 0x80, 0xe0, 0x21, 0x00, 0xc0,
- 0x08, 0x00, 0x08, 0x49, 0x10, 0x41, 0x09, 0x8e,
- 0xff, 0xff, 0x62, 0x8b, 0x00, 0x04, 0x61, 0x22,
- 0x00, 0x03, 0x00, 0x45, 0x22, 0x01, 0x33, 0x80,
- 0x20, 0x01, 0xa3, 0x02, 0x00, 0x00, 0x7a, 0x80,
- 0xc0, 0x00, 0x00, 0x82, 0x07, 0x20, 0x40, 0x0a,
- 0x08, 0x83, 0x00, 0x84, 0x40, 0x21, 0x00, 0x80,
- 0x40, 0x05, 0x93, 0x10, 0xc7, 0x20, 0x00, 0x39,
- 0x00, 0x00, 0x40, 0x45, 0x07, 0x20, 0x40, 0x0a,
- 0x0c, 0xa3, 0x00, 0x84, 0x08, 0x00, 0x00, 0x82,
- 0x0c, 0x24, 0x61, 0x50, 0x40, 0x01, 0x00, 0x80,
- 0xc7, 0x20, 0x00, 0x39, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0x42, 0x01, 0x09, 0x0e, 0x02, 0x20, 0x61, 0x0a,
- 0x00, 0x01, 0x00, 0x45, 0x0c, 0x20, 0x60, 0x0a,
- 0x00, 0x73, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
- 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
- 0x00, 0x24, 0x71, 0xc0, 0x20, 0x33, 0x33, 0xc0,
- 0xe0, 0x01, 0xa3, 0x82, 0x22, 0x03, 0x7a, 0x02,
- 0xc3, 0x01, 0xa3, 0x82, 0x20, 0x01, 0x33, 0x80,
- 0x00, 0x00, 0x7a, 0x80, 0xc2, 0x01, 0xb3, 0x50,
- 0xcc, 0x20, 0x00, 0x39, 0x00, 0x00, 0x71, 0x80,
- 0x00, 0xf3, 0x00, 0x44, 0x0c, 0x20, 0x60, 0x0a,
- 0x00, 0xd3, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
- 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
- 0x00, 0x00, 0xb3, 0x10, 0xcc, 0x20, 0x00, 0x39,
- 0x00, 0x00, 0x71, 0xc0, 0x00, 0xf3, 0x00, 0x44,
- 0xcc, 0x20, 0x00, 0x39, 0x00, 0x20, 0x71, 0xc0,
- 0x00, 0x30, 0x71, 0xc0, 0x00, 0xf3, 0x00, 0x44,
- 0x20, 0x01, 0x00, 0x80, 0xff, 0xff, 0x62, 0x8b,
- 0x20, 0x01, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
- 0x20, 0x00, 0x7a, 0x80, 0x20, 0xe1, 0x09, 0x5c,
- 0x82, 0x00, 0x09, 0x2f, 0x80, 0x4a, 0x09, 0x8e,
- 0xe0, 0x01, 0xb3, 0x82, 0x20, 0x04, 0xa3, 0x80,
- 0x00, 0x00, 0x7a, 0xcb, 0x03, 0x00, 0xa8, 0x18,
- 0x00, 0x00, 0x10, 0x39, 0x08, 0x04, 0xea, 0x10,
- 0x08, 0x04, 0x7a, 0x10, 0x20, 0x00, 0x00, 0x80,
- 0x40, 0x00, 0x21, 0xcb, 0x0c, 0x00, 0xe8, 0x10,
- 0x00, 0x00, 0x41, 0x02, 0x0c, 0x00, 0xeb, 0x10,
- 0xf2, 0x01, 0x00, 0x82, 0x40, 0x21, 0x33, 0x02,
- 0x08, 0x20, 0x61, 0x0a, 0xc4, 0x00, 0x04, 0x19,
- 0xc7, 0x00, 0x00, 0x99, 0x02, 0x00, 0x61, 0x0a,
- 0x0c, 0xe8, 0x04, 0x14, 0x01, 0x00, 0x61, 0x0a,
- 0x03, 0x00, 0x48, 0x0a, 0x00, 0xb8, 0x04, 0x54,
- 0xc3, 0x00, 0x04, 0x19, 0x0c, 0xb8, 0x00, 0x44,
- 0x08, 0x00, 0xc8, 0x0a, 0x0c, 0xb8, 0x04, 0x54,
- 0xc8, 0x00, 0x04, 0x19, 0x0a, 0x00, 0x61, 0x0a,
- 0x09, 0x00, 0x48, 0x0a, 0x00, 0x68, 0x04, 0x54,
- 0xc9, 0x00, 0x04, 0x19, 0x0c, 0x68, 0x00, 0x44,
- 0x0b, 0x00, 0xc8, 0x0a, 0x0c, 0x68, 0x04, 0x54,
- 0xcb, 0x00, 0x04, 0x19, 0x04, 0x00, 0x61, 0x0a,
- 0x06, 0x00, 0x48, 0x0a, 0x00, 0x78, 0x04, 0x54,
- 0xc6, 0x00, 0x04, 0x19, 0x0c, 0x78, 0x00, 0x44,
- 0x05, 0x00, 0xc8, 0x0a, 0x0c, 0x78, 0x04, 0x54,
- 0xc5, 0x00, 0x04, 0x19, 0x07, 0x00, 0x61, 0x0a,
- 0x0c, 0x00, 0x48, 0x0a, 0x00, 0xe8, 0x04, 0x54,
- 0xcc, 0x00, 0x04, 0x19, 0x0c, 0xe8, 0x00, 0x44,
- 0x0e, 0x00, 0xc8, 0x0a, 0x0c, 0xe8, 0x04, 0x54,
- 0xce, 0x00, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
- 0x20, 0x10, 0x71, 0x8b, 0x09, 0x3f, 0x07, 0x00
-};
-
-static unsigned char alaw_main[] = {
- 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
- 0x00, 0xb1, 0x00, 0x44, 0x00, 0x61, 0x00, 0x44,
- 0x08, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
- 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
- 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
- 0x50, 0x05, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0f, 0xd4, 0x49,
- 0x20, 0x01, 0x09, 0x0e, 0x20, 0x00, 0x71, 0x8b,
- 0xa8, 0x01, 0xa8, 0x80, 0x88, 0x01, 0xa8, 0x80,
- 0xa8, 0x00, 0x00, 0x80, 0xd2, 0x00, 0x71, 0x8b,
- 0x88, 0x00, 0xa8, 0x80, 0xa8, 0x04, 0xb3, 0x80,
- 0x20, 0x07, 0xb3, 0x80, 0x88, 0x03, 0xb1, 0x80,
- 0xc0, 0x00, 0x09, 0x5c, 0xc2, 0x01, 0x00, 0x82,
- 0xa1, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x04, 0x19,
- 0x21, 0x20, 0x71, 0x8b, 0xcf, 0x00, 0x04, 0x19,
- 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x00, 0x04, 0x19,
- 0x00, 0x40, 0x00, 0x14, 0x08, 0x40, 0x04, 0x24,
- 0x00, 0x00, 0x34, 0x49, 0x0c, 0x40, 0x00, 0x44,
- 0x44, 0x04, 0x04, 0x39, 0x00, 0x00, 0x40, 0x45,
- 0x32, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x0c, 0x39,
- 0x00, 0x00, 0x40, 0x45, 0x40, 0x40, 0x09, 0xef,
- 0xff, 0x20, 0x09, 0xcf, 0x00, 0x04, 0x63, 0xa1,
- 0x50, 0x03, 0x33, 0x80, 0x00, 0x04, 0xa3, 0x80,
- 0x00, 0xff, 0xc2, 0x8b, 0x00, 0xd0, 0x04, 0x54,
- 0x04, 0xe0, 0x00, 0xc4, 0x20, 0x03, 0x80, 0xc0,
- 0x30, 0x00, 0x00, 0x88, 0x00, 0x00, 0x7a, 0x0a,
- 0xd0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
- 0xc0, 0x00, 0x00, 0x99, 0x00, 0x60, 0x00, 0x44,
- 0x00, 0xff, 0xc2, 0x8b, 0x20, 0x00, 0x00, 0x80,
- 0x00, 0x0d, 0x42, 0x8b, 0x08, 0x32, 0x00, 0xc4,
- 0x00, 0x0e, 0x42, 0x8b, 0x00, 0xa2, 0x00, 0xc4,
- 0x00, 0x1e, 0x42, 0x8b, 0x0c, 0xb2, 0x00, 0xc4,
- 0x00, 0x8e, 0x42, 0x8b, 0x00, 0x62, 0x00, 0xc4,
- 0x00, 0x9e, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
- 0x00, 0xbe, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
- 0x00, 0x04, 0x42, 0x8b, 0x04, 0x72, 0x00, 0xc4,
- 0x00, 0x24, 0x42, 0x8b, 0x00, 0xd2, 0x00, 0xc4,
- 0x00, 0x55, 0x42, 0x8b, 0x00, 0x60, 0x00, 0xc4,
- 0x00, 0x00, 0x40, 0x45, 0x20, 0x01, 0x79, 0x80,
- 0x00, 0x30, 0x42, 0x8b, 0x08, 0x82, 0x00, 0xc4,
- 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x71, 0x8b,
- 0x40, 0x01, 0x00, 0x80, 0x00, 0x60, 0x00, 0x44,
- 0xff, 0x00, 0xe2, 0xab, 0x00, 0xb2, 0x00, 0xc4,
- 0x0f, 0xf2, 0xa8, 0xa8, 0x20, 0x00, 0xb1, 0x88,
- 0x00, 0x00, 0x41, 0x02, 0x4d, 0xf2, 0x00, 0x39,
- 0xc0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
- 0x0d, 0xf2, 0xa3, 0xa8, 0x4d, 0xf2, 0x00, 0x39,
- 0x00, 0x60, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
- 0x20, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x02,
- 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
- 0xff, 0x00, 0xe2, 0xab, 0xa0, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x61, 0x10, 0x4d, 0xf2, 0x04, 0x19,
- 0x00, 0x60, 0x00, 0x44, 0xff, 0x20, 0xe2, 0xab,
- 0x60, 0x00, 0x00, 0x88, 0x00, 0x00, 0x71, 0xc0,
- 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
- 0x00, 0x00, 0x79, 0x80, 0x00, 0xe2, 0x00, 0x84,
- 0x03, 0x03, 0x04, 0x49, 0x04, 0xc2, 0x00, 0x54,
- 0x00, 0x60, 0x04, 0x64, 0x00, 0x60, 0x00, 0x44,
- 0x00, 0x00, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
- 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
- 0x20, 0x01, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
- 0x00, 0x20, 0xe2, 0x8b, 0x0c, 0xf2, 0x00, 0x84,
- 0xbe, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
- 0x08, 0x01, 0x00, 0x44, 0xec, 0x00, 0x51, 0x8b,
- 0xc0, 0x20, 0x00, 0x39, 0x00, 0x02, 0xe2, 0x8b,
- 0x04, 0x21, 0x00, 0x84, 0x3f, 0x00, 0x51, 0x8b,
- 0xc2, 0x20, 0x00, 0x39, 0x00, 0x11, 0x00, 0x44,
- 0x3d, 0x00, 0x51, 0x8b, 0xc2, 0x20, 0x00, 0x39,
- 0xe5, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x00, 0x39,
- 0x00, 0x00, 0xb1, 0x80, 0xc9, 0x20, 0x04, 0x19,
- 0xcb, 0x20, 0x04, 0x19, 0xc1, 0x20, 0x04, 0x19,
- 0xc3, 0x20, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
- 0xc7, 0x20, 0x04, 0x19, 0xde, 0x00, 0x51, 0x8b,
- 0xcf, 0x00, 0x00, 0x39, 0x00, 0x01, 0xb1, 0x80,
- 0xc4, 0x20, 0x04, 0x19, 0xc6, 0x20, 0x04, 0x19,
- 0xc8, 0x20, 0x04, 0x19, 0xca, 0x20, 0x04, 0x19,
- 0x20, 0x00, 0x71, 0x8b, 0xcc, 0x20, 0x04, 0x19,
- 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
- 0x09, 0x04, 0x61, 0xa8, 0xc1, 0x00, 0x04, 0x19,
- 0x0b, 0x04, 0x61, 0xa8, 0xca, 0x00, 0x04, 0x19,
- 0x04, 0x60, 0x00, 0xd4, 0x0d, 0x00, 0x61, 0x0a,
- 0x90, 0x40, 0x09, 0x8f, 0x00, 0x01, 0x00, 0x45,
- 0x0f, 0x00, 0x61, 0x0a, 0x00, 0x40, 0x09, 0x8f,
- 0x00, 0x01, 0x00, 0x45, 0x82, 0x00, 0x09, 0x2e,
- 0x80, 0x40, 0x09, 0xcf, 0x02, 0x00, 0x61, 0x22,
- 0x43, 0x25, 0x61, 0x22, 0x40, 0x33, 0x00, 0x80,
- 0x08, 0x48, 0x00, 0x44, 0x20, 0xb1, 0x49, 0x5c,
- 0x92, 0x00, 0x09, 0x4e, 0x02, 0x03, 0x09, 0x2e,
- 0x00, 0x00, 0xa3, 0x02, 0xc0, 0x00, 0x71, 0xc0,
- 0x20, 0x00, 0xeb, 0x80, 0x00, 0x04, 0xc2, 0x8b,
- 0x20, 0x04, 0x61, 0x80, 0x00, 0x04, 0x7a, 0x02,
- 0xc0, 0x00, 0x00, 0x82, 0x0c, 0xc3, 0x08, 0x49,
- 0xb0, 0x01, 0xf3, 0x80, 0x00, 0x00, 0x10, 0x39,
- 0x20, 0x00, 0x0c, 0x89, 0x0c, 0x88, 0x08, 0x49,
- 0x03, 0x00, 0xa8, 0x18, 0x00, 0x00, 0x10, 0x39,
- 0xbd, 0xff, 0x62, 0x8b, 0x20, 0x01, 0x00, 0x80,
- 0x00, 0x00, 0x63, 0xcb, 0x00, 0x00, 0x7a, 0x02,
- 0x40, 0x00, 0x01, 0x5b, 0x20, 0x00, 0x00, 0x80,
- 0x00, 0x00, 0x4a, 0xcb, 0x20, 0x00, 0x13, 0x80,
- 0x20, 0x00, 0x7a, 0x80, 0xe0, 0x21, 0x00, 0xc0,
- 0x08, 0x00, 0x08, 0x49, 0x10, 0x41, 0x09, 0x8e,
- 0xae, 0xae, 0x62, 0x8b, 0x00, 0x04, 0x61, 0x22,
- 0x00, 0x03, 0x00, 0x45, 0x22, 0x01, 0x33, 0x80,
- 0x20, 0x01, 0xa3, 0x02, 0x00, 0x00, 0x7a, 0x80,
- 0xc0, 0x00, 0x00, 0x82, 0x07, 0x20, 0x40, 0x0a,
- 0x08, 0xa3, 0x00, 0x84, 0x40, 0x21, 0x00, 0x80,
- 0x40, 0x05, 0x93, 0x10, 0xc7, 0x20, 0x00, 0x39,
- 0x00, 0x00, 0x40, 0x45, 0x07, 0x20, 0x40, 0x0a,
- 0x0c, 0x93, 0x00, 0x84, 0x08, 0x00, 0x00, 0x82,
- 0x0c, 0x24, 0x61, 0x50, 0x40, 0x01, 0x00, 0x80,
- 0xc7, 0x20, 0x00, 0x39, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0x42, 0x01, 0x09, 0x0e, 0x02, 0x20, 0x61, 0x0a,
- 0x00, 0x01, 0x00, 0x45, 0x0c, 0x20, 0x60, 0x0a,
- 0x00, 0xc3, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
- 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
- 0x00, 0x24, 0x71, 0xc0, 0x20, 0x33, 0x33, 0xc0,
- 0xe0, 0x01, 0xa3, 0x82, 0x22, 0x03, 0x7a, 0x02,
- 0xc3, 0x01, 0xa3, 0x82, 0x20, 0x01, 0x33, 0x80,
- 0x00, 0x00, 0x7a, 0x80, 0xc2, 0x01, 0xb3, 0x50,
- 0xcc, 0x20, 0x00, 0x39, 0x00, 0x00, 0x71, 0x80,
- 0x00, 0x08, 0x00, 0x44, 0x0c, 0x20, 0x60, 0x0a,
- 0x00, 0xf3, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
- 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
- 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x93, 0x10,
- 0xcc, 0x20, 0x00, 0x39, 0x00, 0x08, 0x00, 0x44,
- 0xcc, 0x20, 0x00, 0x39, 0x00, 0x20, 0x00, 0xc0,
- 0x00, 0x30, 0x71, 0xc0, 0x00, 0x08, 0x00, 0x44,
- 0x20, 0x01, 0x00, 0x80, 0xae, 0xae, 0x62, 0x8b,
- 0x20, 0x01, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
- 0x20, 0x00, 0x7a, 0x80, 0x20, 0xa1, 0x49, 0x5c,
- 0x82, 0x00, 0x09, 0x6e, 0x80, 0x4a, 0x09, 0x8e,
- 0xe0, 0x01, 0xb3, 0x82, 0x20, 0x04, 0xa3, 0x80,
- 0x00, 0x00, 0x7a, 0xcb, 0x28, 0x04, 0xea, 0x10,
- 0x0c, 0x04, 0x7a, 0x10, 0x70, 0x00, 0xc0, 0x8b,
- 0x00, 0x00, 0x10, 0x39, 0x90, 0x03, 0x00, 0x80,
- 0x40, 0x00, 0x21, 0x5b, 0x90, 0x00, 0x61, 0x80,
- 0x0c, 0x8a, 0x08, 0x49, 0x00, 0x00, 0x1c, 0x19,
- 0x40, 0x00, 0x08, 0x5b, 0x08, 0x00, 0x08, 0x49,
- 0x20, 0x02, 0x00, 0x80, 0x03, 0x00, 0xa8, 0x18,
- 0x00, 0x00, 0x14, 0x19, 0x40, 0x00, 0x21, 0xcb,
- 0x00, 0x00, 0x41, 0x02, 0x00, 0x00, 0xeb, 0x80,
- 0xf2, 0x01, 0x00, 0x82, 0x40, 0x21, 0x33, 0x02,
- 0x08, 0x20, 0x61, 0x0a, 0xc4, 0x00, 0x04, 0x19,
- 0xc7, 0x00, 0x00, 0x99, 0x02, 0x00, 0x61, 0x0a,
- 0x0c, 0x0a, 0x04, 0x14, 0x01, 0x00, 0x61, 0x0a,
- 0x03, 0x00, 0x48, 0x0a, 0x00, 0x58, 0x04, 0x54,
- 0xc3, 0x00, 0x04, 0x19, 0x0c, 0x58, 0x00, 0x44,
- 0x08, 0x00, 0xc8, 0x0a, 0x0c, 0x58, 0x04, 0x54,
- 0xc8, 0x00, 0x04, 0x19, 0x0a, 0x00, 0x61, 0x0a,
- 0x09, 0x00, 0x48, 0x0a, 0x00, 0xc8, 0x04, 0x54,
- 0xc9, 0x00, 0x04, 0x19, 0x0c, 0xc8, 0x00, 0x44,
- 0x0b, 0x00, 0xc8, 0x0a, 0x0c, 0xc8, 0x04, 0x54,
- 0xcb, 0x00, 0x04, 0x19, 0x04, 0x00, 0x61, 0x0a,
- 0x06, 0x00, 0x48, 0x0a, 0x00, 0xd8, 0x04, 0x54,
- 0xc6, 0x00, 0x04, 0x19, 0x0c, 0xd8, 0x00, 0x44,
- 0x05, 0x00, 0xc8, 0x0a, 0x0c, 0xd8, 0x04, 0x54,
- 0xc5, 0x00, 0x04, 0x19, 0x07, 0x00, 0x61, 0x0a,
- 0x0c, 0x00, 0x48, 0x0a, 0x00, 0x0a, 0x04, 0x54,
- 0xcc, 0x00, 0x04, 0x19, 0x0c, 0x0a, 0x00, 0x44,
- 0x0e, 0x00, 0xc8, 0x0a, 0x0c, 0x0a, 0x04, 0x54,
- 0xce, 0x00, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
- 0x20, 0x10, 0x71, 0x8b, 0x08, 0x42, 0x06, 0x00
-};
-
-
-static unsigned char ima_adpcm_init[] = {
- 0x00, 0x10, 0x00, 0x44, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x00, 0x40, 0x45, 0xaa, 0xaa, 0x71, 0x8b,
- 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
- 0xff, 0x6e, 0x21, 0x49, 0xff, 0x0f, 0xd4, 0x49,
- 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
- 0x50, 0x05, 0xb1, 0x80, 0x62, 0x00, 0x19, 0x0e,
- 0x21, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xb0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x40, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x60, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x50, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x70, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xc0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xe0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xd0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x02, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x22, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x32, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xa2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xb2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x62, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xc2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xf2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x11, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xa1, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x61, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xe1, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x13, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xb3, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xc3, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x18, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x68, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x0a, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x4a, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x29, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x79, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x9b, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x14, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xf4, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xe6, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xe5, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xd7, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x2e, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x9d, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xef, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xb2, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x33, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x2a, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x3b, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x46, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x2c, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xdd, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x01, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x9a, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x16, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x8e, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xc2, 0x30, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xc9, 0x30, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x3c, 0x30, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x81, 0x80, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xd4, 0x80, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x10, 0xa0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x34, 0xa0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x02, 0x90, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x75, 0x90, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x9a, 0xb0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x12, 0x40, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x0d, 0x40, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x3c, 0x60, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xe7, 0x50, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x0e, 0x70, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xff, 0xc0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xc8, 0xd0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x57, 0xf0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xc8, 0x22, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xb0, 0x32, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xdd, 0x82, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x90, 0xb2, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x8a, 0x62, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xce, 0x72, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xa5, 0xd2, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x97, 0x21, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xa2, 0xa1, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x5c, 0x41, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xfe, 0xc1, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x7a, 0x23, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x78, 0x93, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x67, 0x73, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x17, 0x28, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x88, 0x48, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xdb, 0xf8, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x2b, 0xba, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xf1, 0x09, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xdc, 0x69, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x19, 0x8b, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0xff, 0xfb, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x20, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
- 0x52, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0xff, 0xff, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x00, 0x00, 0x82,
- 0xc2, 0x00, 0x00, 0x82, 0x10, 0x00, 0x71, 0x8b,
- 0xc2, 0x00, 0x00, 0x82, 0x80, 0x00, 0x71, 0x8b,
- 0xc2, 0x00, 0x00, 0x82, 0x90, 0x00, 0x71, 0x8b,
- 0xc2, 0x00, 0x00, 0x82, 0x40, 0x00, 0x71, 0x8b,
- 0xc2, 0x00, 0x00, 0x82, 0xff, 0xff, 0x71, 0x8b,
- 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x00, 0x00, 0x82,
- 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x00, 0x00, 0x82,
- 0x10, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0x80, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0x90, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0x40, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0xff, 0xfb, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0x00, 0x04, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0x4a, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0x00, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0x00, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
- 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x30, 0x04, 0x19,
- 0x10, 0x00, 0x09, 0x4f, 0xc2, 0x01, 0x00, 0x82,
- 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
- 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
- 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
- 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
- 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
- 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
- 0x00, 0x10, 0x71, 0x8b, 0xc1, 0x30, 0x04, 0x19,
- 0x93, 0x00, 0x01, 0x4f, 0xcd, 0x30, 0x00, 0x09,
- 0xcf, 0x30, 0x00, 0x09, 0x00, 0x00, 0x34, 0x49,
- 0x00, 0x08, 0x00, 0x44, 0xc8, 0x54, 0x11, 0x00
-};
-
-static unsigned char ima_adpcm_playback[] = {
- 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
- 0x0c, 0x50, 0x00, 0x44, 0x00, 0x70, 0x00, 0x44,
- 0x04, 0x70, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
- 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0d, 0xd4, 0x49,
- 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
- 0x50, 0x01, 0xb1, 0x80, 0x00, 0x01, 0xb1, 0x80,
- 0xc9, 0x20, 0x04, 0x19, 0x51, 0x00, 0x71, 0x8b,
- 0xcd, 0x00, 0x04, 0x19, 0xe4, 0x20, 0x71, 0x8b,
- 0xcf, 0x00, 0x04, 0x19, 0x80, 0x00, 0x71, 0x8b,
- 0xcb, 0x20, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
- 0xc4, 0x20, 0x04, 0x19, 0x65, 0x00, 0x51, 0x8b,
- 0xc2, 0x20, 0x00, 0x39, 0x00, 0x00, 0xb1, 0x80,
- 0xc2, 0x30, 0x04, 0x19, 0x00, 0x00, 0x63, 0x80,
- 0xc1, 0xa0, 0x04, 0x19, 0x93, 0x00, 0x01, 0x4f,
- 0xcd, 0x30, 0x00, 0x09, 0xcf, 0x30, 0x00, 0x09,
- 0x04, 0x40, 0x00, 0x14, 0x0c, 0x40, 0x00, 0x14,
- 0x00, 0x04, 0x61, 0xa8, 0x02, 0x04, 0x61, 0xa8,
- 0x04, 0x60, 0x04, 0x24, 0x00, 0x00, 0x34, 0x49,
- 0x00, 0x50, 0x00, 0x44, 0x44, 0x04, 0x04, 0x39,
- 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x40, 0x45,
- 0x0f, 0x00, 0x61, 0x0a, 0x00, 0x01, 0x00, 0x45,
- 0x40, 0x40, 0x09, 0xef, 0xff, 0x20, 0x09, 0xcf,
- 0x00, 0x04, 0x63, 0xa1, 0x50, 0x03, 0x33, 0x80,
- 0x00, 0x04, 0xa3, 0x80, 0x00, 0xff, 0xc2, 0x8b,
- 0x08, 0xf0, 0x04, 0x54, 0x0c, 0xd0, 0x00, 0xc4,
- 0x20, 0x03, 0x80, 0xc0, 0x30, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x7a, 0x0a, 0xd0, 0x01, 0x00, 0x82,
- 0x08, 0x50, 0x00, 0x44, 0xc0, 0x00, 0x00, 0x99,
- 0x08, 0x50, 0x00, 0x44, 0x00, 0xff, 0xc2, 0x8b,
- 0x20, 0x00, 0x00, 0x80, 0x00, 0x0d, 0x42, 0x8b,
- 0x00, 0xa2, 0x00, 0xc4, 0x00, 0x0e, 0x42, 0x8b,
- 0x0c, 0x92, 0x00, 0xc4, 0x00, 0x1e, 0x42, 0x8b,
- 0x04, 0x62, 0x00, 0xc4, 0x00, 0x8e, 0x42, 0x8b,
- 0x0c, 0x52, 0x00, 0xc4, 0x00, 0x9e, 0x42, 0x8b,
- 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xbe, 0x42, 0x8b,
- 0x00, 0xc2, 0x00, 0xc4, 0x00, 0x04, 0x42, 0x8b,
- 0x00, 0xf2, 0x00, 0xc4, 0x00, 0x24, 0x42, 0x8b,
- 0x00, 0x91, 0x00, 0xc4, 0x00, 0x55, 0x42, 0x8b,
- 0x08, 0x50, 0x00, 0xc4, 0x00, 0x3f, 0x42, 0x8b,
- 0x08, 0xe2, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
- 0x20, 0x01, 0x79, 0x80, 0x00, 0x30, 0x42, 0x8b,
- 0x00, 0x92, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x00, 0x71, 0x8b, 0x40, 0x01, 0x00, 0x80,
- 0x08, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
- 0x0c, 0x42, 0x00, 0xc4, 0x0f, 0xf2, 0xa8, 0xa8,
- 0x20, 0x00, 0xb1, 0x88, 0x00, 0x00, 0x41, 0x02,
- 0x4d, 0xf2, 0x00, 0x39, 0xc0, 0x01, 0x00, 0x82,
- 0x08, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0xa3, 0xa8,
- 0x4d, 0xf2, 0x00, 0x39, 0x08, 0x50, 0x00, 0x44,
- 0xff, 0x00, 0xe2, 0xab, 0x20, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x61, 0x02, 0x4d, 0xf2, 0x04, 0x19,
- 0x08, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
- 0xa0, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x10,
- 0x4d, 0xf2, 0x04, 0x19, 0x08, 0x50, 0x00, 0x44,
- 0xff, 0x20, 0xe2, 0xab, 0x60, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x71, 0xc0, 0x4d, 0xf2, 0x04, 0x19,
- 0x08, 0x50, 0x00, 0x44, 0x00, 0x00, 0x7a, 0x0a,
- 0x20, 0x01, 0xf0, 0x80, 0x01, 0xa0, 0x41, 0x0a,
- 0x04, 0xd2, 0x00, 0xc4, 0x20, 0x01, 0xf0, 0x80,
- 0xc1, 0x30, 0x04, 0x19, 0x08, 0x50, 0x00, 0x44,
- 0x00, 0x00, 0x79, 0x80, 0x00, 0xa1, 0x00, 0x84,
- 0xb5, 0x00, 0x51, 0x8b, 0xcf, 0x00, 0x00, 0x39,
- 0x00, 0x01, 0xb1, 0x80, 0x88, 0x00, 0x04, 0x19,
- 0x8a, 0x00, 0x04, 0x19, 0xc8, 0x20, 0x04, 0x19,
- 0xca, 0x20, 0x04, 0x19, 0xc2, 0x30, 0x04, 0x19,
- 0xcd, 0x10, 0x04, 0x19, 0xcf, 0x10, 0x04, 0x19,
- 0xb0, 0x00, 0x71, 0x8b, 0x8c, 0x00, 0x04, 0x19,
- 0x8e, 0x00, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
- 0xc4, 0x20, 0x04, 0x19, 0x93, 0x00, 0x01, 0x4f,
- 0xcd, 0x30, 0x00, 0x09, 0xcf, 0x30, 0x00, 0x09,
- 0x03, 0x03, 0x04, 0x49, 0x04, 0x81, 0x00, 0x54,
- 0x08, 0x50, 0x04, 0x64, 0x08, 0x50, 0x00, 0x44,
- 0x00, 0x00, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
- 0x03, 0x00, 0x04, 0x49, 0x08, 0x50, 0x00, 0x44,
- 0x20, 0x01, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
- 0x00, 0x02, 0xe2, 0x8b, 0x08, 0x41, 0x00, 0x84,
- 0x65, 0x00, 0x51, 0x8b, 0xc2, 0x20, 0x00, 0x39,
- 0x00, 0x00, 0x63, 0x80, 0xc1, 0xa0, 0x04, 0x19,
- 0x08, 0x61, 0x00, 0x44, 0x2d, 0x00, 0x51, 0x8b,
- 0xc2, 0x20, 0x00, 0x39, 0x00, 0x00, 0xb1, 0x80,
- 0xc1, 0xa0, 0x04, 0x19, 0x03, 0x00, 0x04, 0x49,
- 0x08, 0x50, 0x00, 0x44, 0x02, 0x20, 0x61, 0x0a,
- 0x00, 0x01, 0x00, 0x45, 0x02, 0x30, 0x61, 0x0a,
- 0x04, 0x03, 0x00, 0xc4, 0x05, 0xb0, 0xc8, 0x18,
- 0x04, 0x71, 0x00, 0xc4, 0x00, 0x13, 0x00, 0x44,
- 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
- 0x00, 0x49, 0x00, 0xc4, 0xca, 0x20, 0x04, 0x19,
- 0x4a, 0x04, 0x04, 0x19, 0xff, 0x00, 0xe2, 0x8b,
- 0x0c, 0xf9, 0x08, 0x44, 0xcf, 0x10, 0x04, 0x19,
- 0x0c, 0x2b, 0x08, 0x44, 0x8e, 0x00, 0x04, 0x19,
- 0x03, 0x30, 0x61, 0x0a, 0xc8, 0x20, 0x00, 0x39,
- 0x48, 0x04, 0x00, 0x39, 0x0a, 0x30, 0x61, 0x0a,
- 0x0c, 0xf9, 0x08, 0x44, 0xcd, 0x10, 0x04, 0x19,
- 0x0c, 0x2b, 0x08, 0x44, 0x8c, 0x00, 0x04, 0x19,
- 0x0c, 0xd9, 0x08, 0x44, 0x0c, 0x5a, 0x00, 0x44,
- 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
- 0x00, 0x49, 0x00, 0xc4, 0xc3, 0x30, 0x04, 0x19,
- 0xca, 0x30, 0x00, 0x99, 0x0c, 0xd9, 0x08, 0x44,
- 0x42, 0x0a, 0x09, 0x0e, 0x00, 0x01, 0x33, 0x11,
- 0x8c, 0x01, 0xa3, 0x80, 0x00, 0x01, 0x7a, 0x10,
- 0x80, 0x05, 0xb1, 0x80, 0x05, 0xb0, 0xe0, 0x18,
- 0x00, 0x93, 0x00, 0x84, 0x00, 0x79, 0x08, 0x44,
- 0x00, 0x04, 0x79, 0x80, 0x00, 0x49, 0x00, 0xc4,
- 0x0c, 0x1b, 0x08, 0x44, 0x88, 0x00, 0x04, 0x19,
- 0x8a, 0x00, 0x00, 0x99, 0x0c, 0xd9, 0x08, 0x44,
- 0x42, 0x0a, 0x09, 0x0e, 0x80, 0x00, 0x71, 0x8b,
- 0xc0, 0x04, 0xb1, 0x82, 0x10, 0x00, 0xe0, 0x0b,
- 0x00, 0x43, 0x00, 0x84, 0x02, 0x30, 0x61, 0x0a,
- 0x01, 0x30, 0xc8, 0x0a, 0x00, 0x43, 0x00, 0x84,
- 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x30, 0x04, 0x19,
- 0x0c, 0xa8, 0x00, 0x44, 0x02, 0x30, 0x61, 0x0a,
- 0x00, 0xd3, 0x00, 0xc4, 0x05, 0xb0, 0xc8, 0x18,
- 0x04, 0x63, 0x00, 0xc4, 0x08, 0xf3, 0x00, 0x44,
- 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
- 0x00, 0x49, 0x00, 0xc4, 0x20, 0x00, 0x04, 0x19,
- 0xff, 0x00, 0xe2, 0x8b, 0x0c, 0xf9, 0x08, 0x44,
- 0xcd, 0x10, 0x04, 0x19, 0xcf, 0x10, 0x04, 0x19,
- 0x0c, 0x2b, 0x08, 0x44, 0x8c, 0x00, 0x04, 0x19,
- 0x8e, 0x00, 0x04, 0x19, 0x03, 0x30, 0x61, 0x0a,
- 0xc8, 0x20, 0x00, 0x39, 0xca, 0x20, 0x00, 0x39,
- 0x48, 0x04, 0x00, 0x39, 0x4a, 0x04, 0x00, 0x39,
- 0x0c, 0xd9, 0x08, 0x44, 0x0c, 0x5a, 0x00, 0x44,
- 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
- 0x00, 0x49, 0x00, 0xc4, 0xc3, 0x30, 0x04, 0x19,
- 0x0c, 0xd9, 0x08, 0x44, 0x42, 0x0a, 0x09, 0x0e,
- 0x05, 0xb0, 0xe0, 0x18, 0x00, 0x18, 0x00, 0x84,
- 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
- 0x00, 0x49, 0x00, 0xc4, 0x0c, 0x1b, 0x08, 0x44,
- 0x80, 0x01, 0x00, 0x80, 0x0c, 0xd9, 0x08, 0x44,
- 0x42, 0x0a, 0x09, 0x0e, 0x80, 0x00, 0x71, 0x8b,
- 0xc0, 0x04, 0xb1, 0x82, 0x10, 0x00, 0xe0, 0x0b,
- 0x00, 0x88, 0x00, 0x84, 0x02, 0x30, 0x61, 0x0a,
- 0x01, 0x30, 0xc8, 0x0a, 0x00, 0x88, 0x00, 0x84,
- 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x30, 0x04, 0x19,
- 0x00, 0x01, 0x00, 0x11, 0x00, 0x0f, 0xe2, 0x8b,
- 0x00, 0x00, 0x41, 0xcb, 0x8c, 0x00, 0x00, 0x80,
- 0x00, 0x00, 0x48, 0xcb, 0x20, 0x00, 0x7a, 0x80,
- 0x80, 0x01, 0x00, 0x80, 0x82, 0x0c, 0x09, 0x6e,
- 0x03, 0x08, 0x09, 0x0e, 0x80, 0x40, 0x09, 0xcf,
- 0x00, 0x01, 0x71, 0xc2, 0x00, 0x08, 0xc2, 0x1b,
- 0x04, 0xb8, 0x00, 0xc4, 0x20, 0x05, 0xa8, 0x80,
- 0x20, 0x01, 0xf0, 0x80, 0x00, 0x01, 0xc2, 0x1b,
- 0x04, 0x48, 0x00, 0xc4, 0x20, 0x05, 0xa8, 0x80,
- 0x20, 0x01, 0xf0, 0x80, 0x00, 0x02, 0xc2, 0x1b,
- 0x04, 0x68, 0x00, 0xc4, 0x20, 0x05, 0xa8, 0x80,
- 0x20, 0x01, 0xf0, 0x80, 0x20, 0x03, 0xa8, 0x80,
- 0x00, 0x01, 0x00, 0x11, 0x00, 0x04, 0xc2, 0x8b,
- 0x08, 0x78, 0x00, 0xc4, 0x00, 0x00, 0xe9, 0x80,
- 0x05, 0xb0, 0xa8, 0x18, 0x00, 0x00, 0x4a, 0xcb,
- 0x20, 0x00, 0xa8, 0x22, 0xd0, 0x01, 0x00, 0x82,
- 0x40, 0x01, 0x00, 0x80, 0xc4, 0x00, 0x04, 0x19,
- 0xb0, 0x00, 0xe2, 0x8b, 0x06, 0x20, 0xa8, 0x0a,
- 0x2d, 0x10, 0x61, 0x0a, 0xd1, 0x08, 0x09, 0x2e,
- 0x00, 0x01, 0xa8, 0x02, 0x0c, 0xf9, 0x08, 0x44,
- 0xcd, 0x10, 0x04, 0x19, 0x0c, 0x2b, 0x08, 0x44,
- 0x03, 0x08, 0x09, 0x0e, 0x9a, 0x25, 0xb1, 0x60,
- 0xa2, 0x0e, 0x09, 0x6e, 0x03, 0x00, 0x09, 0x0f,
- 0x00, 0x01, 0x71, 0x82, 0x20, 0x01, 0x00, 0x80,
- 0x00, 0x00, 0x61, 0xcb, 0x80, 0x01, 0x00, 0x80,
- 0x03, 0x00, 0x09, 0x0f, 0x00, 0x01, 0x71, 0xc2,
- 0x00, 0x08, 0xc2, 0x1b, 0x0c, 0x2a, 0x00, 0xc4,
- 0x20, 0x05, 0xa8, 0x80, 0x20, 0x01, 0xf0, 0x80,
- 0x00, 0x01, 0xc2, 0x1b, 0x0c, 0x1a, 0x00, 0xc4,
- 0x20, 0x05, 0xa8, 0x80, 0x20, 0x01, 0xf0, 0x80,
- 0x00, 0x02, 0xc2, 0x1b, 0x0c, 0x3a, 0x00, 0xc4,
- 0x20, 0x05, 0xa8, 0x80, 0x20, 0x01, 0xf0, 0x80,
- 0x20, 0x03, 0xa8, 0x80, 0x00, 0x01, 0x00, 0x11,
- 0x00, 0x04, 0xc2, 0x8b, 0x04, 0xaa, 0x00, 0xc4,
- 0x00, 0x00, 0xe9, 0x80, 0x05, 0xb0, 0xa8, 0x18,
- 0x00, 0x00, 0x4a, 0xcb, 0x20, 0x00, 0xa8, 0x22,
- 0xd0, 0x01, 0x00, 0x82, 0x40, 0x01, 0x00, 0x80,
- 0xc7, 0x00, 0x04, 0x19, 0xb0, 0x00, 0xe2, 0x8b,
- 0x06, 0x20, 0xa8, 0x0a, 0x2f, 0x10, 0x61, 0x0a,
- 0xf1, 0x08, 0x09, 0x2e, 0x00, 0x01, 0xa8, 0x02,
- 0x0c, 0xf9, 0x08, 0x44, 0xcf, 0x10, 0x04, 0x19,
- 0x0c, 0x2b, 0x08, 0x44, 0x9f, 0x35, 0xb1, 0x60,
- 0x03, 0x08, 0x09, 0x0e, 0x00, 0x01, 0x71, 0x82,
- 0x20, 0x01, 0x00, 0x80, 0x00, 0x00, 0x61, 0xcb,
- 0x80, 0x01, 0x00, 0x80, 0xe4, 0x20, 0x71, 0x8b,
- 0x00, 0x01, 0x00, 0x45, 0x90, 0x40, 0x09, 0x8f,
- 0x00, 0x05, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0x08, 0x19, 0x04, 0xd4, 0x93, 0x00, 0x01, 0x4f,
- 0xe7, 0x00, 0x01, 0x6f, 0x0d, 0x30, 0x61, 0x0a,
- 0x20, 0x04, 0x61, 0xa8, 0xc2, 0x00, 0x00, 0x82,
- 0x02, 0x04, 0x61, 0xa8, 0xc2, 0x00, 0x00, 0x82,
- 0xcd, 0x30, 0x00, 0x09, 0x02, 0x00, 0x00, 0x02,
- 0x02, 0x00, 0x00, 0x02, 0xc0, 0x80, 0x00, 0x09,
- 0x20, 0x00, 0x09, 0x49, 0x0f, 0x30, 0x61, 0x0a,
- 0x0d, 0x30, 0xc8, 0x0a, 0x00, 0x29, 0x00, 0xc4,
- 0x00, 0x80, 0xc8, 0x0a, 0x00, 0x29, 0x00, 0xc4,
- 0x00, 0x04, 0xb1, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0xc9, 0x20, 0x04, 0x39, 0x00, 0x39, 0x00, 0x44,
- 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0x00, 0x04, 0xb1, 0x80, 0xc9, 0x20, 0x04, 0x39,
- 0x00, 0x39, 0x00, 0x44, 0x09, 0x20, 0x23, 0x0a,
- 0x00, 0x00, 0x06, 0x19, 0xc9, 0x20, 0x04, 0x19,
- 0x00, 0x00, 0x40, 0x45, 0x02, 0x00, 0x61, 0x0a,
- 0x0c, 0xb9, 0x04, 0x14, 0x04, 0x00, 0x61, 0x0a,
- 0x06, 0x00, 0x48, 0x0a, 0x00, 0xa9, 0x04, 0x54,
- 0xc6, 0x00, 0x04, 0x19, 0x0c, 0xa9, 0x00, 0x44,
- 0x05, 0x00, 0xc8, 0x0a, 0x0c, 0xa9, 0x04, 0x54,
- 0xc5, 0x00, 0x04, 0x19, 0x07, 0x00, 0x61, 0x0a,
- 0x0c, 0x00, 0x48, 0x0a, 0x00, 0xb9, 0x04, 0x54,
- 0xcc, 0x00, 0x04, 0x19, 0x0c, 0xb9, 0x00, 0x44,
- 0x0e, 0x00, 0xc8, 0x0a, 0x0c, 0xb9, 0x04, 0x54,
- 0xce, 0x00, 0x04, 0x19, 0x0c, 0x5a, 0x00, 0x44,
- 0x82, 0x0d, 0x09, 0x2e, 0x80, 0x40, 0x09, 0xcf,
- 0x00, 0xdf, 0x71, 0x8b, 0x80, 0x01, 0x00, 0x80,
- 0x02, 0xc1, 0x00, 0x22, 0x03, 0xc1, 0x00, 0x22,
- 0x00, 0x01, 0x65, 0x80, 0xd2, 0x05, 0x65, 0x82,
- 0x40, 0x21, 0x00, 0x80, 0xd3, 0x03, 0x00, 0x82,
- 0x40, 0x33, 0x00, 0x80, 0x0c, 0x5a, 0x00, 0x44,
- 0x0f, 0x30, 0x61, 0x0a, 0x0d, 0x30, 0xc8, 0x0a,
- 0x08, 0xd9, 0x00, 0xc4, 0x93, 0x00, 0x01, 0x4f,
- 0xe7, 0x00, 0x01, 0x6f, 0x0f, 0x30, 0x61, 0x0a,
- 0x20, 0x00, 0x00, 0x88, 0x02, 0x00, 0x61, 0x02,
- 0x02, 0x00, 0x00, 0x03, 0xcf, 0x30, 0x00, 0x09,
- 0x20, 0x00, 0x09, 0x49, 0x00, 0x04, 0x63, 0x80,
- 0x04, 0xd9, 0x00, 0x44, 0x00, 0x04, 0xb1, 0x80,
- 0x00, 0x00, 0x00, 0x46, 0x02, 0x30, 0x61, 0x0a,
- 0x05, 0xb0, 0xa8, 0x18, 0xc2, 0x30, 0x04, 0x19,
- 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0xc8, 0x0a,
- 0x0c, 0x0b, 0x04, 0x14, 0x0e, 0x10, 0x61, 0x0a,
- 0x04, 0x2b, 0x00, 0x44, 0x0c, 0x10, 0xc8, 0x0a,
- 0x04, 0x2b, 0x04, 0x54, 0x0c, 0x10, 0x61, 0x0a,
- 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0xa8, 0x18,
- 0xa0, 0x00, 0x00, 0x88, 0x00, 0x01, 0x71, 0x82,
- 0x00, 0x00, 0x00, 0x46, 0x00, 0x04, 0x33, 0x80,
- 0x00, 0x00, 0x83, 0x80, 0x20, 0x04, 0x7a, 0x80,
- 0x20, 0x01, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
- 0x20, 0x00, 0x7a, 0x80, 0x20, 0x03, 0x00, 0x80,
- 0x00, 0x00, 0x00, 0x46, 0x16, 0xce, 0x11, 0x00
-};
-
-static unsigned char ima_adpcm_capture[] = {
- 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
- 0x00, 0x70, 0x00, 0x44, 0x08, 0xd0, 0x00, 0x44,
- 0x00, 0xf0, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
- 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
- 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0c, 0xd4, 0x49,
- 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
- 0x50, 0x01, 0xb1, 0x80, 0x00, 0x00, 0x71, 0x8b,
- 0xc2, 0x30, 0x04, 0x19, 0xc0, 0xa0, 0x04, 0x19,
- 0xc2, 0xa0, 0x04, 0x19, 0x89, 0x00, 0x71, 0x8b,
- 0xc8, 0x30, 0x04, 0x19, 0x71, 0x00, 0x71, 0x8b,
- 0xcd, 0x00, 0x04, 0x19, 0xcf, 0x00, 0x04, 0x19,
- 0x80, 0x00, 0x71, 0x8b, 0xcb, 0x20, 0x04, 0x19,
- 0x20, 0x00, 0x71, 0x8b, 0xc4, 0x20, 0x04, 0x19,
- 0x47, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
- 0x00, 0x00, 0x63, 0x80, 0xc1, 0xa0, 0x04, 0x19,
- 0x93, 0x00, 0x01, 0x4f, 0xcd, 0x30, 0x00, 0x09,
- 0xcf, 0x30, 0x00, 0x09, 0x0c, 0x40, 0x00, 0x14,
- 0x00, 0x60, 0x00, 0x14, 0x00, 0x04, 0x61, 0xa8,
- 0x02, 0x04, 0x61, 0xa8, 0x0c, 0x60, 0x04, 0x24,
- 0x00, 0x00, 0x34, 0x49, 0x08, 0x50, 0x00, 0x44,
- 0x44, 0x04, 0x04, 0x39, 0x00, 0x00, 0x40, 0x45,
- 0x08, 0x30, 0x61, 0x0a, 0x05, 0xb0, 0xe8, 0x18,
- 0x0c, 0xc0, 0x04, 0x54, 0xc8, 0x30, 0x04, 0x19,
- 0x09, 0x04, 0x00, 0xa8, 0x0b, 0x04, 0x00, 0xa8,
- 0x00, 0x00, 0x40, 0x45, 0x09, 0x04, 0x61, 0xa8,
- 0xc1, 0x00, 0x04, 0x19, 0x0b, 0x04, 0x61, 0xa8,
- 0xca, 0x00, 0x04, 0x19, 0x0d, 0x00, 0x61, 0x0a,
- 0x00, 0x01, 0x00, 0x45, 0x0f, 0x00, 0x61, 0x0a,
- 0x00, 0x40, 0x09, 0x8f, 0x00, 0x01, 0x00, 0x45,
- 0x40, 0x40, 0x09, 0xef, 0xff, 0x20, 0x09, 0xcf,
- 0x00, 0x04, 0x63, 0xa1, 0x50, 0x03, 0x33, 0x80,
- 0x00, 0x04, 0xa3, 0x80, 0x00, 0xff, 0xc2, 0x8b,
- 0x0c, 0x12, 0x04, 0x54, 0x08, 0x12, 0x00, 0xc4,
- 0x20, 0x03, 0x80, 0xc0, 0x30, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x7a, 0x0a, 0xd0, 0x01, 0x00, 0x82,
- 0x04, 0x50, 0x00, 0x44, 0xc0, 0x00, 0x00, 0x99,
- 0x04, 0x50, 0x00, 0x44, 0x00, 0xff, 0xc2, 0x8b,
- 0x20, 0x00, 0x00, 0x80, 0x00, 0x0d, 0x42, 0x8b,
- 0x04, 0x42, 0x00, 0xc4, 0x00, 0x0e, 0x42, 0x8b,
- 0x08, 0x52, 0x00, 0xc4, 0x00, 0x1e, 0x42, 0x8b,
- 0x00, 0xe2, 0x00, 0xc4, 0x00, 0x8e, 0x42, 0x8b,
- 0x08, 0xd2, 0x00, 0xc4, 0x00, 0x9e, 0x42, 0x8b,
- 0x04, 0xf2, 0x00, 0xc4, 0x00, 0xbe, 0x42, 0x8b,
- 0x04, 0xf2, 0x00, 0xc4, 0x00, 0x04, 0x42, 0x8b,
- 0x04, 0x11, 0x00, 0xc4, 0x00, 0x24, 0x42, 0x8b,
- 0x0c, 0x61, 0x00, 0xc4, 0x00, 0x55, 0x42, 0x8b,
- 0x04, 0x50, 0x00, 0xc4, 0x00, 0x3f, 0x42, 0x8b,
- 0x0c, 0x01, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
- 0x20, 0x01, 0x79, 0x80, 0x00, 0x30, 0x42, 0x8b,
- 0x04, 0x62, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
- 0x00, 0x00, 0x71, 0x8b, 0x40, 0x01, 0x00, 0x80,
- 0x04, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
- 0x08, 0xc2, 0x00, 0xc4, 0x0f, 0xf2, 0xa8, 0xa8,
- 0x20, 0x00, 0xb1, 0x88, 0x00, 0x00, 0x41, 0x02,
- 0x4d, 0xf2, 0x00, 0x39, 0xc0, 0x01, 0x00, 0x82,
- 0x04, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0xa3, 0xa8,
- 0x4d, 0xf2, 0x00, 0x39, 0x04, 0x50, 0x00, 0x44,
- 0xff, 0x00, 0xe2, 0xab, 0x20, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x61, 0x02, 0x4d, 0xf2, 0x04, 0x19,
- 0x04, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
- 0xa0, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x10,
- 0x4d, 0xf2, 0x04, 0x19, 0x04, 0x50, 0x00, 0x44,
- 0xff, 0x20, 0xe2, 0xab, 0x60, 0x00, 0x00, 0x88,
- 0x00, 0x00, 0x71, 0xc0, 0x4d, 0xf2, 0x04, 0x19,
- 0x04, 0x50, 0x00, 0x44, 0x00, 0x00, 0x7a, 0x0a,
- 0x20, 0x01, 0xf0, 0x80, 0x01, 0xa0, 0x41, 0x0a,
- 0x00, 0x11, 0x00, 0xc4, 0x20, 0x01, 0xf0, 0x80,
- 0xc1, 0x30, 0x04, 0x19, 0x04, 0x50, 0x00, 0x44,
- 0x00, 0x00, 0x79, 0x80, 0x0c, 0x41, 0x00, 0x84,
- 0x89, 0x00, 0x71, 0x8b, 0xc8, 0x30, 0x04, 0x19,
- 0x97, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x00, 0x39,
- 0x00, 0x01, 0xb1, 0x80, 0x80, 0x00, 0x04, 0x19,
- 0x82, 0x00, 0x04, 0x19, 0xc1, 0x20, 0x04, 0x19,
- 0xc3, 0x20, 0x04, 0x19, 0xc2, 0x30, 0x04, 0x19,
- 0xcd, 0x10, 0x04, 0x19, 0xcf, 0x10, 0x04, 0x19,
- 0xb0, 0x00, 0x71, 0x8b, 0x84, 0x00, 0x04, 0x19,
- 0x86, 0x00, 0x04, 0x19, 0x80, 0x00, 0x71, 0x8b,
- 0xcb, 0x20, 0x04, 0x19, 0x93, 0x00, 0x01, 0x4f,
- 0xcd, 0x30, 0x00, 0x09, 0xcf, 0x30, 0x00, 0x09,
- 0x03, 0x02, 0x04, 0x49, 0x08, 0x41, 0x00, 0x14,
- 0x04, 0x50, 0x00, 0x44, 0x00, 0x00, 0x63, 0x80,
- 0x00, 0x00, 0x06, 0x19, 0x03, 0x00, 0x04, 0x49,
- 0x04, 0x50, 0x00, 0x44, 0x20, 0x01, 0x63, 0x80,
- 0x00, 0x00, 0x06, 0x19, 0x00, 0x20, 0xe2, 0x8b,
- 0x00, 0xc1, 0x00, 0x84, 0x47, 0x00, 0x51, 0x8b,
- 0xc0, 0x20, 0x00, 0x39, 0x00, 0x00, 0x63, 0x80,
- 0xc1, 0xa0, 0x04, 0x19, 0x00, 0xe1, 0x00, 0x44,
- 0xbd, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
- 0x00, 0x00, 0xb1, 0x80, 0xc1, 0xa0, 0x04, 0x19,
- 0x03, 0x00, 0x04, 0x49, 0x04, 0x50, 0x00, 0x44,
- 0x00, 0x20, 0x61, 0x0a, 0x00, 0x01, 0x00, 0x45,
- 0x02, 0x30, 0x61, 0x0a, 0x0c, 0x83, 0x00, 0xc4,
- 0x0c, 0x78, 0x08, 0x44, 0x04, 0x5a, 0x08, 0x44,
- 0xb2, 0x00, 0x09, 0x4f, 0x10, 0x42, 0x09, 0x8e,
- 0x05, 0xb0, 0xe0, 0x18, 0x04, 0x23, 0x00, 0x84,
- 0x0c, 0x01, 0x00, 0x11, 0x08, 0x05, 0x61, 0x10,
- 0x00, 0x49, 0x08, 0x44, 0x00, 0x48, 0x08, 0x44,
- 0xb2, 0x00, 0x09, 0x4f, 0x80, 0x00, 0x71, 0x8b,
- 0xc0, 0x00, 0x00, 0x82, 0x0c, 0x01, 0x33, 0x10,
- 0x28, 0x01, 0xa3, 0x10, 0x00, 0x01, 0x7a, 0x80,
- 0x8c, 0x01, 0x00, 0x80, 0x02, 0x30, 0x61, 0x0a,
- 0x20, 0x00, 0x04, 0x19, 0x0c, 0x83, 0x00, 0xc4,
- 0x05, 0xb0, 0xc8, 0x18, 0x08, 0x43, 0x00, 0xc4,
- 0x01, 0x30, 0xc8, 0x0a, 0x0c, 0x38, 0x00, 0xc4,
- 0x08, 0x88, 0x00, 0x44, 0x0c, 0x78, 0x08, 0x44,
- 0x04, 0x5a, 0x08, 0x44, 0x00, 0x00, 0xa3, 0x18,
- 0x80, 0x00, 0x04, 0x19, 0x0b, 0x04, 0x61, 0xa8,
- 0xc3, 0x20, 0x00, 0x39, 0xc3, 0x30, 0x04, 0x19,
- 0x0f, 0x10, 0x61, 0x0a, 0xca, 0x30, 0x04, 0x19,
- 0x09, 0x04, 0x41, 0xa8, 0xe1, 0x20, 0x00, 0x39,
- 0xd1, 0x00, 0x09, 0x4f, 0x00, 0x04, 0x61, 0x02,
- 0x08, 0x63, 0x00, 0x44, 0x03, 0x30, 0x41, 0x0a,
- 0x20, 0x00, 0x00, 0x39, 0xa3, 0x00, 0x09, 0x4f,
- 0x00, 0x04, 0x61, 0x02, 0x00, 0x48, 0x08, 0x44,
- 0x08, 0x88, 0x00, 0x44, 0x02, 0x30, 0x61, 0x0a,
- 0x00, 0x08, 0x00, 0xc4, 0x0c, 0x78, 0x08, 0x44,
- 0x04, 0x5a, 0x08, 0x44, 0xb2, 0x00, 0x09, 0x0f,
- 0x10, 0x40, 0x09, 0x8e, 0x00, 0x00, 0x68, 0x5b,
- 0x20, 0x04, 0xb1, 0x80, 0x02, 0x00, 0x61, 0x5b,
- 0x88, 0x03, 0x7a, 0x80, 0xac, 0x01, 0x00, 0x80,
- 0x05, 0xb0, 0xe0, 0x18, 0x00, 0xd3, 0x00, 0x84,
- 0x00, 0x49, 0x08, 0x44, 0x00, 0x48, 0x08, 0x44,
- 0xb2, 0x00, 0x09, 0x0f, 0x80, 0x00, 0x71, 0x8b,
- 0xc0, 0x00, 0x00, 0x82, 0x02, 0x30, 0x61, 0x0a,
- 0x00, 0x08, 0x00, 0xc4, 0x05, 0xb0, 0xc8, 0x18,
- 0x0c, 0x18, 0x00, 0xc4, 0x01, 0x30, 0xc8, 0x0a,
- 0x0c, 0x38, 0x00, 0xc4, 0x08, 0x88, 0x00, 0x44,
- 0x0c, 0x78, 0x08, 0x44, 0x00, 0x00, 0x61, 0x18,
- 0x20, 0x05, 0xb1, 0x80, 0x00, 0x00, 0x68, 0xcb,
- 0x80, 0x00, 0x04, 0x19, 0x0d, 0x10, 0x61, 0x0a,
- 0xc3, 0x30, 0x04, 0x19, 0x0b, 0x04, 0x41, 0xa8,
- 0x09, 0x04, 0x41, 0xa8, 0xe1, 0x20, 0x00, 0x39,
- 0x08, 0x38, 0x00, 0x44, 0x03, 0x30, 0x41, 0x0a,
- 0x20, 0x04, 0xb1, 0x80, 0x00, 0x48, 0x08, 0x44,
- 0x08, 0x88, 0x00, 0x44, 0x00, 0x00, 0xb1, 0x80,
- 0xc2, 0x30, 0x04, 0x19, 0x0c, 0xb8, 0x00, 0xd4,
- 0x0f, 0x30, 0x61, 0x0a, 0x0d, 0x30, 0xc8, 0x0a,
- 0x0c, 0xb8, 0x00, 0xc4, 0x93, 0x00, 0x01, 0x4f,
- 0xe7, 0x00, 0x01, 0x6f, 0x0f, 0x30, 0x61, 0x0a,
- 0x20, 0x00, 0x00, 0x88, 0x02, 0x00, 0x61, 0x02,
- 0x41, 0x04, 0x04, 0x19, 0x02, 0x04, 0x61, 0x02,
- 0x43, 0x04, 0x04, 0x39, 0xcf, 0x30, 0x00, 0x09,
- 0x20, 0x00, 0x09, 0x49, 0x00, 0x59, 0x00, 0x44,
- 0x93, 0x00, 0x01, 0x4f, 0xe7, 0x00, 0x01, 0x6f,
- 0x0d, 0x30, 0x61, 0x0a, 0x20, 0x00, 0x61, 0x88,
- 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x03, 0x00, 0x82,
- 0xcd, 0x30, 0x00, 0x09, 0x20, 0x00, 0x09, 0x49,
- 0x0f, 0x30, 0x61, 0x0a, 0x0d, 0x30, 0xc8, 0x0a,
- 0x0c, 0x58, 0x00, 0x84, 0x02, 0x30, 0x61, 0x0a,
- 0x05, 0xb0, 0xa8, 0x18, 0xc2, 0x30, 0x04, 0x19,
- 0x00, 0x00, 0x00, 0x46, 0x90, 0x40, 0x09, 0x8f,
- 0x12, 0x04, 0x09, 0x6e, 0x03, 0x00, 0x09, 0x0e,
- 0x00, 0x01, 0x71, 0x82, 0x20, 0x01, 0x00, 0x80,
- 0x00, 0x00, 0x61, 0xcb, 0x80, 0x04, 0xb1, 0x80,
- 0x00, 0x01, 0xe0, 0x60, 0x0c, 0xd8, 0x04, 0x14,
- 0x00, 0x01, 0xeb, 0x80, 0x40, 0x00, 0x52, 0x1b,
- 0x80, 0x00, 0x79, 0x80, 0xc0, 0x01, 0x71, 0xc2,
- 0x20, 0x00, 0xc0, 0x80, 0x08, 0x0a, 0x04, 0x54,
- 0xc0, 0x04, 0xa8, 0x82, 0x80, 0x00, 0x72, 0x1b,
- 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
- 0x20, 0x00, 0xc0, 0x80, 0x0c, 0x2a, 0x04, 0x54,
- 0xc0, 0x04, 0xa8, 0x82, 0x10, 0x00, 0x72, 0x1b,
- 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
- 0x20, 0x00, 0xc0, 0x80, 0x08, 0x3a, 0x04, 0x54,
- 0xc0, 0x04, 0xa8, 0x82, 0x20, 0x00, 0x72, 0x1b,
- 0x80, 0x00, 0x00, 0x80, 0xc0, 0x03, 0xf0, 0x82,
- 0x20, 0x00, 0xa0, 0x80, 0x00, 0x01, 0x00, 0x11,
- 0x40, 0x00, 0xc2, 0x8b, 0x00, 0xaa, 0x00, 0xc4,
- 0x00, 0x00, 0xe9, 0x80, 0x05, 0xb0, 0xa8, 0x18,
- 0x00, 0x01, 0xa8, 0x22, 0xd0, 0x01, 0x00, 0x82,
- 0xf0, 0x00, 0xe2, 0x1b, 0x06, 0x20, 0xa8, 0x0a,
- 0x2d, 0x10, 0x61, 0x0a, 0xd1, 0x00, 0x09, 0x2e,
- 0x00, 0x01, 0xa8, 0x02, 0x0e, 0x10, 0xc8, 0x0a,
- 0x0c, 0xba, 0x04, 0x14, 0x0e, 0x10, 0x61, 0x0a,
- 0x04, 0x4a, 0x00, 0x44, 0x0c, 0x10, 0xc8, 0x0a,
- 0x04, 0x4a, 0x04, 0x54, 0x0c, 0x10, 0x61, 0x0a,
- 0xd0, 0x01, 0x00, 0x82, 0x00, 0x10, 0xa8, 0x18,
- 0xa0, 0x00, 0x00, 0x88, 0x00, 0x01, 0x71, 0x82,
- 0x03, 0x00, 0x09, 0x0e, 0x9a, 0x01, 0x00, 0x60,
- 0x32, 0x00, 0x09, 0x2e, 0x00, 0x00, 0x00, 0x46,
- 0x00, 0x01, 0x71, 0x82, 0x20, 0x01, 0x00, 0x80,
- 0x00, 0x00, 0x61, 0xcb, 0x80, 0x24, 0xb1, 0xc0,
- 0x00, 0x31, 0xe0, 0x60, 0x0c, 0xca, 0x04, 0x14,
- 0x00, 0x01, 0xeb, 0x80, 0x40, 0x00, 0x52, 0x1b,
- 0x80, 0x00, 0x79, 0x80, 0xc0, 0x01, 0x71, 0xc2,
- 0x20, 0x00, 0xc0, 0x80, 0x08, 0xda, 0x04, 0x54,
- 0xc0, 0x04, 0xa8, 0x82, 0x80, 0x00, 0x72, 0x1b,
- 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
- 0x20, 0x00, 0xc0, 0x80, 0x0c, 0xfa, 0x04, 0x54,
- 0xc0, 0x04, 0xa8, 0x82, 0x10, 0x00, 0x72, 0x1b,
- 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
- 0x20, 0x00, 0xc0, 0x80, 0x08, 0x29, 0x04, 0x54,
- 0xc0, 0x04, 0xa8, 0x82, 0x20, 0x00, 0x72, 0x1b,
- 0x80, 0x00, 0x00, 0x80, 0xc0, 0x03, 0xf0, 0x82,
- 0x20, 0x00, 0xa0, 0x80, 0x00, 0x01, 0x00, 0x11,
- 0x40, 0x00, 0xc2, 0x8b, 0x00, 0x39, 0x00, 0xc4,
- 0x00, 0x00, 0xe9, 0x80, 0x05, 0xb0, 0xa8, 0x18,
- 0x00, 0x01, 0xa8, 0x22, 0xd0, 0x01, 0x00, 0x82,
- 0xb0, 0x00, 0xe2, 0x1b, 0x06, 0x20, 0xa8, 0x0a,
- 0x2f, 0x10, 0x61, 0x0a, 0xf1, 0x00, 0x09, 0x2e,
- 0x00, 0x01, 0xa8, 0x02, 0x0e, 0x10, 0xc8, 0x0a,
- 0x0c, 0xa9, 0x04, 0x14, 0x0e, 0x10, 0x61, 0x0a,
- 0x04, 0x99, 0x00, 0x44, 0x0c, 0x10, 0xc8, 0x0a,
- 0x04, 0x99, 0x04, 0x54, 0x0c, 0x10, 0x61, 0x0a,
- 0xd0, 0x01, 0x00, 0x82, 0x00, 0x10, 0xa8, 0x18,
- 0xa0, 0x00, 0x00, 0x88, 0x00, 0x01, 0x71, 0x82,
- 0x9f, 0x01, 0x00, 0x60, 0x00, 0x00, 0x00, 0x46,
- 0x00, 0x00, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
- 0x20, 0x00, 0x7a, 0x80, 0x20, 0x07, 0x33, 0x80,
- 0x00, 0x00, 0x83, 0x80, 0x20, 0x04, 0x7a, 0x80,
- 0x20, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x46,
- 0x02, 0x00, 0x61, 0x0a, 0x04, 0x1b, 0x04, 0x14,
- 0x01, 0x00, 0x61, 0x0a, 0x03, 0x00, 0x48, 0x0a,
- 0x0c, 0x79, 0x04, 0x54, 0xc3, 0x00, 0x04, 0x19,
- 0x04, 0xc9, 0x00, 0x44, 0x08, 0x00, 0xc8, 0x0a,
- 0x04, 0xc9, 0x04, 0x54, 0xc8, 0x00, 0x04, 0x19,
- 0x0a, 0x00, 0x61, 0x0a, 0x09, 0x00, 0x48, 0x0a,
- 0x0c, 0xe9, 0x04, 0x54, 0xc9, 0x00, 0x04, 0x19,
- 0x04, 0xd9, 0x00, 0x44, 0x0b, 0x00, 0xc8, 0x0a,
- 0x04, 0xd9, 0x04, 0x54, 0xcb, 0x00, 0x04, 0x19,
- 0x04, 0x00, 0x61, 0x0a, 0x06, 0x00, 0x48, 0x0a,
- 0x0c, 0xf9, 0x04, 0x54, 0xc6, 0x00, 0x04, 0x19,
- 0x04, 0x0b, 0x00, 0x44, 0x05, 0x00, 0xc8, 0x0a,
- 0x04, 0x0b, 0x04, 0x54, 0xc5, 0x00, 0x04, 0x19,
- 0x07, 0x00, 0x61, 0x0a, 0x0c, 0x00, 0x48, 0x0a,
- 0x0c, 0x2b, 0x04, 0x54, 0xcc, 0x00, 0x04, 0x19,
- 0x04, 0x1b, 0x00, 0x44, 0x0e, 0x00, 0xc8, 0x0a,
- 0x04, 0x1b, 0x04, 0x54, 0xce, 0x00, 0x04, 0x19,
- 0x00, 0x00, 0x40, 0x45, 0x92, 0x20, 0x71, 0x8b,
- 0xa6, 0xc5, 0x11, 0x00
-};
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index f183f1845a3..0bbcd4714d2 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of 16-bit SoundBlaster cards and clones
* Note: This is very ugly hardware which uses one 8-bit DMA channel and
* second 16-bit DMA channel. Unfortunately 8-bit DMA channel can't
@@ -33,11 +33,11 @@
*
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/time.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/sb16_csp.h>
@@ -45,7 +45,7 @@
#include <sound/control.h>
#include <sound/info.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones");
MODULE_LICENSE("GPL");
@@ -395,7 +395,7 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream,
return result;
}
-irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
{
struct snd_sb *chip = dev_id;
unsigned char status;
@@ -405,7 +405,7 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
spin_unlock(&chip->mixer_lock);
if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback)
- chip->rmidi_callback(irq, chip->rmidi->private_data, regs);
+ chip->rmidi_callback(irq, chip->rmidi->private_data);
if (status & SB_IRQTYPE_8BIT) {
ok = 0;
if (chip->mode & SB_MODE_PLAYBACK_8) {
@@ -563,6 +563,11 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream)
__open_ok:
if (chip->hardware == SB_HW_ALS100)
runtime->hw.rate_max = 48000;
+ if (chip->hardware == SB_HW_CS5530) {
+ runtime->hw.buffer_bytes_max = 32 * 1024;
+ runtime->hw.periods_min = 2;
+ runtime->hw.rate_min = 44100;
+ }
if (chip->mode & SB_RATE_LOCK)
runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
chip->playback_substream = substream;
@@ -633,6 +638,11 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream)
__open_ok:
if (chip->hardware == SB_HW_ALS100)
runtime->hw.rate_max = 48000;
+ if (chip->hardware == SB_HW_CS5530) {
+ runtime->hw.buffer_bytes_max = 32 * 1024;
+ runtime->hw.periods_min = 2;
+ runtime->hw.rate_min = 44100;
+ }
if (chip->mode & SB_RATE_LOCK)
runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
chip->capture_substream = substream;
@@ -660,7 +670,8 @@ static int snd_sb16_capture_close(struct snd_pcm_substream *substream)
static int snd_sb16_set_dma_mode(struct snd_sb *chip, int what)
{
if (chip->dma8 < 0 || chip->dma16 < 0) {
- snd_assert(what == 0, return -EINVAL);
+ if (snd_BUG_ON(what))
+ return -EINVAL;
return 0;
}
if (what == 0) {
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 60ee79cd14a..6c32b3aa34a 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -1,6 +1,6 @@
/*
* Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,26 +19,24 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <linux/isa.h>
#include <linux/ioport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/opl3.h>
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3 */
@@ -56,14 +54,12 @@ MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");
module_param_array(dma8, int, NULL, 0444);
MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
-static struct platform_device *devices[SNDRV_CARDS];
-
struct snd_sb8 {
struct resource *fm_res; /* used to block FM i/o region for legacy cards */
struct snd_sb *chip;
};
-static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
{
struct snd_sb *chip = dev_id;
@@ -76,26 +72,40 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs
static void snd_sb8_free(struct snd_card *card)
{
- struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
+ struct snd_sb8 *acard = card->private_data;
if (acard == NULL)
return;
release_and_free_resource(acard->fm_res);
}
-static int __init snd_sb8_probe(struct platform_device *pdev)
+static int snd_sb8_match(struct device *pdev, unsigned int dev)
+{
+ if (!enable[dev])
+ return 0;
+ if (irq[dev] == SNDRV_AUTO_IRQ) {
+ dev_err(pdev, "please specify irq\n");
+ return 0;
+ }
+ if (dma8[dev] == SNDRV_AUTO_DMA) {
+ dev_err(pdev, "please specify dma8\n");
+ return 0;
+ }
+ return 1;
+}
+
+static int snd_sb8_probe(struct device *pdev, unsigned int dev)
{
- int dev = pdev->id;
struct snd_sb *chip;
struct snd_card *card;
struct snd_sb8 *acard;
struct snd_opl3 *opl3;
int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_sb8));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_sb8), &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
card->private_free = snd_sb8_free;
@@ -129,8 +139,10 @@ static int __init snd_sb8_probe(struct platform_device *pdev)
break;
}
}
- if (i >= ARRAY_SIZE(possible_ports))
+ if (i >= ARRAY_SIZE(possible_ports)) {
+ err = -EINVAL;
goto _err;
+ }
}
acard->chip = chip;
@@ -180,12 +192,10 @@ static int __init snd_sb8_probe(struct platform_device *pdev)
chip->port,
irq[dev], dma8[dev]);
- snd_card_set_dev(card, &pdev->dev);
-
if ((err = snd_card_register(card)) < 0)
goto _err;
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(pdev, card);
return 0;
_err:
@@ -193,17 +203,17 @@ static int __init snd_sb8_probe(struct platform_device *pdev)
return err;
}
-static int snd_sb8_remove(struct platform_device *pdev)
+static int snd_sb8_remove(struct device *pdev, unsigned int dev)
{
- snd_card_free(platform_get_drvdata(pdev));
- platform_set_drvdata(pdev, NULL);
+ snd_card_free(dev_get_drvdata(pdev));
return 0;
}
#ifdef CONFIG_PM
-static int snd_sb8_suspend(struct platform_device *dev, pm_message_t state)
+static int snd_sb8_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
{
- struct snd_card *card = platform_get_drvdata(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct snd_sb8 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
@@ -213,9 +223,9 @@ static int snd_sb8_suspend(struct platform_device *dev, pm_message_t state)
return 0;
}
-static int snd_sb8_resume(struct platform_device *dev)
+static int snd_sb8_resume(struct device *dev, unsigned int n)
{
- struct snd_card *card = platform_get_drvdata(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct snd_sb8 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
@@ -226,9 +236,10 @@ static int snd_sb8_resume(struct platform_device *dev)
}
#endif
-#define SND_SB8_DRIVER "snd_sb8"
+#define DEV_NAME "sb8"
-static struct platform_driver snd_sb8_driver = {
+static struct isa_driver snd_sb8_driver = {
+ .match = snd_sb8_match,
.probe = snd_sb8_probe,
.remove = snd_sb8_remove,
#ifdef CONFIG_PM
@@ -236,56 +247,18 @@ static struct platform_driver snd_sb8_driver = {
.resume = snd_sb8_resume,
#endif
.driver = {
- .name = SND_SB8_DRIVER
+ .name = DEV_NAME
},
};
-static void __init_or_module snd_sb8_unregister_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_sb8_driver);
-}
-
static int __init alsa_card_sb8_init(void)
{
- int i, cards, err;
-
- err = platform_driver_register(&snd_sb8_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(SND_SB8_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
- }
- if (!cards) {
-#ifdef MODULE
- snd_printk(KERN_ERR "Sound Blaster soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_sb8_unregister_all();
- return err;
+ return isa_register_driver(&snd_sb8_driver, SNDRV_CARDS);
}
static void __exit alsa_card_sb8_exit(void)
{
- snd_sb8_unregister_all();
+ isa_unregister_driver(&snd_sb8_driver);
}
module_init(alsa_card_sb8_init)
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
index aea9e5ec7b3..24d4121ab0e 100644
--- a/sound/isa/sb/sb8_main.c
+++ b/sound/isa/sb/sb8_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Uros Bizjak <uros@kss-loka.si>
*
* Routines for control of 8-bit SoundBlaster cards and clones
@@ -30,15 +30,15 @@
* Cleaned up and rewrote lowlevel routines.
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/time.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/sb.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Uros Bizjak <uros@kss-loka.si>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Uros Bizjak <uros@kss-loka.si>");
MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones");
MODULE_LICENSE("GPL");
@@ -107,12 +107,26 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int mixreg, rate, size, count;
+ unsigned char format;
+ unsigned char stereo = runtime->channels > 1;
+ int dma;
rate = runtime->rate;
switch (chip->hardware) {
+ case SB_HW_JAZZ16:
+ if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
+ if (chip->mode & SB_MODE_CAPTURE_16)
+ return -EBUSY;
+ else
+ chip->mode |= SB_MODE_PLAYBACK_16;
+ }
+ chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
+ break;
case SB_HW_PRO:
if (runtime->channels > 1) {
- snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
+ if (snd_BUG_ON(rate != SB8_RATE(11025) &&
+ rate != SB8_RATE(22050)))
+ return -EINVAL;
chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
break;
}
@@ -132,11 +146,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
default:
return -EINVAL;
}
+ if (chip->mode & SB_MODE_PLAYBACK_16) {
+ format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
+ dma = chip->dma16;
+ } else {
+ format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
+ chip->mode |= SB_MODE_PLAYBACK_8;
+ dma = chip->dma8;
+ }
size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
spin_lock_irqsave(&chip->reg_lock, flags);
snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
- if (runtime->channels > 1) {
+ if (chip->hardware == SB_HW_JAZZ16)
+ snd_sbdsp_command(chip, format);
+ else if (stereo) {
/* set playback stereo mode */
spin_lock(&chip->mixer_lock);
mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
@@ -146,15 +170,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
/* Soundblaster hardware programming reference guide, 3-23 */
snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
runtime->dma_area[0] = 0x80;
- snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE);
+ snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
/* force interrupt */
- chip->mode = SB_MODE_HALT;
snd_sbdsp_command(chip, SB_DSP_OUTPUT);
snd_sbdsp_command(chip, 0);
snd_sbdsp_command(chip, 0);
}
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
- if (runtime->channels > 1) {
+ if (stereo) {
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
spin_lock(&chip->mixer_lock);
/* save output filter status and turn it off */
@@ -167,13 +190,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
snd_sbdsp_command(chip, 256 - runtime->rate_den);
}
if (chip->playback_format != SB_DSP_OUTPUT) {
+ if (chip->mode & SB_MODE_PLAYBACK_16)
+ count /= 2;
count--;
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
snd_sbdsp_command(chip, count & 0xff);
snd_sbdsp_command(chip, count >> 8);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_dma_program(chip->dma8, runtime->dma_addr,
+ snd_dma_program(dma, runtime->dma_addr,
size, DMA_MODE_WRITE | DMA_AUTOINIT);
return 0;
}
@@ -211,7 +236,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
- chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT;
return 0;
}
@@ -233,12 +257,26 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int mixreg, rate, size, count;
+ unsigned char format;
+ unsigned char stereo = runtime->channels > 1;
+ int dma;
rate = runtime->rate;
switch (chip->hardware) {
+ case SB_HW_JAZZ16:
+ if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
+ if (chip->mode & SB_MODE_PLAYBACK_16)
+ return -EBUSY;
+ else
+ chip->mode |= SB_MODE_CAPTURE_16;
+ }
+ chip->capture_format = SB_DSP_LO_INPUT_AUTO;
+ break;
case SB_HW_PRO:
if (runtime->channels > 1) {
- snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
+ if (snd_BUG_ON(rate != SB8_RATE(11025) &&
+ rate != SB8_RATE(22050)))
+ return -EINVAL;
chip->capture_format = SB_DSP_HI_INPUT_AUTO;
break;
}
@@ -259,14 +297,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
default:
return -EINVAL;
}
+ if (chip->mode & SB_MODE_CAPTURE_16) {
+ format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
+ dma = chip->dma16;
+ } else {
+ format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
+ chip->mode |= SB_MODE_CAPTURE_8;
+ dma = chip->dma8;
+ }
size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
spin_lock_irqsave(&chip->reg_lock, flags);
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
- if (runtime->channels > 1)
+ if (chip->hardware == SB_HW_JAZZ16)
+ snd_sbdsp_command(chip, format);
+ else if (stereo)
snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
- if (runtime->channels > 1) {
+ if (stereo) {
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
spin_lock(&chip->mixer_lock);
/* save input filter status and turn it off */
@@ -278,14 +326,16 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
} else {
snd_sbdsp_command(chip, 256 - runtime->rate_den);
}
- if (chip->capture_format != SB_DSP_OUTPUT) {
+ if (chip->capture_format != SB_DSP_INPUT) {
+ if (chip->mode & SB_MODE_PLAYBACK_16)
+ count /= 2;
count--;
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
snd_sbdsp_command(chip, count & 0xff);
snd_sbdsp_command(chip, count >> 8);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_dma_program(chip->dma8, runtime->dma_addr,
+ snd_dma_program(dma, runtime->dma_addr,
size, DMA_MODE_READ | DMA_AUTOINIT);
return 0;
}
@@ -325,7 +375,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
- chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT;
return 0;
}
@@ -336,13 +385,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
snd_sb_ack_8bit(chip);
switch (chip->mode) {
- case SB_MODE_PLAYBACK_8: /* ok.. playback is active */
+ case SB_MODE_PLAYBACK_16: /* ok.. playback is active */
+ if (chip->hardware != SB_HW_JAZZ16)
+ break;
+ /* fallthru */
+ case SB_MODE_PLAYBACK_8:
substream = chip->playback_substream;
runtime = substream->runtime;
if (chip->playback_format == SB_DSP_OUTPUT)
snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
snd_pcm_period_elapsed(substream);
break;
+ case SB_MODE_CAPTURE_16:
+ if (chip->hardware != SB_HW_JAZZ16)
+ break;
+ /* fallthru */
case SB_MODE_CAPTURE_8:
substream = chip->capture_substream;
runtime = substream->runtime;
@@ -358,10 +415,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
size_t ptr;
+ int dma;
- if (chip->mode != SB_MODE_PLAYBACK_8)
+ if (chip->mode & SB_MODE_PLAYBACK_8)
+ dma = chip->dma8;
+ else if (chip->mode & SB_MODE_PLAYBACK_16)
+ dma = chip->dma16;
+ else
return 0;
- ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size);
+ ptr = snd_dma_pointer(dma, chip->p_dma_size);
return bytes_to_frames(substream->runtime, ptr);
}
@@ -369,10 +431,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
size_t ptr;
+ int dma;
- if (chip->mode != SB_MODE_CAPTURE_8)
+ if (chip->mode & SB_MODE_CAPTURE_8)
+ dma = chip->dma8;
+ else if (chip->mode & SB_MODE_CAPTURE_16)
+ dma = chip->dma16;
+ else
return 0;
- ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size);
+ ptr = snd_dma_pointer(dma, chip->c_dma_size);
return bytes_to_frames(substream->runtime, ptr);
}
@@ -443,6 +510,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
runtime->hw = snd_sb8_capture;
}
switch (chip->hardware) {
+ case SB_HW_JAZZ16:
+ if (chip->dma16 == 5 || chip->dma16 == 7)
+ runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
+ runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;
+ runtime->hw.rate_min = 4000;
+ runtime->hw.rate_max = 50000;
+ runtime->hw.channels_max = 2;
+ break;
case SB_HW_PRO:
runtime->hw.rate_max = 44100;
runtime->hw.channels_max = 2;
@@ -465,6 +540,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
}
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hw_constraints_clock);
+ if (chip->dma8 > 3 || chip->dma16 >= 0) {
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);
+ runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;
+ runtime->hw.period_bytes_max = 128 * 1024 * 1024;
+ }
return 0;
}
@@ -477,6 +560,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream)
chip->capture_substream = NULL;
spin_lock_irqsave(&chip->open_lock, flags);
chip->open &= ~SB_OPEN_PCM;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ chip->mode &= ~SB_MODE_PLAYBACK;
+ else
+ chip->mode &= ~SB_MODE_CAPTURE;
spin_unlock_irqrestore(&chip->open_lock, flags);
return 0;
}
@@ -512,6 +599,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
struct snd_card *card = chip->card;
struct snd_pcm *pcm;
int err;
+ size_t max_prealloc = 64 * 1024;
if (rpcm)
*rpcm = NULL;
@@ -524,9 +612,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
+ if (chip->dma8 > 3 || chip->dma16 >= 0)
+ max_prealloc = 128 * 1024;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_isa_data(),
- 64*1024, 64*1024);
+ 64*1024, max_prealloc);
if (rpcm)
*rpcm = pcm;
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
index c549aceea29..988a8b73475 100644
--- a/sound/isa/sb/sb8_midi.c
+++ b/sound/isa/sb/sb8_midi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of SoundBlaster cards - MIDI interface
*
* This program is free software; you can redistribute it and/or modify
@@ -26,26 +26,27 @@
* Added full duplex UART mode for DSP version 2.0 and later.
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/sb.h>
-/*
-
- */
-irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip)
+irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip)
{
struct snd_rawmidi *rmidi;
int max = 64;
char byte;
- if (chip == NULL || (rmidi = chip->rmidi) == NULL) {
+ if (!chip)
+ return IRQ_NONE;
+
+ rmidi = chip->rmidi;
+ if (!rmidi) {
inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */
return IRQ_NONE;
}
+
spin_lock(&chip->midi_input_lock);
while (max-- > 0) {
if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
@@ -59,10 +60,6 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip)
return IRQ_HANDLED;
}
-/*
-
- */
-
static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
@@ -252,10 +249,6 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
snd_sb8dsp_midi_output_write(substream);
}
-/*
-
- */
-
static struct snd_rawmidi_ops snd_sb8dsp_midi_output =
{
.open = snd_sb8dsp_midi_output_open,
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index f343a8211d2..3ef990602cd 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Uros Bizjak <uros@kss-loka.si>
*
* Lowlevel routines for control of Sound Blaster cards
@@ -20,12 +20,12 @@
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/ioport.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/initval.h>
@@ -33,7 +33,7 @@
#include <asm/io.h>
#include <asm/dma.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards");
MODULE_LICENSE("GPL");
@@ -52,7 +52,7 @@ int snd_sbdsp_command(struct snd_sb *chip, unsigned char val)
outb(val, SBP(chip, COMMAND));
return 1;
}
- snd_printd("%s [0x%lx]: timeout (0x%x)\n", __FUNCTION__, chip->port, val);
+ snd_printd("%s [0x%lx]: timeout (0x%x)\n", __func__, chip->port, val);
return 0;
}
@@ -69,7 +69,7 @@ int snd_sbdsp_get_byte(struct snd_sb *chip)
return val;
}
}
- snd_printd("%s [0x%lx]: timeout\n", __FUNCTION__, chip->port);
+ snd_printd("%s [0x%lx]: timeout\n", __func__, chip->port);
return -ENODEV;
}
@@ -88,7 +88,7 @@ int snd_sbdsp_reset(struct snd_sb *chip)
else
break;
}
- snd_printdd("%s [0x%lx] failed...\n", __FUNCTION__, chip->port);
+ snd_printdd("%s [0x%lx] failed...\n", __func__, chip->port);
return -ENODEV;
}
@@ -128,7 +128,7 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
minor = version & 0xff;
snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
chip->port, major, minor);
-
+
switch (chip->hardware) {
case SB_HW_AUTO:
switch (major) {
@@ -168,6 +168,12 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
case SB_HW_DT019X:
str = "(DT019X/ALS007)";
break;
+ case SB_HW_CS5530:
+ str = "16 (CS5530)";
+ break;
+ case SB_HW_JAZZ16:
+ str = "Pro (Jazz16)";
+ break;
default:
return -ENODEV;
}
@@ -205,7 +211,7 @@ static int snd_sbdsp_dev_free(struct snd_device *device)
int snd_sbdsp_create(struct snd_card *card,
unsigned long port,
int irq,
- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
+ irq_handler_t irq_handler,
int dma8,
int dma16,
unsigned short hardware,
@@ -217,7 +223,8 @@ int snd_sbdsp_create(struct snd_card *card,
.dev_free = snd_sbdsp_dev_free,
};
- snd_assert(r_chip != NULL, return -EINVAL);
+ if (snd_BUG_ON(!r_chip))
+ return -EINVAL;
*r_chip = NULL;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
@@ -231,8 +238,10 @@ int snd_sbdsp_create(struct snd_card *card,
chip->dma16 = -1;
chip->port = port;
- if (request_irq(irq, irq_handler, hardware == SB_HW_ALS4000 ?
- SA_INTERRUPT | SA_SHIRQ : SA_INTERRUPT,
+ if (request_irq(irq, irq_handler,
+ (hardware == SB_HW_ALS4000 ||
+ hardware == SB_HW_CS5530) ?
+ IRQF_SHARED : 0,
"SoundBlaster", (void *) chip)) {
snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq);
snd_sbdsp_free(chip);
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 1a6ee344ddd..1ff78ec9f0a 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for Sound Blaster mixer control
*
*
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/time.h>
@@ -183,7 +182,7 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = {
+ static const char *texts[5] = {
"CD", "Mic", "Line", "Synth", "Master"
};
@@ -270,12 +269,73 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl
}
/*
+ * ALS4000 mono recording control switch
+ */
+
+static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char *texts[3] = {
+ "L chan only", "R chan only", "L ch/2 + R ch/2"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item > 2)
+ uinfo->value.enumerated.item = 2;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ unsigned char oval;
+
+ spin_lock_irqsave(&sb->mixer_lock, flags);
+ oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
+ spin_unlock_irqrestore(&sb->mixer_lock, flags);
+ oval >>= 6;
+ if (oval > 2)
+ oval = 2;
+
+ ucontrol->value.enumerated.item[0] = oval;
+ return 0;
+}
+
+static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int change;
+ unsigned char nval, oval;
+
+ if (ucontrol->value.enumerated.item[0] > 2)
+ return -EINVAL;
+ spin_lock_irqsave(&sb->mixer_lock, flags);
+ oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
+
+ nval = (oval & ~(3 << 6))
+ | (ucontrol->value.enumerated.item[0] << 6);
+ change = nval != oval;
+ if (change)
+ snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
+ spin_unlock_irqrestore(&sb->mixer_lock, flags);
+ return change;
+}
+
+/*
* SBPRO input multiplexer
*/
static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char *texts[3] = {
"Mic", "CD", "Line"
};
@@ -443,6 +503,12 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
.get = snd_dt019x_input_sw_get,
.put = snd_dt019x_input_sw_put,
},
+ [SB_MIX_MONO_CAPTURE_ALS4K] = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = snd_als4k_mono_capture_route_info,
+ .get = snd_als4k_mono_capture_route_get,
+ .put = snd_als4k_mono_capture_route_put,
+ },
};
struct snd_kcontrol *ctl;
int err;
@@ -453,10 +519,8 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
ctl->id.index = index;
ctl->private_value = value;
- if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
- snd_ctl_free_one(ctl);
+ if ((err = snd_ctl_add(chip->card, ctl)) < 0)
return err;
- }
return 0;
}
@@ -464,20 +528,11 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
* SB 2.0 specific mixer elements
*/
-static struct sbmix_elem snd_sb20_ctl_master_play_vol =
- SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
-static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
- SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
-static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
- SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
-static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
- SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
-
-static struct sbmix_elem *snd_sb20_controls[] = {
- &snd_sb20_ctl_master_play_vol,
- &snd_sb20_ctl_pcm_play_vol,
- &snd_sb20_ctl_synth_play_vol,
- &snd_sb20_ctl_cd_play_vol
+static struct sbmix_elem snd_sb20_controls[] = {
+ SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
+ SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
+ SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
+ SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
};
static unsigned char snd_sb20_init_values[][2] = {
@@ -488,41 +543,24 @@ static unsigned char snd_sb20_init_values[][2] = {
/*
* SB Pro specific mixer elements
*/
-static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
- SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
- SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
- SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
-static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
- SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
- SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
- SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
-static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
- SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
-static struct sbmix_elem snd_sbpro_ctl_capture_source =
+static struct sbmix_elem snd_sbpro_controls[] = {
+ SB_DOUBLE("Master Playback Volume",
+ SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
+ SB_DOUBLE("PCM Playback Volume",
+ SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
+ SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
+ SB_DOUBLE("Synth Playback Volume",
+ SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
+ SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
+ SB_DOUBLE("Line Playback Volume",
+ SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
+ SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
{
.name = "Capture Source",
.type = SB_MIX_CAPTURE_PRO
- };
-static struct sbmix_elem snd_sbpro_ctl_capture_filter =
- SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
-static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
- SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
-
-static struct sbmix_elem *snd_sbpro_controls[] = {
- &snd_sbpro_ctl_master_play_vol,
- &snd_sbpro_ctl_pcm_play_vol,
- &snd_sbpro_ctl_pcm_play_filter,
- &snd_sbpro_ctl_synth_play_vol,
- &snd_sbpro_ctl_cd_play_vol,
- &snd_sbpro_ctl_line_play_vol,
- &snd_sbpro_ctl_mic_play_vol,
- &snd_sbpro_ctl_capture_source,
- &snd_sbpro_ctl_capture_filter,
- &snd_sbpro_ctl_capture_low_filter
+ },
+ SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
+ SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
};
static unsigned char snd_sbpro_init_values[][2] = {
@@ -534,68 +572,42 @@ static unsigned char snd_sbpro_init_values[][2] = {
/*
* SB16 specific mixer elements
*/
-static struct sbmix_elem snd_sb16_ctl_master_play_vol =
- SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
- SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
-static struct sbmix_elem snd_sb16_ctl_tone_bass =
- SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
-static struct sbmix_elem snd_sb16_ctl_tone_treble =
- SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
-static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
- SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
- SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
-static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
- SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
- SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
-static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
- SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
-static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
- SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_line_capture_route =
- SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
-static struct sbmix_elem snd_sb16_ctl_line_play_switch =
- SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
-static struct sbmix_elem snd_sb16_ctl_line_play_vol =
- SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
- SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
-static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
- SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
-static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
- SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
-static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
- SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
-static struct sbmix_elem snd_sb16_ctl_capture_vol =
- SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
-static struct sbmix_elem snd_sb16_ctl_play_vol =
- SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
-static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
- SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
-
-static struct sbmix_elem *snd_sb16_controls[] = {
- &snd_sb16_ctl_master_play_vol,
- &snd_sb16_ctl_3d_enhance_switch,
- &snd_sb16_ctl_tone_bass,
- &snd_sb16_ctl_tone_treble,
- &snd_sb16_ctl_pcm_play_vol,
- &snd_sb16_ctl_synth_capture_route,
- &snd_sb16_ctl_synth_play_vol,
- &snd_sb16_ctl_cd_capture_route,
- &snd_sb16_ctl_cd_play_switch,
- &snd_sb16_ctl_cd_play_vol,
- &snd_sb16_ctl_line_capture_route,
- &snd_sb16_ctl_line_play_switch,
- &snd_sb16_ctl_line_play_vol,
- &snd_sb16_ctl_mic_capture_route,
- &snd_sb16_ctl_mic_play_switch,
- &snd_sb16_ctl_mic_play_vol,
- &snd_sb16_ctl_pc_speaker_vol,
- &snd_sb16_ctl_capture_vol,
- &snd_sb16_ctl_play_vol,
- &snd_sb16_ctl_auto_mic_gain
+static struct sbmix_elem snd_sb16_controls[] = {
+ SB_DOUBLE("Master Playback Volume",
+ SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
+ SB_DOUBLE("PCM Playback Volume",
+ SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
+ SB16_INPUT_SW("Synth Capture Route",
+ SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
+ SB_DOUBLE("Synth Playback Volume",
+ SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
+ SB16_INPUT_SW("CD Capture Route",
+ SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
+ SB_DOUBLE("CD Playback Switch",
+ SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
+ SB_DOUBLE("CD Playback Volume",
+ SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
+ SB16_INPUT_SW("Mic Capture Route",
+ SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
+ SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
+ SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
+ SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
+ SB_DOUBLE("Capture Volume",
+ SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
+ SB_DOUBLE("Playback Volume",
+ SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
+ SB16_INPUT_SW("Line Capture Route",
+ SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
+ SB_DOUBLE("Line Playback Switch",
+ SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
+ SB_DOUBLE("Line Playback Volume",
+ SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
+ SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
+ SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
+ SB_DOUBLE("Tone Control - Bass",
+ SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
+ SB_DOUBLE("Tone Control - Treble",
+ SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
};
static unsigned char snd_sb16_init_values[][2] = {
@@ -614,44 +626,34 @@ static unsigned char snd_sb16_init_values[][2] = {
/*
* DT019x specific mixer elements
*/
-static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
- SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
- SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
- SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
- SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
- SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
-static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
- SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7);
-static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
- SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
-static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
- SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
-static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
- SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
-static struct sbmix_elem snd_dt019x_ctl_capture_source =
+static struct sbmix_elem snd_dt019x_controls[] = {
+ /* ALS4000 below has some parts which we might be lacking,
+ * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
+ SB_DOUBLE("Master Playback Volume",
+ SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
+ SB_DOUBLE("PCM Playback Switch",
+ SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
+ SB_DOUBLE("PCM Playback Volume",
+ SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
+ SB_DOUBLE("Synth Playback Switch",
+ SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
+ SB_DOUBLE("Synth Playback Volume",
+ SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
+ SB_DOUBLE("CD Playback Switch",
+ SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
+ SB_DOUBLE("CD Playback Volume",
+ SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
+ SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
+ SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
+ SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7),
+ SB_DOUBLE("Line Playback Switch",
+ SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
+ SB_DOUBLE("Line Playback Volume",
+ SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
{
.name = "Capture Source",
.type = SB_MIX_CAPTURE_DT019X
- };
-
-static struct sbmix_elem *snd_dt019x_controls[] = {
- &snd_dt019x_ctl_master_play_vol,
- &snd_dt019x_ctl_pcm_play_vol,
- &snd_dt019x_ctl_synth_play_vol,
- &snd_dt019x_ctl_cd_play_vol,
- &snd_dt019x_ctl_mic_play_vol,
- &snd_dt019x_ctl_pc_speaker_vol,
- &snd_dt019x_ctl_line_play_vol,
- &snd_sb16_ctl_mic_play_switch,
- &snd_sb16_ctl_cd_play_switch,
- &snd_sb16_ctl_line_play_switch,
- &snd_dt019x_ctl_pcm_play_switch,
- &snd_dt019x_ctl_synth_play_switch,
- &snd_dt019x_ctl_capture_source
+ }
};
static unsigned char snd_dt019x_init_values[][2] = {
@@ -669,74 +671,37 @@ static unsigned char snd_dt019x_init_values[][2] = {
/*
* ALS4000 specific mixer elements
*/
-/* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl! */
-static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
- SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
-static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route =
- SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03);
-/* FIXME: mono playback switch also available on DT019X? */
-static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
- SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
-static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
- SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
-static struct sbmix_elem snd_als4000_ctl_mixer_loopback =
- SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
-/* FIXME: functionality of 3D controls might be swapped, I didn't find
- * a description of how to identify what is supposed to be what */
-static struct sbmix_elem snd_als4000_3d_control_switch =
- SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
-static struct sbmix_elem snd_als4000_3d_control_ratio =
- SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07);
-static struct sbmix_elem snd_als4000_3d_control_freq =
+static struct sbmix_elem snd_als4000_controls[] = {
+ SB_DOUBLE("PCM Playback Switch",
+ SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
+ SB_DOUBLE("Synth Playback Switch",
+ SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
+ SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
+ SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
+ {
+ .name = "Master Mono Capture Route",
+ .type = SB_MIX_MONO_CAPTURE_ALS4K
+ },
+ SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
+ SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
+ SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
+ SB_SINGLE("Digital Loopback Switch",
+ SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
+ /* FIXME: functionality of 3D controls might be swapped, I didn't find
+ * a description of how to identify what is supposed to be what */
+ SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
/* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
- SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03);
-static struct sbmix_elem snd_als4000_3d_control_delay =
+ SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03),
/* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
* but what ALSA 3D attribute is that actually? "Center", "Depth",
* "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
- SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
-static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
- SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
-#ifdef NOT_AVAILABLE
-static struct sbmix_elem snd_als4000_ctl_fmdac =
- SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
-static struct sbmix_elem snd_als4000_ctl_qsound =
- SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
-#endif
-
-static struct sbmix_elem *snd_als4000_controls[] = {
- &snd_sb16_ctl_master_play_vol,
- &snd_dt019x_ctl_pcm_play_switch,
- &snd_sb16_ctl_pcm_play_vol,
- &snd_sb16_ctl_synth_capture_route,
- &snd_dt019x_ctl_synth_play_switch,
- &snd_sb16_ctl_synth_play_vol,
- &snd_sb16_ctl_cd_capture_route,
- &snd_sb16_ctl_cd_play_switch,
- &snd_sb16_ctl_cd_play_vol,
- &snd_sb16_ctl_line_capture_route,
- &snd_sb16_ctl_line_play_switch,
- &snd_sb16_ctl_line_play_vol,
- &snd_sb16_ctl_mic_capture_route,
- &snd_als4000_ctl_mic_20db_boost,
- &snd_sb16_ctl_auto_mic_gain,
- &snd_sb16_ctl_mic_play_switch,
- &snd_sb16_ctl_mic_play_vol,
- &snd_sb16_ctl_pc_speaker_vol,
- &snd_sb16_ctl_capture_vol,
- &snd_sb16_ctl_play_vol,
- &snd_als4000_ctl_master_mono_playback_switch,
- &snd_als4000_ctl_master_mono_capture_route,
- &snd_als4000_ctl_mono_playback_switch,
- &snd_als4000_ctl_mixer_loopback,
- &snd_als4000_3d_control_switch,
- &snd_als4000_3d_control_ratio,
- &snd_als4000_3d_control_freq,
- &snd_als4000_3d_control_delay,
- &snd_als4000_3d_control_poweroff_switch,
+ SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
+ SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
+ SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
+ SB_ALS4000_FMDAC, 5, 0x01),
#ifdef NOT_AVAILABLE
- &snd_als4000_ctl_fmdac,
- &snd_als4000_ctl_qsound,
+ SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
+ SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
#endif
};
@@ -755,11 +720,10 @@ static unsigned char snd_als4000_init_values[][2] = {
{ SB_ALS4000_MIC_IN_GAIN, 0 },
};
-
/*
*/
static int snd_sbmixer_init(struct snd_sb *chip,
- struct sbmix_elem **controls,
+ struct sbmix_elem *controls,
int controls_count,
unsigned char map[][2],
int map_count,
@@ -782,7 +746,8 @@ static int snd_sbmixer_init(struct snd_sb *chip,
}
for (idx = 0; idx < controls_count; idx++) {
- if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
+ err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
+ if (err < 0)
return err;
}
snd_component_add(card, name);
@@ -795,7 +760,8 @@ int snd_sbmixer_new(struct snd_sb *chip)
struct snd_card *card;
int err;
- snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!chip || !chip->card))
+ return -EINVAL;
card = chip->card;
@@ -813,6 +779,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
return err;
break;
case SB_HW_PRO:
+ case SB_HW_JAZZ16:
if ((err = snd_sbmixer_init(chip,
snd_sbpro_controls,
ARRAY_SIZE(snd_sbpro_controls),
@@ -823,6 +790,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
break;
case SB_HW_16:
case SB_HW_ALS100:
+ case SB_HW_CS5530:
if ((err = snd_sbmixer_init(chip,
snd_sb16_controls,
ARRAY_SIZE(snd_sb16_controls),
@@ -832,6 +800,15 @@ int snd_sbmixer_new(struct snd_sb *chip)
return err;
break;
case SB_HW_ALS4000:
+ /* use only the first 16 controls from SB16 */
+ err = snd_sbmixer_init(chip,
+ snd_sb16_controls,
+ 16,
+ snd_sb16_init_values,
+ ARRAY_SIZE(snd_sb16_init_values),
+ "ALS4000");
+ if (err < 0)
+ return err;
if ((err = snd_sbmixer_init(chip,
snd_als4000_controls,
ARRAY_SIZE(snd_als4000_controls),
@@ -841,12 +818,14 @@ int snd_sbmixer_new(struct snd_sb *chip)
return err;
break;
case SB_HW_DT019X:
- if ((err = snd_sbmixer_init(chip,
- snd_dt019x_controls,
- ARRAY_SIZE(snd_dt019x_controls),
- snd_dt019x_init_values,
- ARRAY_SIZE(snd_dt019x_init_values),
- "DT019X")) < 0)
+ err = snd_sbmixer_init(chip,
+ snd_dt019x_controls,
+ ARRAY_SIZE(snd_dt019x_controls),
+ snd_dt019x_init_values,
+ ARRAY_SIZE(snd_dt019x_init_values),
+ "DT019X");
+ if (err < 0)
+ return err;
break;
default:
strcpy(card->mixername, "???");
@@ -906,13 +885,14 @@ static unsigned char dt019x_saved_regs[] = {
};
static unsigned char als4000_saved_regs[] = {
+ /* please verify in dsheet whether regs to be added
+ are actually real H/W or just dummy */
SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
SB_DSP4_OUTPUT_SW,
SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
- SB_DSP4_MIC_AGC,
SB_DSP4_MIC_DEV,
SB_DSP4_SPEAKER_DEV,
SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
@@ -920,14 +900,17 @@ static unsigned char als4000_saved_regs[] = {
SB_DT019X_OUTPUT_SW2,
SB_ALS4000_MONO_IO_CTRL,
SB_ALS4000_MIC_IN_GAIN,
+ SB_ALS4000_FMDAC,
SB_ALS4000_3D_SND_FX,
SB_ALS4000_3D_TIME_DELAY,
+ SB_ALS4000_CR3_CONFIGURATION,
};
static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
{
unsigned char *val = chip->saved_regs;
- snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
+ if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
+ return;
for (; num_regs; num_regs--)
*val++ = snd_sbmixer_read(chip, *regs++);
}
@@ -935,7 +918,8 @@ static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
{
unsigned char *val = chip->saved_regs;
- snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
+ if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
+ return;
for (; num_regs; num_regs--)
snd_sbmixer_write(chip, *regs++, *val++);
}
@@ -948,10 +932,12 @@ void snd_sbmixer_suspend(struct snd_sb *chip)
save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
break;
case SB_HW_PRO:
+ case SB_HW_JAZZ16:
save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
break;
case SB_HW_16:
case SB_HW_ALS100:
+ case SB_HW_CS5530:
save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
break;
case SB_HW_ALS4000:
@@ -973,10 +959,12 @@ void snd_sbmixer_resume(struct snd_sb *chip)
restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
break;
case SB_HW_PRO:
+ case SB_HW_JAZZ16:
restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
break;
case SB_HW_16:
case SB_HW_ALS100:
+ case SB_HW_CS5530:
restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
break;
case SB_HW_ALS4000:
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
new file mode 100644
index 00000000000..15a152eaa2e
--- /dev/null
+++ b/sound/isa/sc6000.c
@@ -0,0 +1,725 @@
+/*
+ * Driver for Gallant SC-6000 soundcard. This card is also known as
+ * Audio Excel DSP 16 or Zoltrix AV302.
+ * These cards use CompuMedia ASC-9308 chip + AD1848 codec.
+ * SC-6600 and SC-7000 cards are also supported. They are based on
+ * CompuMedia ASC-9408 chip and CS4231 codec.
+ *
+ * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
+ *
+ * I don't have documentation for this card. I used the driver
+ * for OSS/Free included in the kernel source as reference.
+ *
+ * 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 <linux/module.h>
+#include <linux/delay.h>
+#include <linux/isa.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
+#include <sound/control.h>
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Krzysztof Helt");
+MODULE_DESCRIPTION("Gallant SC-6000");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Gallant, SC-6000},"
+ "{AudioExcel, Audio Excel DSP 16},"
+ "{Zoltrix, AV302}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220, 0x240 */
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 11 */
+static long mss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530, 0xe80 */
+static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+ /* 0x300, 0x310, 0x320, 0x330 */
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 0 */
+static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0, 1, 3 */
+static bool joystick[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = false };
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for sc-6000 based soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable sc-6000 based soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for sc-6000 driver.");
+module_param_array(mss_port, long, NULL, 0444);
+MODULE_PARM_DESC(mss_port, "MSS Port # for sc-6000 driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for sc-6000 driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for sc-6000 driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver.");
+module_param_array(dma, int, NULL, 0444);
+MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver.");
+module_param_array(joystick, bool, NULL, 0444);
+MODULE_PARM_DESC(joystick, "Enable gameport.");
+
+/*
+ * Commands of SC6000's DSP (SBPRO+special).
+ * Some of them are COMMAND_xx, in the future they may change.
+ */
+#define WRITE_MDIRQ_CFG 0x50 /* Set M&I&DRQ mask (the real config) */
+#define COMMAND_52 0x52 /* */
+#define READ_HARD_CFG 0x58 /* Read Hardware Config (I/O base etc) */
+#define COMMAND_5C 0x5c /* */
+#define COMMAND_60 0x60 /* */
+#define COMMAND_66 0x66 /* */
+#define COMMAND_6C 0x6c /* */
+#define COMMAND_6E 0x6e /* */
+#define COMMAND_88 0x88 /* Unknown command */
+#define DSP_INIT_MSS 0x8c /* Enable Microsoft Sound System mode */
+#define COMMAND_C5 0xc5 /* */
+#define GET_DSP_VERSION 0xe1 /* Get DSP Version */
+#define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright */
+
+/*
+ * Offsets of SC6000 DSP I/O ports. The offset is added to base I/O port
+ * to have the actual I/O port.
+ * Register permissions are:
+ * (wo) == Write Only
+ * (ro) == Read Only
+ * (w-) == Write
+ * (r-) == Read
+ */
+#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */
+#define DSP_READ 0x0a /* offset of DSP READ (ro) */
+#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */
+#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */
+#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */
+#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */
+
+#define PFX "sc6000: "
+#define DRV_NAME "SC-6000"
+
+/* hardware dependent functions */
+
+/*
+ * sc6000_irq_to_softcfg - Decode irq number into cfg code.
+ */
+static unsigned char sc6000_irq_to_softcfg(int irq)
+{
+ unsigned char val = 0;
+
+ switch (irq) {
+ case 5:
+ val = 0x28;
+ break;
+ case 7:
+ val = 0x8;
+ break;
+ case 9:
+ val = 0x10;
+ break;
+ case 10:
+ val = 0x18;
+ break;
+ case 11:
+ val = 0x20;
+ break;
+ default:
+ break;
+ }
+ return val;
+}
+
+/*
+ * sc6000_dma_to_softcfg - Decode dma number into cfg code.
+ */
+static unsigned char sc6000_dma_to_softcfg(int dma)
+{
+ unsigned char val = 0;
+
+ switch (dma) {
+ case 0:
+ val = 1;
+ break;
+ case 1:
+ val = 2;
+ break;
+ case 3:
+ val = 3;
+ break;
+ default:
+ break;
+ }
+ return val;
+}
+
+/*
+ * sc6000_mpu_irq_to_softcfg - Decode MPU-401 irq number into cfg code.
+ */
+static unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq)
+{
+ unsigned char val = 0;
+
+ switch (mpu_irq) {
+ case 5:
+ val = 4;
+ break;
+ case 7:
+ val = 0x44;
+ break;
+ case 9:
+ val = 0x84;
+ break;
+ case 10:
+ val = 0xc4;
+ break;
+ default:
+ break;
+ }
+ return val;
+}
+
+static int sc6000_wait_data(char __iomem *vport)
+{
+ int loop = 1000;
+ unsigned char val = 0;
+
+ do {
+ val = ioread8(vport + DSP_DATAVAIL);
+ if (val & 0x80)
+ return 0;
+ cpu_relax();
+ } while (loop--);
+
+ return -EAGAIN;
+}
+
+static int sc6000_read(char __iomem *vport)
+{
+ if (sc6000_wait_data(vport))
+ return -EBUSY;
+
+ return ioread8(vport + DSP_READ);
+
+}
+
+static int sc6000_write(char __iomem *vport, int cmd)
+{
+ unsigned char val;
+ int loop = 500000;
+
+ do {
+ val = ioread8(vport + DSP_STATUS);
+ /*
+ * DSP ready to receive data if bit 7 of val == 0
+ */
+ if (!(val & 0x80)) {
+ iowrite8(cmd, vport + DSP_COMMAND);
+ return 0;
+ }
+ cpu_relax();
+ } while (loop--);
+
+ snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd);
+
+ return -EIO;
+}
+
+static int sc6000_dsp_get_answer(char __iomem *vport, int command,
+ char *data, int data_len)
+{
+ int len = 0;
+
+ if (sc6000_write(vport, command)) {
+ snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command);
+ return -EIO;
+ }
+
+ do {
+ int val = sc6000_read(vport);
+
+ if (val < 0)
+ break;
+
+ data[len++] = val;
+
+ } while (len < data_len);
+
+ /*
+ * If no more data available, return to the caller, no error if len>0.
+ * We have no other way to know when the string is finished.
+ */
+ return len ? len : -EIO;
+}
+
+static int sc6000_dsp_reset(char __iomem *vport)
+{
+ iowrite8(1, vport + DSP_RESET);
+ udelay(10);
+ iowrite8(0, vport + DSP_RESET);
+ udelay(20);
+ if (sc6000_read(vport) == 0xaa)
+ return 0;
+ return -ENODEV;
+}
+
+/* detection and initialization */
+static int sc6000_hw_cfg_write(char __iomem *vport, const int *cfg)
+{
+ if (sc6000_write(vport, COMMAND_6C) < 0) {
+ snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C);
+ return -EIO;
+ }
+ if (sc6000_write(vport, COMMAND_5C) < 0) {
+ snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C);
+ return -EIO;
+ }
+ if (sc6000_write(vport, cfg[0]) < 0) {
+ snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]);
+ return -EIO;
+ }
+ if (sc6000_write(vport, cfg[1]) < 0) {
+ snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]);
+ return -EIO;
+ }
+ if (sc6000_write(vport, COMMAND_C5) < 0) {
+ snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg)
+{
+
+ if (sc6000_write(vport, WRITE_MDIRQ_CFG)) {
+ snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
+ return -EIO;
+ }
+ if (sc6000_write(vport, softcfg)) {
+ snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int sc6000_setup_board(char __iomem *vport, int config)
+{
+ int loop = 10;
+
+ do {
+ if (sc6000_write(vport, COMMAND_88)) {
+ snd_printk(KERN_ERR "CMD 0x%x: failed!\n",
+ COMMAND_88);
+ return -EIO;
+ }
+ } while ((sc6000_wait_data(vport) < 0) && loop--);
+
+ if (sc6000_read(vport) < 0) {
+ snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n",
+ COMMAND_88);
+ return -EIO;
+ }
+
+ if (sc6000_cfg_write(vport, config))
+ return -ENODEV;
+
+ return 0;
+}
+
+static int sc6000_init_mss(char __iomem *vport, int config,
+ char __iomem *vmss_port, int mss_config)
+{
+ if (sc6000_write(vport, DSP_INIT_MSS)) {
+ snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n",
+ DSP_INIT_MSS);
+ return -EIO;
+ }
+
+ msleep(10);
+
+ if (sc6000_cfg_write(vport, config))
+ return -EIO;
+
+ iowrite8(mss_config, vmss_port);
+
+ return 0;
+}
+
+static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg,
+ long xport, long xmpu,
+ long xmss_port, int joystick)
+{
+ cfg[0] = 0;
+ cfg[1] = 0;
+ if (xport == 0x240)
+ cfg[0] |= 1;
+ if (xmpu != SNDRV_AUTO_PORT) {
+ cfg[0] |= (xmpu & 0x30) >> 2;
+ cfg[1] |= 0x20;
+ }
+ if (xmss_port == 0xe80)
+ cfg[0] |= 0x10;
+ cfg[0] |= 0x40; /* always set */
+ if (!joystick)
+ cfg[0] |= 0x02;
+ cfg[1] |= 0x80; /* enable WSS system */
+ cfg[1] &= ~0x40; /* disable IDE */
+ snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]);
+}
+
+static int sc6000_init_board(char __iomem *vport,
+ char __iomem *vmss_port, int dev)
+{
+ char answer[15];
+ char version[2];
+ int mss_config = sc6000_irq_to_softcfg(irq[dev]) |
+ sc6000_dma_to_softcfg(dma[dev]);
+ int config = mss_config |
+ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]);
+ int err;
+ int old = 0;
+
+ err = sc6000_dsp_reset(vport);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n");
+ return err;
+ }
+
+ memset(answer, 0, sizeof(answer));
+ err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15);
+ if (err <= 0) {
+ snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n");
+ return -ENODEV;
+ }
+ /*
+ * My SC-6000 card return "SC-6000" in DSPCopyright, so
+ * if we have something different, we have to be warned.
+ */
+ if (strncmp("SC-6000", answer, 7))
+ snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n");
+
+ if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) {
+ snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n",
+ answer, version[0], version[1]);
+
+ /* set configuration */
+ sc6000_write(vport, COMMAND_5C);
+ if (sc6000_read(vport) < 0)
+ old = 1;
+
+ if (!old) {
+ int cfg[2];
+ sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev],
+ mss_port[dev], joystick[dev]);
+ if (sc6000_hw_cfg_write(vport, cfg) < 0) {
+ snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n");
+ return -EIO;
+ }
+ }
+ err = sc6000_setup_board(vport, config);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
+ return -ENODEV;
+ }
+
+ sc6000_dsp_reset(vport);
+
+ if (!old) {
+ sc6000_write(vport, COMMAND_60);
+ sc6000_write(vport, 0x02);
+ sc6000_dsp_reset(vport);
+ }
+
+ err = sc6000_setup_board(vport, config);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
+ return -ENODEV;
+ }
+ err = sc6000_init_mss(vport, config, vmss_port, mss_config);
+ if (err < 0) {
+ snd_printk(KERN_ERR "Cannot initialize "
+ "Microsoft Sound System mode.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int snd_sc6000_mixer(struct snd_wss *chip)
+{
+ struct snd_card *card = chip->card;
+ struct snd_ctl_elem_id id1, id2;
+ int err;
+
+ memset(&id1, 0, sizeof(id1));
+ memset(&id2, 0, sizeof(id2));
+ id1.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ /* reassign AUX0 to FM */
+ strcpy(id1.name, "Aux Playback Switch");
+ strcpy(id2.name, "FM Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0)
+ return err;
+ strcpy(id1.name, "Aux Playback Volume");
+ strcpy(id2.name, "FM Playback Volume");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0)
+ return err;
+ /* reassign AUX1 to CD */
+ strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+ strcpy(id2.name, "CD Playback Switch");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0)
+ return err;
+ strcpy(id1.name, "Aux Playback Volume");
+ strcpy(id2.name, "CD Playback Volume");
+ err = snd_ctl_rename_id(card, &id1, &id2);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int snd_sc6000_match(struct device *devptr, unsigned int dev)
+{
+ if (!enable[dev])
+ return 0;
+ if (port[dev] == SNDRV_AUTO_PORT) {
+ printk(KERN_ERR PFX "specify IO port\n");
+ return 0;
+ }
+ if (mss_port[dev] == SNDRV_AUTO_PORT) {
+ printk(KERN_ERR PFX "specify MSS port\n");
+ return 0;
+ }
+ if (port[dev] != 0x220 && port[dev] != 0x240) {
+ printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n");
+ return 0;
+ }
+ if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) {
+ printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n");
+ return 0;
+ }
+ if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) {
+ printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]);
+ return 0;
+ }
+ if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) {
+ printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]);
+ return 0;
+ }
+ if (mpu_port[dev] != SNDRV_AUTO_PORT &&
+ (mpu_port[dev] & ~0x30L) != 0x300) {
+ printk(KERN_ERR PFX "invalid MPU-401 port %lx\n",
+ mpu_port[dev]);
+ return 0;
+ }
+ if (mpu_port[dev] != SNDRV_AUTO_PORT &&
+ mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 &&
+ !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) {
+ printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]);
+ return 0;
+ }
+ return 1;
+}
+
+static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
+{
+ static int possible_irqs[] = { 5, 7, 9, 10, 11, -1 };
+ static int possible_dmas[] = { 1, 3, 0, -1 };
+ int err;
+ int xirq = irq[dev];
+ int xdma = dma[dev];
+ struct snd_card *card;
+ struct snd_wss *chip;
+ struct snd_opl3 *opl3;
+ char __iomem **vport;
+ char __iomem *vmss_port;
+
+
+ err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+ sizeof(vport), &card);
+ if (err < 0)
+ return err;
+
+ vport = card->private_data;
+ if (xirq == SNDRV_AUTO_IRQ) {
+ xirq = snd_legacy_find_free_irq(possible_irqs);
+ if (xirq < 0) {
+ snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
+ err = -EBUSY;
+ goto err_exit;
+ }
+ }
+
+ if (xdma == SNDRV_AUTO_DMA) {
+ xdma = snd_legacy_find_free_dma(possible_dmas);
+ if (xdma < 0) {
+ snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
+ err = -EBUSY;
+ goto err_exit;
+ }
+ }
+
+ if (!request_region(port[dev], 0x10, DRV_NAME)) {
+ snd_printk(KERN_ERR PFX
+ "I/O port region is already in use.\n");
+ err = -EBUSY;
+ goto err_exit;
+ }
+ *vport = devm_ioport_map(devptr, port[dev], 0x10);
+ if (*vport == NULL) {
+ snd_printk(KERN_ERR PFX
+ "I/O port cannot be iomaped.\n");
+ err = -EBUSY;
+ goto err_unmap1;
+ }
+
+ /* to make it marked as used */
+ if (!request_region(mss_port[dev], 4, DRV_NAME)) {
+ snd_printk(KERN_ERR PFX
+ "SC-6000 port I/O port region is already in use.\n");
+ err = -EBUSY;
+ goto err_unmap1;
+ }
+ vmss_port = devm_ioport_map(devptr, mss_port[dev], 4);
+ if (!vmss_port) {
+ snd_printk(KERN_ERR PFX
+ "MSS port I/O cannot be iomaped.\n");
+ err = -EBUSY;
+ goto err_unmap2;
+ }
+
+ snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n",
+ port[dev], xirq, xdma,
+ mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);
+
+ err = sc6000_init_board(*vport, vmss_port, dev);
+ if (err < 0)
+ goto err_unmap2;
+
+ err = snd_wss_create(card, mss_port[dev] + 4, -1, xirq, xdma, -1,
+ WSS_HW_DETECT, 0, &chip);
+ if (err < 0)
+ goto err_unmap2;
+
+ err = snd_wss_pcm(chip, 0, NULL);
+ if (err < 0) {
+ snd_printk(KERN_ERR PFX
+ "error creating new WSS PCM device\n");
+ goto err_unmap2;
+ }
+ err = snd_wss_mixer(chip);
+ if (err < 0) {
+ snd_printk(KERN_ERR PFX "error creating new WSS mixer\n");
+ goto err_unmap2;
+ }
+ err = snd_sc6000_mixer(chip);
+ if (err < 0) {
+ snd_printk(KERN_ERR PFX "the mixer rewrite failed\n");
+ goto err_unmap2;
+ }
+ if (snd_opl3_create(card,
+ 0x388, 0x388 + 2,
+ OPL3_HW_AUTO, 0, &opl3) < 0) {
+ snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n",
+ 0x388, 0x388 + 2);
+ } else {
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ goto err_unmap2;
+ }
+
+ if (mpu_port[dev] != SNDRV_AUTO_PORT) {
+ if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
+ mpu_irq[dev] = -1;
+ if (snd_mpu401_uart_new(card, 0,
+ MPU401_HW_MPU401,
+ mpu_port[dev], 0,
+ mpu_irq[dev], NULL) < 0)
+ snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n",
+ mpu_port[dev]);
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, "SC-6000");
+ sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d",
+ mss_port[dev], xirq, xdma);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto err_unmap2;
+
+ dev_set_drvdata(devptr, card);
+ return 0;
+
+err_unmap2:
+ sc6000_setup_board(*vport, 0);
+ release_region(mss_port[dev], 4);
+err_unmap1:
+ release_region(port[dev], 0x10);
+err_exit:
+ snd_card_free(card);
+ return err;
+}
+
+static int snd_sc6000_remove(struct device *devptr, unsigned int dev)
+{
+ struct snd_card *card = dev_get_drvdata(devptr);
+ char __iomem **vport = card->private_data;
+
+ if (sc6000_setup_board(*vport, 0) < 0)
+ snd_printk(KERN_WARNING "sc6000_setup_board failed on exit!\n");
+
+ release_region(port[dev], 0x10);
+ release_region(mss_port[dev], 4);
+
+ snd_card_free(card);
+ return 0;
+}
+
+static struct isa_driver snd_sc6000_driver = {
+ .match = snd_sc6000_match,
+ .probe = snd_sc6000_probe,
+ .remove = snd_sc6000_remove,
+ /* FIXME: suspend/resume */
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+
+static int __init alsa_card_sc6000_init(void)
+{
+ return isa_register_driver(&snd_sc6000_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_sc6000_exit(void)
+{
+ isa_unregister_driver(&snd_sc6000_driver);
+}
+
+module_init(alsa_card_sc6000_init)
+module_exit(alsa_card_sc6000_exit)
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
deleted file mode 100644
index 0dbbb35b242..00000000000
--- a/sound/isa/sgalaxy.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Driver for Aztech Sound Galaxy cards
- * Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
- *
- * I don't have documentation for this card, I based this driver on the
- * driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c)
- *
- * 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 <linux/init.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <asm/dma.h>
-#include <sound/core.h>
-#include <sound/sb.h>
-#include <sound/ad1848.h>
-#include <sound/control.h>
-#define SNDRV_LEGACY_FIND_FREE_IRQ
-#define SNDRV_LEGACY_FIND_FREE_DMA
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
-MODULE_DESCRIPTION("Aztech Sound Galaxy");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
-static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
-static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
-static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
-module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
-module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
-
-static struct platform_device *devices[SNDRV_CARDS];
-
-#define SGALAXY_AUXC_LEFT 18
-#define SGALAXY_AUXC_RIGHT 19
-
-#define PFX "sgalaxy: "
-
-/*
-
- */
-
-#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
-
-/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
-/* short time we actually need it.. */
-
-static int snd_sgalaxy_sbdsp_reset(unsigned long port)
-{
- int i;
-
- outb(1, SBP1(port, RESET));
- udelay(10);
- outb(0, SBP1(port, RESET));
- udelay(30);
- for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
- if (inb(SBP1(port, READ)) != 0xaa) {
- snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
- return -ENODEV;
- }
- return 0;
-}
-
-static int __init snd_sgalaxy_sbdsp_command(unsigned long port, unsigned char val)
-{
- int i;
-
- for (i = 10000; i; i--)
- if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
- outb(val, SBP1(port, COMMAND));
- return 1;
- }
-
- return 0;
-}
-
-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- return IRQ_NONE;
-}
-
-static int __init snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
-{
- static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1,
- 0x10, 0x18, 0x20, -1, -1, -1, -1};
- static int dma_bits[] = {1, 2, 0, 3};
- int tmp, tmp1;
-
- if ((tmp = inb(port + 3)) == 0xff)
- {
- snd_printdd("I/O address dead (0x%lx)\n", port);
- return 0;
- }
-#if 0
- snd_printdd("WSS signature = 0x%x\n", tmp);
-#endif
-
- if ((tmp & 0x3f) != 0x04 &&
- (tmp & 0x3f) != 0x0f &&
- (tmp & 0x3f) != 0x00) {
- snd_printdd("No WSS signature detected on port 0x%lx\n",
- port + 3);
- return 0;
- }
-
-#if 0
- snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
-#endif
-
- /* initialize IRQ for WSS codec */
- tmp = interrupt_bits[irq % 16];
- if (tmp < 0)
- return -EINVAL;
-
- if (request_irq(irq, snd_sgalaxy_dummy_interrupt, SA_INTERRUPT, "sgalaxy", NULL)) {
- snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
- return -EIO;
- }
-
- outb(tmp | 0x40, port);
- tmp1 = dma_bits[dma % 4];
- outb(tmp | tmp1, port);
-
- free_irq(irq, NULL);
-
- return 0;
-}
-
-static int __init snd_sgalaxy_detect(int dev, int irq, int dma)
-{
-#if 0
- snd_printdd(PFX "switching to WSS mode\n");
-#endif
-
- /* switch to WSS mode */
- snd_sgalaxy_sbdsp_reset(sbport[dev]);
-
- snd_sgalaxy_sbdsp_command(sbport[dev], 9);
- snd_sgalaxy_sbdsp_command(sbport[dev], 0);
-
- udelay(400);
- return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
-}
-
-static struct ad1848_mix_elem snd_sgalaxy_controls[] = {
-AD1848_DOUBLE("Aux Playback Switch", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-AD1848_DOUBLE("Aux Playback Volume", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
-};
-
-static int __init snd_sgalaxy_mixer(struct snd_ad1848 *chip)
-{
- struct snd_card *card = chip->card;
- struct snd_ctl_elem_id id1, id2;
- unsigned int idx;
- int err;
-
- memset(&id1, 0, sizeof(id1));
- memset(&id2, 0, sizeof(id2));
- id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- /* reassign AUX0 to LINE */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "Line Playback Switch");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "Line Playback Volume");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- /* reassign AUX1 to FM */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "FM Playback Switch");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "FM Playback Volume");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- /* build AUX2 input */
- for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
- if ((err = snd_ad1848_add_ctl_elem(chip, &snd_sgalaxy_controls[idx])) < 0)
- return err;
- }
- return 0;
-}
-
-static int __init snd_sgalaxy_probe(struct platform_device *devptr)
-{
- int dev = devptr->id;
- static int possible_irqs[] = {7, 9, 10, 11, -1};
- static int possible_dmas[] = {1, 3, 0, -1};
- int err, xirq, xdma1;
- struct snd_card *card;
- struct snd_ad1848 *chip;
-
- if (sbport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify SB port\n");
- return -EINVAL;
- }
- if (wssport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify WSS port\n");
- return -EINVAL;
- }
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
-
- xirq = irq[dev];
- if (xirq == SNDRV_AUTO_IRQ) {
- if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
- err = -EBUSY;
- goto _err;
- }
- }
- xdma1 = dma1[dev];
- if (xdma1 == SNDRV_AUTO_DMA) {
- if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
- err = -EBUSY;
- goto _err;
- }
- }
-
- if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
- goto _err;
-
- if ((err = snd_ad1848_create(card, wssport[dev] + 4,
- xirq, xdma1,
- AD1848_HW_DETECT, &chip)) < 0)
- goto _err;
- card->private_data = chip;
-
- if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) {
- snd_printdd(PFX "error creating new ad1848 PCM device\n");
- goto _err;
- }
- if ((err = snd_ad1848_mixer(chip)) < 0) {
- snd_printdd(PFX "error creating new ad1848 mixer\n");
- goto _err;
- }
- if ((err = snd_sgalaxy_mixer(chip)) < 0) {
- snd_printdd(PFX "the mixer rewrite failed\n");
- goto _err;
- }
-
- strcpy(card->driver, "Sound Galaxy");
- strcpy(card->shortname, "Sound Galaxy");
- sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
- wssport[dev], xirq, xdma1);
-
- snd_card_set_dev(card, &devptr->dev);
-
- if ((err = snd_card_register(card)) < 0)
- goto _err;
-
- platform_set_drvdata(devptr, card);
- return 0;
-
- _err:
- snd_card_free(card);
- return err;
-}
-
-static int __devexit snd_sgalaxy_remove(struct platform_device *devptr)
-{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int snd_sgalaxy_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct snd_card *card = platform_get_drvdata(pdev);
- struct snd_ad1848 *chip = card->private_data;
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- chip->suspend(chip);
- return 0;
-}
-
-static int snd_sgalaxy_resume(struct platform_device *pdev)
-{
- struct snd_card *card = platform_get_drvdata(pdev);
- struct snd_ad1848 *chip = card->private_data;
-
- chip->resume(chip);
- snd_ad1848_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
- snd_ad1848_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-#endif
-
-#define SND_SGALAXY_DRIVER "snd_sgalaxy"
-
-static struct platform_driver snd_sgalaxy_driver = {
- .probe = snd_sgalaxy_probe,
- .remove = __devexit_p(snd_sgalaxy_remove),
-#ifdef CONFIG_PM
- .suspend = snd_sgalaxy_suspend,
- .resume = snd_sgalaxy_resume,
-#endif
- .driver = {
- .name = SND_SGALAXY_DRIVER
- },
-};
-
-static void __init_or_module snd_sgalaxy_unregister_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devices); ++i)
- platform_device_unregister(devices[i]);
- platform_driver_unregister(&snd_sgalaxy_driver);
-}
-
-static int __init alsa_card_sgalaxy_init(void)
-{
- int i, cards, err;
-
- err = platform_driver_register(&snd_sgalaxy_driver);
- if (err < 0)
- return err;
-
- cards = 0;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
- device = platform_device_register_simple(SND_SGALAXY_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- devices[i] = device;
- cards++;
- }
- if (!cards) {
-#ifdef MODULE
- snd_printk(KERN_ERR "Sound Galaxy soundcard not found or device busy\n");
-#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_sgalaxy_unregister_all();
- return err;
-}
-
-static void __exit alsa_card_sgalaxy_exit(void)
-{
- snd_sgalaxy_unregister_all();
-}
-
-module_init(alsa_card_sgalaxy_init)
-module_exit(alsa_card_sgalaxy_exit)
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 5fb981c0a28..44405df7d4b 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1,5 +1,5 @@
/*
- * Low-level ALSA driver for the ENSONIQ SoundScape PnP
+ * Low-level ALSA driver for the ENSONIQ SoundScape
* Copyright (c) by Chris Rankin
*
* This driver was written in part using information obtained from
@@ -21,34 +21,40 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/pnp.h>
#include <linux/spinlock.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <asm/dma.h>
#include <sound/core.h>
-#include <sound/hwdep.h>
-#include <sound/cs4231.h>
+#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/initval.h>
-#include <sound/sscape_ioctl.h>
-
MODULE_AUTHOR("Chris Rankin");
-MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver");
+MODULE_DESCRIPTION("ENSONIQ SoundScape driver");
MODULE_LICENSE("GPL");
-
-static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX;
-static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR;
-static long port[SNDRV_CARDS] __devinitdata = { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_PORT };
-static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
-static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
-static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
+MODULE_FIRMWARE("sndscape.co0");
+MODULE_FIRMWARE("sndscape.co1");
+MODULE_FIRMWARE("sndscape.co2");
+MODULE_FIRMWARE("sndscape.co3");
+MODULE_FIRMWARE("sndscape.co4");
+MODULE_FIRMWARE("scope.cod");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static bool joystick[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index number for SoundScape soundcard");
@@ -59,6 +65,9 @@ MODULE_PARM_DESC(id, "Description for SoundScape card");
module_param_array(port, long, NULL, 0444);
MODULE_PARM_DESC(port, "Port # for SoundScape driver.");
+module_param_array(wss_port, long, NULL, 0444);
+MODULE_PARM_DESC(wss_port, "WSS Port # for SoundScape driver.");
+
module_param_array(irq, int, NULL, 0444);
MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver.");
@@ -68,12 +77,19 @@ MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver.");
module_param_array(dma, int, NULL, 0444);
MODULE_PARM_DESC(dma, "DMA # for SoundScape driver.");
-static struct platform_device *platform_devices[SNDRV_CARDS];
-static int pnp_registered;
-
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver.");
+
+module_param_array(joystick, bool, NULL, 0444);
+MODULE_PARM_DESC(joystick, "Enable gameport.");
+
#ifdef CONFIG_PNP
+static int isa_registered;
+static int pnp_registered;
+
static struct pnp_card_device_id sscape_pnpids[] = {
- { .id = "ENS3081", .devs = { { "ENS0000" } } },
+ { .id = "ENS3081", .devs = { { "ENS0000" } } }, /* Soundscape PnP */
+ { .id = "ENS4081", .devs = { { "ENS1011" } } }, /* VIVO90 */
{ .id = "" } /* end */
};
@@ -81,9 +97,6 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
#endif
-#define MPU401_IO(i) ((i) + 0)
-#define MIDI_DATA_IO(i) ((i) + 0)
-#define MIDI_CTRL_IO(i) ((i) + 1)
#define HOST_CTRL_IO(i) ((i) + 2)
#define HOST_DATA_IO(i) ((i) + 3)
#define ODIE_ADDR_IO(i) ((i) + 4)
@@ -96,14 +109,14 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
#define RX_READY 0x01
#define TX_READY 0x02
-#define CMD_ACK 0x80
-#define CMD_SET_MIDI_VOL 0x84
-#define CMD_GET_MIDI_VOL 0x85
-#define CMD_XXX_MIDI_VOL 0x86
-#define CMD_SET_EXTMIDI 0x8a
-#define CMD_GET_EXTMIDI 0x8b
-#define CMD_SET_MT32 0x8c
-#define CMD_GET_MT32 0x8d
+#define CMD_ACK 0x80
+#define CMD_SET_MIDI_VOL 0x84
+#define CMD_GET_MIDI_VOL 0x85
+#define CMD_XXX_MIDI_VOL 0x86
+#define CMD_SET_EXTMIDI 0x8a
+#define CMD_GET_EXTMIDI 0x8b
+#define CMD_SET_MT32 0x8c
+#define CMD_GET_MT32 0x8d
enum GA_REG {
GA_INTSTAT_REG = 0,
@@ -121,26 +134,22 @@ enum GA_REG {
#define DMA_8BIT 0x80
-#define AD1845_FREQ_SEL_MSB 0x16
-#define AD1845_FREQ_SEL_LSB 0x17
+enum card_type {
+ MEDIA_FX, /* Sequoia S-1000 */
+ SSCAPE, /* Sequoia S-2000 */
+ SSCAPE_PNP,
+ SSCAPE_VIVO,
+};
struct soundscape {
spinlock_t lock;
unsigned io_base;
- int codec_type;
int ic_type;
+ enum card_type type;
struct resource *io_res;
- struct snd_cs4231 *chip;
- struct snd_mpu401 *mpu;
- struct snd_hwdep *hw;
+ struct resource *wss_res;
+ struct snd_wss *chip;
- /*
- * The MIDI device won't work until we've loaded
- * its firmware via a hardware-dependent device IOCTL
- */
- spinlock_t fwlock;
- int hw_in_use;
- unsigned long midi_usage;
unsigned char midi_vol;
};
@@ -152,28 +161,21 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c)
return (struct soundscape *) (c->private_data);
}
-static inline struct soundscape *get_mpu401_soundscape(struct snd_mpu401 * mpu)
-{
- return (struct soundscape *) (mpu->private_data);
-}
-
-static inline struct soundscape *get_hwdep_soundscape(struct snd_hwdep * hw)
-{
- return (struct soundscape *) (hw->private_data);
-}
-
-
/*
* Allocates some kernel memory that we can use for DMA.
* I think this means that the memory has to map to
* contiguous pages of physical memory.
*/
-static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size)
+static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf,
+ unsigned long size)
{
if (buf) {
- if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(),
+ if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,
+ snd_dma_isa_data(),
size, buf) < 0) {
- snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size);
+ snd_printk(KERN_ERR "sscape: Failed to allocate "
+ "%lu bytes for DMA\n",
+ size);
return NULL;
}
}
@@ -190,13 +192,13 @@ static void free_dmabuf(struct snd_dma_buffer *buf)
snd_dma_free_pages(buf);
}
-
/*
* This function writes to the SoundScape's control registers,
* but doesn't do any locking. It's up to the caller to do that.
* This is why this function is "unsafe" ...
*/
-static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val)
+static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg,
+ unsigned char val)
{
outb(reg, ODIE_ADDR_IO(io_base));
outb(val, ODIE_DATA_IO(io_base));
@@ -206,7 +208,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsign
* Write to the SoundScape's control registers, and do the
* necessary locking ...
*/
-static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val)
+static void sscape_write(struct soundscape *s, enum GA_REG reg,
+ unsigned char val)
{
unsigned long flags;
@@ -219,7 +222,8 @@ static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char va
* Read from the SoundScape's control registers, but leave any
* locking to the caller. This is why the function is "unsafe" ...
*/
-static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg)
+static inline unsigned char sscape_read_unsafe(unsigned io_base,
+ enum GA_REG reg)
{
outb(reg, ODIE_ADDR_IO(io_base));
return inb(ODIE_DATA_IO(io_base));
@@ -248,9 +252,8 @@ static inline void set_midi_mode_unsafe(unsigned io_base)
static inline int host_read_unsafe(unsigned io_base)
{
int data = -1;
- if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) {
+ if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0)
data = inb(HOST_DATA_IO(io_base));
- }
return data;
}
@@ -292,7 +295,7 @@ static inline int host_write_unsafe(unsigned io_base, unsigned char data)
* Also leaves all locking-issues to the caller ...
*/
static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
- unsigned timeout)
+ unsigned timeout)
{
int err;
@@ -311,17 +314,17 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
*
* NOTE: This check is based upon observation, not documentation.
*/
-static inline int verify_mpu401(const struct snd_mpu401 * mpu)
+static inline int verify_mpu401(const struct snd_mpu401 *mpu)
{
- return ((inb(MIDI_CTRL_IO(mpu->port)) & 0xc0) == 0x80);
+ return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
}
/*
* This is apparently the standard way to initailise an MPU-401
*/
-static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
+static inline void initialise_mpu401(const struct snd_mpu401 *mpu)
{
- outb(0, MIDI_DATA_IO(mpu->port));
+ outb(0, MPU401D(mpu));
}
/*
@@ -329,9 +332,10 @@ static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
* The AD1845 detection fails if we *don't* do this, so I
* think that this is a good idea ...
*/
-static inline void activate_ad1845_unsafe(unsigned io_base)
+static void activate_ad1845_unsafe(unsigned io_base)
{
- sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10);
+ unsigned char val = sscape_read_unsafe(io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(io_base, GA_HMCTL_REG, (val & 0xcf) | 0x10);
sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80);
}
@@ -340,8 +344,9 @@ static inline void activate_ad1845_unsafe(unsigned io_base)
*/
static void soundscape_free(struct snd_card *c)
{
- register struct soundscape *sscape = get_card_soundscape(c);
+ struct soundscape *sscape = get_card_soundscape(c);
release_and_free_resource(sscape->io_res);
+ release_and_free_resource(sscape->wss_res);
free_dma(sscape->chip->dma1);
}
@@ -349,24 +354,27 @@ static void soundscape_free(struct snd_card *c)
* Tell the SoundScape to begin a DMA tranfer using the given channel.
* All locking issues are left to the caller.
*/
-static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
+static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
{
- sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01);
- sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe);
+ sscape_write_unsafe(io_base, reg,
+ sscape_read_unsafe(io_base, reg) | 0x01);
+ sscape_write_unsafe(io_base, reg,
+ sscape_read_unsafe(io_base, reg) & 0xfe);
}
/*
* Wait for a DMA transfer to complete. This is a "limited busy-wait",
* and all locking issues are left to the caller.
*/
-static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout)
+static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg,
+ unsigned timeout)
{
while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) {
udelay(100);
--timeout;
} /* while */
- return (sscape_read_unsafe(io_base, reg) & 0x01);
+ return sscape_read_unsafe(io_base, reg) & 0x01;
}
/*
@@ -378,20 +386,20 @@ static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned ti
*/
static int obp_startup_ack(struct soundscape *s, unsigned timeout)
{
- while (timeout != 0) {
- unsigned long flags;
- unsigned char x;
+ unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
- schedule_timeout_interruptible(1);
+ do {
+ unsigned long flags;
+ int x;
spin_lock_irqsave(&s->lock, flags);
- x = inb(HOST_DATA_IO(s->io_base));
+ x = host_read_unsafe(s->io_base);
spin_unlock_irqrestore(&s->lock, flags);
- if ((x & 0xfe) == 0xfe)
+ if (x == 0xfe || x == 0xff)
return 1;
- --timeout;
- } /* while */
+ msleep(10);
+ } while (time_before(jiffies, end_time));
return 0;
}
@@ -405,20 +413,20 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
*/
static int host_startup_ack(struct soundscape *s, unsigned timeout)
{
- while (timeout != 0) {
- unsigned long flags;
- unsigned char x;
+ unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
- schedule_timeout_interruptible(1);
+ do {
+ unsigned long flags;
+ int x;
spin_lock_irqsave(&s->lock, flags);
- x = inb(HOST_DATA_IO(s->io_base));
+ x = host_read_unsafe(s->io_base);
spin_unlock_irqrestore(&s->lock, flags);
if (x == 0xfe)
return 1;
- --timeout;
- } /* while */
+ msleep(10);
+ } while (time_before(jiffies, end_time));
return 0;
}
@@ -426,15 +434,15 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
/*
* Upload a byte-stream into the SoundScape using DMA channel A.
*/
-static int upload_dma_data(struct soundscape *s,
- const unsigned char __user *data,
- size_t size)
+static int upload_dma_data(struct soundscape *s, const unsigned char *data,
+ size_t size)
{
unsigned long flags;
struct snd_dma_buffer dma;
int ret;
+ unsigned char val;
- if (!get_dmabuf(&dma, PAGE_ALIGN(size)))
+ if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024)))
return -ENOMEM;
spin_lock_irqsave(&s->lock, flags);
@@ -442,70 +450,57 @@ static int upload_dma_data(struct soundscape *s,
/*
* Reset the board ...
*/
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f);
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f);
/*
* Enable the DMA channels and configure them ...
*/
- sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50);
- sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT);
+ val = (s->chip->dma1 << 4) | DMA_8BIT;
+ sscape_write_unsafe(s->io_base, GA_DMAA_REG, val);
sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);
/*
* Take the board out of reset ...
*/
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80);
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80);
/*
- * Upload the user's data (firmware?) to the SoundScape
+ * Upload the firmware to the SoundScape
* board through the DMA channel ...
*/
while (size != 0) {
unsigned long len;
- /*
- * Apparently, copying to/from userspace can sleep.
- * We are therefore forbidden from holding any
- * spinlocks while we copy ...
- */
- spin_unlock_irqrestore(&s->lock, flags);
-
- /*
- * Remember that the data that we want to DMA
- * comes from USERSPACE. We have already verified
- * the userspace pointer ...
- */
len = min(size, dma.bytes);
- len -= __copy_from_user(dma.area, data, len);
+ memcpy(dma.area, data, len);
data += len;
size -= len;
- /*
- * Grab that spinlock again, now that we've
- * finished copying!
- */
- spin_lock_irqsave(&s->lock, flags);
-
snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
/*
- * Don't forget to release this spinlock we're holding ...
+ * Don't forget to release this spinlock we're holding
*/
spin_unlock_irqrestore(&s->lock, flags);
- snd_printk(KERN_ERR "sscape: DMA upload has timed out\n");
+ snd_printk(KERN_ERR
+ "sscape: DMA upload has timed out\n");
ret = -EAGAIN;
goto _release_dma;
}
} /* while */
set_host_mode_unsafe(s->io_base);
+ outb(0x0, s->io_base);
/*
* Boot the board ... (I think)
*/
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40);
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40);
spin_unlock_irqrestore(&s->lock, flags);
/*
@@ -514,19 +509,21 @@ static int upload_dma_data(struct soundscape *s,
* give it 5 seconds (max) ...
*/
ret = 0;
- if (!obp_startup_ack(s, 5)) {
- snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
+ if (!obp_startup_ack(s, 5000)) {
+ snd_printk(KERN_ERR "sscape: No response "
+ "from on-board processor after upload\n");
ret = -EAGAIN;
- } else if (!host_startup_ack(s, 5)) {
- snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
+ } else if (!host_startup_ack(s, 5000)) {
+ snd_printk(KERN_ERR
+ "sscape: SoundScape failed to initialise\n");
ret = -EAGAIN;
}
- _release_dma:
+_release_dma:
/*
* NOTE!!! We are NOT holding any spinlocks at this point !!!
*/
- sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40));
+ sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70));
free_dmabuf(&dma);
return ret;
@@ -536,167 +533,76 @@ static int upload_dma_data(struct soundscape *s,
* Upload the bootblock(?) into the SoundScape. The only
* purpose of this block of code seems to be to tell
* us which version of the microcode we should be using.
- *
- * NOTE: The boot-block data resides in USER-SPACE!!!
- * However, we have already verified its memory
- * addresses by the time we get here.
*/
-static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb)
+static int sscape_upload_bootblock(struct snd_card *card)
{
+ struct soundscape *sscape = get_card_soundscape(card);
unsigned long flags;
+ const struct firmware *init_fw = NULL;
int data = 0;
int ret;
- ret = upload_dma_data(sscape, bb->code, sizeof(bb->code));
-
- spin_lock_irqsave(&sscape->lock, flags);
- if (ret == 0) {
- data = host_read_ctrl_unsafe(sscape->io_base, 100);
- }
- set_midi_mode_unsafe(sscape->io_base);
- spin_unlock_irqrestore(&sscape->lock, flags);
-
- if (ret == 0) {
- if (data < 0) {
- snd_printk(KERN_ERR "sscape: timeout reading firmware version\n");
- ret = -EAGAIN;
- }
- else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) {
- ret = -EFAULT;
- }
+ ret = request_firmware(&init_fw, "scope.cod", card->dev);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "sscape: Error loading scope.cod");
+ return ret;
}
+ ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
- return ret;
-}
-
-/*
- * Upload the microcode into the SoundScape. The
- * microcode is 64K of data, and if we try to copy
- * it into a local variable then we will SMASH THE
- * KERNEL'S STACK! We therefore leave it in USER
- * SPACE, and save ourselves from copying it at all.
- */
-static int sscape_upload_microcode(struct soundscape *sscape,
- const struct sscape_microcode __user *mc)
-{
- unsigned long flags;
- char __user *code;
- int err;
+ release_firmware(init_fw);
- /*
- * We are going to have to copy this data into a special
- * DMA-able buffer before we can upload it. We shall therefore
- * just check that the data pointer is valid for now.
- *
- * NOTE: This buffer is 64K long! That's WAY too big to
- * copy into a stack-temporary anyway.
- */
- if ( get_user(code, &mc->code) ||
- !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) )
- return -EFAULT;
+ spin_lock_irqsave(&sscape->lock, flags);
+ if (ret == 0)
+ data = host_read_ctrl_unsafe(sscape->io_base, 100);
- if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) {
- snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n");
- }
+ if (data & 0x10)
+ sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f);
- spin_lock_irqsave(&sscape->lock, flags);
- set_midi_mode_unsafe(sscape->io_base);
spin_unlock_irqrestore(&sscape->lock, flags);
- initialise_mpu401(sscape->mpu);
+ data &= 0xf;
+ if (ret == 0 && data > 7) {
+ snd_printk(KERN_ERR
+ "sscape: timeout reading firmware version\n");
+ ret = -EAGAIN;
+ }
- return err;
+ return (ret == 0) ? data : ret;
}
/*
- * Hardware-specific device functions, to implement special
- * IOCTLs for the SoundScape card. This is how we upload
- * the microcode into the card, for example, and so we
- * must ensure that no two processes can open this device
- * simultaneously, and that we can't open it at all if
- * someone is using the MIDI device.
+ * Upload the microcode into the SoundScape.
*/
-static int sscape_hw_open(struct snd_hwdep * hw, struct file *file)
+static int sscape_upload_microcode(struct snd_card *card, int version)
{
- register struct soundscape *sscape = get_hwdep_soundscape(hw);
- unsigned long flags;
+ struct soundscape *sscape = get_card_soundscape(card);
+ const struct firmware *init_fw = NULL;
+ char name[14];
int err;
- spin_lock_irqsave(&sscape->fwlock, flags);
+ snprintf(name, sizeof(name), "sndscape.co%d", version);
- if ((sscape->midi_usage != 0) || sscape->hw_in_use) {
- err = -EBUSY;
- } else {
- sscape->hw_in_use = 1;
- err = 0;
+ err = request_firmware(&init_fw, name, card->dev);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d",
+ version);
+ return err;
}
+ err = upload_dma_data(sscape, init_fw->data, init_fw->size);
+ if (err == 0)
+ snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n",
+ init_fw->size >> 10);
- spin_unlock_irqrestore(&sscape->fwlock, flags);
- return err;
-}
-
-static int sscape_hw_release(struct snd_hwdep * hw, struct file *file)
-{
- register struct soundscape *sscape = get_hwdep_soundscape(hw);
- unsigned long flags;
-
- spin_lock_irqsave(&sscape->fwlock, flags);
- sscape->hw_in_use = 0;
- spin_unlock_irqrestore(&sscape->fwlock, flags);
- return 0;
-}
-
-static int sscape_hw_ioctl(struct snd_hwdep * hw, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct soundscape *sscape = get_hwdep_soundscape(hw);
- int err = -EBUSY;
-
- switch (cmd) {
- case SND_SSCAPE_LOAD_BOOTB:
- {
- register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg;
-
- /*
- * We are going to have to copy this data into a special
- * DMA-able buffer before we can upload it. We shall therefore
- * just check that the data pointer is valid for now ...
- */
- if ( !access_ok(VERIFY_READ, bb->code, sizeof(bb->code)) )
- return -EFAULT;
-
- /*
- * Now check that we can write the firmware version number too...
- */
- if ( !access_ok(VERIFY_WRITE, &bb->version, sizeof(bb->version)) )
- return -EFAULT;
-
- err = sscape_upload_bootblock(sscape, bb);
- }
- break;
-
- case SND_SSCAPE_LOAD_MCODE:
- {
- register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg;
-
- err = sscape_upload_microcode(sscape, mc);
- }
- break;
-
- default:
- err = -EINVAL;
- break;
- } /* switch */
+ release_firmware(init_fw);
return err;
}
-
/*
* Mixer control for the SoundScape's MIDI device.
*/
static int sscape_midi_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *uinfo)
+ struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
@@ -706,36 +612,32 @@ static int sscape_midi_info(struct snd_kcontrol *ctl,
}
static int sscape_midi_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
+ struct snd_ctl_elem_value *uctl)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kctl);
+ struct snd_wss *chip = snd_kcontrol_chip(kctl);
struct snd_card *card = chip->card;
register struct soundscape *s = get_card_soundscape(card);
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
- set_host_mode_unsafe(s->io_base);
-
- if (host_write_ctrl_unsafe(s->io_base, CMD_GET_MIDI_VOL, 100)) {
- uctl->value.integer.value[0] = host_read_ctrl_unsafe(s->io_base, 100);
- }
-
- set_midi_mode_unsafe(s->io_base);
+ uctl->value.integer.value[0] = s->midi_vol;
spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
static int sscape_midi_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
+ struct snd_ctl_elem_value *uctl)
{
- struct snd_cs4231 *chip = snd_kcontrol_chip(kctl);
+ struct snd_wss *chip = snd_kcontrol_chip(kctl);
struct snd_card *card = chip->card;
- register struct soundscape *s = get_card_soundscape(card);
+ struct soundscape *s = get_card_soundscape(card);
unsigned long flags;
int change;
+ unsigned char new_val;
spin_lock_irqsave(&s->lock, flags);
+ new_val = uctl->value.integer.value[0] & 127;
/*
* We need to put the board into HOST mode before we
* can send any volume-changing HOST commands ...
@@ -748,14 +650,16 @@ static int sscape_midi_put(struct snd_kcontrol *kctl,
* and then perform another volume-related command. Perhaps the
* first command is an "open" and the second command is a "close"?
*/
- if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) {
+ if (s->midi_vol == new_val) {
change = 0;
goto __skip_change;
}
- change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
- && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
- && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
- __skip_change:
+ change = host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
+ && host_write_ctrl_unsafe(s->io_base, new_val, 100)
+ && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)
+ && host_write_ctrl_unsafe(s->io_base, new_val, 100);
+ s->midi_vol = new_val;
+__skip_change:
/*
* Take the board out of HOST mode and back into MIDI mode ...
@@ -779,25 +683,30 @@ static struct snd_kcontrol_new midi_mixer_ctl = {
* These IRQs are encoded as bit patterns so that they can be
* written to the control registers.
*/
-static unsigned __devinit get_irq_config(int irq)
+static unsigned get_irq_config(int sscape_type, int irq)
{
static const int valid_irq[] = { 9, 5, 7, 10 };
+ static const int old_irq[] = { 9, 7, 5, 15 };
unsigned cfg;
- for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) {
- if (irq == valid_irq[cfg])
- return cfg;
- } /* for */
+ if (sscape_type == MEDIA_FX) {
+ for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg)
+ if (irq == old_irq[cfg])
+ return cfg;
+ } else {
+ for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg)
+ if (irq == valid_irq[cfg])
+ return cfg;
+ }
return INVALID_IRQ;
}
-
/*
* Perform certain arcane port-checks to see whether there
* is a SoundScape board lurking behind the given ports.
*/
-static int __devinit detect_sscape(struct soundscape *s)
+static int detect_sscape(struct soundscape *s, long wss_io)
{
unsigned long flags;
unsigned d;
@@ -817,13 +726,11 @@ static int __devinit detect_sscape(struct soundscape *s)
if ((d & 0x80) != 0)
goto _done;
- if (d == 0) {
- s->codec_type = 1;
+ if (d == 0)
s->ic_type = IC_ODIE;
- } else if ((d & 0x60) != 0) {
- s->codec_type = 2;
+ else if ((d & 0x60) != 0)
s->ic_type = IC_OPUS;
- } else
+ else
goto _done;
outb(0xfa, ODIE_ADDR_IO(s->io_base));
@@ -833,15 +740,59 @@ static int __devinit detect_sscape(struct soundscape *s)
outb(0xfe, ODIE_ADDR_IO(s->io_base));
if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0e)
goto _done;
- if ((inb(ODIE_DATA_IO(s->io_base)) & 0x9f) != 0x0e)
+
+ outb(0xfe, ODIE_ADDR_IO(s->io_base));
+ d = inb(ODIE_DATA_IO(s->io_base));
+ if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e)
+ goto _done;
+
+ if (s->ic_type == IC_OPUS)
+ activate_ad1845_unsafe(s->io_base);
+
+ if (s->type == SSCAPE_VIVO)
+ wss_io += 4;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+
+ /* wait for WSS codec */
+ for (d = 0; d < 500; d++) {
+ if ((inb(wss_io) & 0x80) == 0)
+ break;
+ spin_unlock_irqrestore(&s->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&s->lock, flags);
+ }
+
+ if ((inb(wss_io) & 0x80) != 0)
goto _done;
+ if (inb(wss_io + 2) == 0xff)
+ goto _done;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d);
+
+ if ((inb(wss_io) & 0x80) != 0)
+ s->type = MEDIA_FX;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+ /* wait for WSS codec */
+ for (d = 0; d < 500; d++) {
+ if ((inb(wss_io) & 0x80) == 0)
+ break;
+ spin_unlock_irqrestore(&s->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&s->lock, flags);
+ }
+
/*
* SoundScape successfully detected!
*/
retval = 1;
- _done:
+_done:
spin_unlock_irqrestore(&s->lock, flags);
return retval;
}
@@ -852,64 +803,34 @@ static int __devinit detect_sscape(struct soundscape *s)
* to crash the machine. Also check that someone isn't using the hardware
* IOCTL device.
*/
-static int mpu401_open(struct snd_mpu401 * mpu)
+static int mpu401_open(struct snd_mpu401 *mpu)
{
- int err;
-
if (!verify_mpu401(mpu)) {
- snd_printk(KERN_ERR "sscape: MIDI disabled, please load firmware\n");
- err = -ENODEV;
- } else {
- register struct soundscape *sscape = get_mpu401_soundscape(mpu);
- unsigned long flags;
-
- spin_lock_irqsave(&sscape->fwlock, flags);
-
- if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) {
- err = -EBUSY;
- } else {
- ++(sscape->midi_usage);
- err = 0;
- }
-
- spin_unlock_irqrestore(&sscape->fwlock, flags);
+ snd_printk(KERN_ERR "sscape: MIDI disabled, "
+ "please load firmware\n");
+ return -ENODEV;
}
- return err;
-}
-
-static void mpu401_close(struct snd_mpu401 * mpu)
-{
- register struct soundscape *sscape = get_mpu401_soundscape(mpu);
- unsigned long flags;
-
- spin_lock_irqsave(&sscape->fwlock, flags);
- --(sscape->midi_usage);
- spin_unlock_irqrestore(&sscape->fwlock, flags);
+ return 0;
}
/*
* Initialse an MPU-401 subdevice for MIDI support on the SoundScape.
*/
-static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq)
+static int create_mpu401(struct snd_card *card, int devnum,
+ unsigned long port, int irq)
{
struct soundscape *sscape = get_card_soundscape(card);
struct snd_rawmidi *rawmidi;
int err;
-#define MPU401_SHARE_HARDWARE 1
- if ((err = snd_mpu401_uart_new(card, devnum,
- MPU401_HW_MPU401,
- port, MPU401_SHARE_HARDWARE,
- irq, SA_INTERRUPT,
- &rawmidi)) == 0) {
- struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data;
+ err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port,
+ MPU401_INFO_INTEGRATED, irq, &rawmidi);
+ if (err == 0) {
+ struct snd_mpu401 *mpu = rawmidi->private_data;
mpu->open_input = mpu401_open;
mpu->open_output = mpu401_open;
- mpu->close_input = mpu401_close;
- mpu->close_output = mpu401_close;
mpu->private_data = sscape;
- sscape->mpu = mpu;
initialise_mpu401(mpu);
}
@@ -919,166 +840,95 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l
/*
- * Override for the CS4231 playback format function.
- * The AD1845 has much simpler format and rate selection.
- */
-static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format)
-{
- unsigned long flags;
- unsigned rate = params_rate(params);
-
- /*
- * The AD1845 can't handle sample frequencies
- * outside of 4 kHZ to 50 kHZ
- */
- if (rate > 50000)
- rate = 50000;
- else if (rate < 4000)
- rate = 4000;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
-
- /*
- * Program the AD1845 correctly for the playback stream.
- * Note that we do NOT need to toggle the MCE bit because
- * the PLAYBACK_ENABLE bit of the Interface Configuration
- * register is set.
- *
- * NOTE: We seem to need to write to the MSB before the LSB
- * to get the correct sample frequency.
- */
- snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
- snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
- snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/*
- * Override for the CS4231 capture format function.
- * The AD1845 has much simpler format and rate selection.
- */
-static void ad1845_capture_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format)
-{
- unsigned long flags;
- unsigned rate = params_rate(params);
-
- /*
- * The AD1845 can't handle sample frequencies
- * outside of 4 kHZ to 50 kHZ
- */
- if (rate > 50000)
- rate = 50000;
- else if (rate < 4000)
- rate = 4000;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
-
- /*
- * Program the AD1845 correctly for the playback stream.
- * Note that we do NOT need to toggle the MCE bit because
- * the CAPTURE_ENABLE bit of the Interface Configuration
- * register is set.
- *
- * NOTE: We seem to need to write to the MSB before the LSB
- * to get the correct sample frequency.
- */
- snd_cs4231_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
- snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
- snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/*
* Create an AD1845 PCM subdevice on the SoundScape. The AD1845
* is very much like a CS4231, with a few extra bits. We will
* try to support at least some of the extra bits by overriding
* some of the CS4231 callback.
*/
-static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq, int dma1)
+static int create_ad1845(struct snd_card *card, unsigned port,
+ int irq, int dma1, int dma2)
{
register struct soundscape *sscape = get_card_soundscape(card);
- struct snd_cs4231 *chip;
+ struct snd_wss *chip;
int err;
+ int codec_type = WSS_HW_DETECT;
-#define CS4231_SHARE_HARDWARE (CS4231_HWSHARE_DMA1 | CS4231_HWSHARE_DMA2)
- /*
- * The AD1845 PCM device is only half-duplex, and so
- * we only give it one DMA channel ...
- */
- if ((err = snd_cs4231_create(card,
- port, -1, irq, dma1, dma1,
- CS4231_HW_DETECT,
- CS4231_HWSHARE_DMA1, &chip)) == 0) {
- unsigned long flags;
- struct snd_pcm *pcm;
-
-#define AD1845_FREQ_SEL_ENABLE 0x08
+ switch (sscape->type) {
+ case MEDIA_FX:
+ case SSCAPE:
+ /*
+ * There are some freak examples of early Soundscape cards
+ * with CS4231 instead of AD1848/CS4248. Unfortunately, the
+ * CS4231 works only in CS4248 compatibility mode on
+ * these cards so force it.
+ */
+ if (sscape->ic_type != IC_OPUS)
+ codec_type = WSS_HW_AD1848;
+ break;
-#define AD1845_PWR_DOWN_CTRL 0x1b
-#define AD1845_CRYS_CLOCK_SEL 0x1d
+ case SSCAPE_VIVO:
+ port += 4;
+ break;
+ default:
+ break;
+ }
-/*
- * It turns out that the PLAYBACK_ENABLE bit is set
- * by the lowlevel driver ...
- *
-#define AD1845_IFACE_CONFIG \
- (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
- */
+ err = snd_wss_create(card, port, -1, irq, dma1, dma2,
+ codec_type, WSS_HWSHARE_DMA1, &chip);
+ if (!err) {
+ unsigned long flags;
+ struct snd_pcm *pcm;
- /*
- * The input clock frequency on the SoundScape must
- * be 14.31818 MHz, because we must set this register
- * to get the playback to sound correct ...
- */
- snd_cs4231_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_cs4231_mce_down(chip);
+ if (sscape->type != SSCAPE_VIVO) {
+ /*
+ * The input clock frequency on the SoundScape must
+ * be 14.31818 MHz, because we must set this register
+ * to get the playback to sound correct ...
+ */
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, AD1845_CLOCK, 0x20);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
- /*
- * More custom configuration:
- * a) select "mode 2", and provide a current drive of 8 mA
- * b) enable frequency selection (for capture/playback)
- */
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs4231_out(chip, CS4231_MISC_INFO, (CS4231_MODE2 | 0x10));
- snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL, snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL) | AD1845_FREQ_SEL_ENABLE);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ }
- if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) {
- snd_printk(KERN_ERR "sscape: No PCM device for AD1845 chip\n");
+ err = snd_wss_pcm(chip, 0, &pcm);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: No PCM device "
+ "for AD1845 chip\n");
goto _error;
}
- if ((err = snd_cs4231_mixer(chip)) < 0) {
- snd_printk(KERN_ERR "sscape: No mixer device for AD1845 chip\n");
+ err = snd_wss_mixer(chip);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: No mixer device "
+ "for AD1845 chip\n");
goto _error;
}
+ if (chip->hardware != WSS_HW_AD1848) {
+ err = snd_wss_timer(chip, 0, NULL);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: No timer device "
+ "for AD1845 chip\n");
+ goto _error;
+ }
+ }
- if ((err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip))) < 0) {
- snd_printk(KERN_ERR "sscape: Could not create MIDI mixer control\n");
- goto _error;
+ if (sscape->type != SSCAPE_VIVO) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&midi_mixer_ctl, chip));
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: Could not create "
+ "MIDI mixer control\n");
+ goto _error;
+ }
}
- strcpy(card->driver, "SoundScape");
- strcpy(card->shortname, pcm->name);
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, IRQ %d, DMA %d\n",
- pcm->name, chip->port, chip->irq, chip->dma1);
- chip->set_playback_format = ad1845_playback_format;
- chip->set_capture_format = ad1845_capture_format;
sscape->chip = chip;
}
- _error:
+_error:
return err;
}
@@ -1087,93 +937,98 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq
* Create an ALSA soundcard entry for the SoundScape, using
* the given list of port, IRQ and DMA resources.
*/
-static int __devinit create_sscape(int dev, struct snd_card **rcardp)
+static int create_sscape(int dev, struct snd_card *card)
{
- struct snd_card *card;
- register struct soundscape *sscape;
- register unsigned dma_cfg;
+ struct soundscape *sscape = get_card_soundscape(card);
+ unsigned dma_cfg;
unsigned irq_cfg;
unsigned mpu_irq_cfg;
- unsigned xport;
struct resource *io_res;
+ struct resource *wss_res;
unsigned long flags;
int err;
-
- /*
- * Check that the user didn't pass us garbage data ...
- */
- irq_cfg = get_irq_config(irq[dev]);
- if (irq_cfg == INVALID_IRQ) {
- snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
- return -ENXIO;
- }
-
- mpu_irq_cfg = get_irq_config(mpu_irq[dev]);
- if (mpu_irq_cfg == INVALID_IRQ) {
- printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
- return -ENXIO;
- }
- xport = port[dev];
+ int val;
+ const char *name;
/*
* Grab IO ports that we will need to probe so that we
* can detect and control this hardware ...
*/
- if ((io_res = request_region(xport, 8, "SoundScape")) == NULL) {
- snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);
+ io_res = request_region(port[dev], 8, "SoundScape");
+ if (!io_res) {
+ snd_printk(KERN_ERR
+ "sscape: can't grab port 0x%lx\n", port[dev]);
return -EBUSY;
}
+ wss_res = NULL;
+ if (sscape->type == SSCAPE_VIVO) {
+ wss_res = request_region(wss_port[dev], 4, "SoundScape");
+ if (!wss_res) {
+ snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n",
+ wss_port[dev]);
+ err = -EBUSY;
+ goto _release_region;
+ }
+ }
/*
- * Grab both DMA channels (OK, only one for now) ...
+ * Grab one DMA channel ...
*/
- if ((err = request_dma(dma[dev], "SoundScape")) < 0) {
+ err = request_dma(dma[dev], "SoundScape");
+ if (err < 0) {
snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", dma[dev]);
goto _release_region;
}
- /*
- * Create a new ALSA sound card entry, in anticipation
- * of detecting our hardware ...
- */
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct soundscape))) == NULL) {
- err = -ENOMEM;
- goto _release_dma;
- }
-
- sscape = get_card_soundscape(card);
spin_lock_init(&sscape->lock);
- spin_lock_init(&sscape->fwlock);
sscape->io_res = io_res;
- sscape->io_base = xport;
+ sscape->wss_res = wss_res;
+ sscape->io_base = port[dev];
- if (!detect_sscape(sscape)) {
- printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
+ if (!detect_sscape(sscape, wss_port[dev])) {
+ printk(KERN_ERR "sscape: hardware not detected at 0x%x\n",
+ sscape->io_base);
err = -ENODEV;
- goto _release_card;
+ goto _release_dma;
+ }
+
+ switch (sscape->type) {
+ case MEDIA_FX:
+ name = "MediaFX/SoundFX";
+ break;
+ case SSCAPE:
+ name = "Soundscape";
+ break;
+ case SSCAPE_PNP:
+ name = "Soundscape PnP";
+ break;
+ case SSCAPE_VIVO:
+ name = "Soundscape VIVO";
+ break;
+ default:
+ name = "unknown Soundscape";
+ break;
}
- printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",
- sscape->io_base, irq[dev], dma[dev]);
+ printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
+ name, sscape->io_base, irq[dev], dma[dev]);
/*
- * Now create the hardware-specific device so that we can
- * load the microcode into the on-board processor.
- * We cannot use the MPU-401 MIDI system until this firmware
- * has been loaded into the card.
+ * Check that the user didn't pass us garbage data ...
*/
- if ((err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw))) < 0) {
- printk(KERN_ERR "sscape: Failed to create firmware device\n");
- goto _release_card;
+ irq_cfg = get_irq_config(sscape->type, irq[dev]);
+ if (irq_cfg == INVALID_IRQ) {
+ snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
+ err = -ENXIO;
+ goto _release_dma;
+ }
+
+ mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]);
+ if (mpu_irq_cfg == INVALID_IRQ) {
+ snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
+ err = -ENXIO;
+ goto _release_dma;
}
- strlcpy(sscape->hw->name, "SoundScape M68K", sizeof(sscape->hw->name));
- sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';
- sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;
- sscape->hw->ops.open = sscape_hw_open;
- sscape->hw->ops.release = sscape_hw_release;
- sscape->hw->ops.ioctl = sscape_hw_ioctl;
- sscape->hw->private_data = sscape;
/*
* Tell the on-board devices where their resources are (I think -
@@ -1181,9 +1036,6 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp)
*/
spin_lock_irqsave(&sscape->lock, flags);
- activate_ad1845_unsafe(sscape->io_base);
-
- sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */
sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
@@ -1191,14 +1043,23 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp)
* Enable and configure the DMA channels ...
*/
sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
- dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40);
+ dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
+ mpu_irq_cfg |= mpu_irq_cfg << 2;
+ val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7;
+ if (joystick[dev])
+ val |= 8;
+ sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10);
+ sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
sscape_write_unsafe(sscape->io_base,
- GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg);
- sscape_write_unsafe(sscape->io_base,
- GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1));
+ GA_CDCFG_REG, 0x09 | DMA_8BIT
+ | (dma[dev] << 4) | (irq_cfg << 1));
+ /*
+ * Enable the master IRQ ...
+ */
+ sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
spin_unlock_irqrestore(&sscape->lock, flags);
@@ -1206,30 +1067,60 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp)
* We have now enabled the codec chip, and so we should
* detect the AD1845 device ...
*/
- if ((err = create_ad1845(card, CODEC_IO(xport), irq[dev], dma[dev])) < 0) {
- printk(KERN_ERR "sscape: No AD1845 device at 0x%x, IRQ %d\n",
- CODEC_IO(xport), irq[dev]);
- goto _release_card;
- }
-#define MIDI_DEVNUM 0
- if ((err = create_mpu401(card, MIDI_DEVNUM, MPU401_IO(xport), mpu_irq[dev])) < 0) {
- printk(KERN_ERR "sscape: Failed to create MPU-401 device at 0x%x\n",
- MPU401_IO(xport));
- goto _release_card;
+ err = create_ad1845(card, wss_port[dev], irq[dev],
+ dma[dev], dma2[dev]);
+ if (err < 0) {
+ snd_printk(KERN_ERR
+ "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
+ wss_port[dev], irq[dev]);
+ goto _release_dma;
}
+ strcpy(card->driver, "SoundScape");
+ strcpy(card->shortname, name);
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
+ name, sscape->chip->port, sscape->chip->irq,
+ sscape->chip->dma1, sscape->chip->dma2);
- /*
- * Enable the master IRQ ...
- */
- sscape_write(sscape, GA_INTENA_REG, 0x80);
+#define MIDI_DEVNUM 0
+ if (sscape->type != SSCAPE_VIVO) {
+ err = sscape_upload_bootblock(card);
+ if (err >= 0)
+ err = sscape_upload_microcode(card, err);
+
+ if (err == 0) {
+ err = create_mpu401(card, MIDI_DEVNUM, port[dev],
+ mpu_irq[dev]);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: Failed to create "
+ "MPU-401 device at 0x%lx\n",
+ port[dev]);
+ goto _release_dma;
+ }
- /*
- * Initialize mixer
- */
- sscape->midi_vol = 0;
- host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);
- host_write_ctrl_unsafe(sscape->io_base, 0, 100);
- host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);
+ /*
+ * Initialize mixer
+ */
+ spin_lock_irqsave(&sscape->lock, flags);
+ sscape->midi_vol = 0;
+ host_write_ctrl_unsafe(sscape->io_base,
+ CMD_SET_MIDI_VOL, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ sscape->midi_vol, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ CMD_XXX_MIDI_VOL, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ sscape->midi_vol, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ CMD_SET_EXTMIDI, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ 0, 100);
+ host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
+
+ set_midi_mode_unsafe(sscape->io_base);
+ spin_unlock_irqrestore(&sscape->lock, flags);
+ }
+ }
/*
* Now that we have successfully created this sound card,
@@ -1238,62 +1129,93 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp)
* function now that our "constructor" has completed.
*/
card->private_free = soundscape_free;
- *rcardp = card;
return 0;
- _release_card:
- snd_card_free(card);
-
- _release_dma:
+_release_dma:
free_dma(dma[dev]);
- _release_region:
+_release_region:
+ release_and_free_resource(wss_res);
release_and_free_resource(io_res);
return err;
}
-static int __init snd_sscape_probe(struct platform_device *pdev)
+static int snd_sscape_match(struct device *pdev, unsigned int i)
+{
+ /*
+ * Make sure we were given ALL of the other parameters.
+ */
+ if (port[i] == SNDRV_AUTO_PORT)
+ return 0;
+
+ if (irq[i] == SNDRV_AUTO_IRQ ||
+ mpu_irq[i] == SNDRV_AUTO_IRQ ||
+ dma[i] == SNDRV_AUTO_DMA) {
+ printk(KERN_INFO
+ "sscape: insufficient parameters, "
+ "need IO, IRQ, MPU-IRQ and DMA\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int snd_sscape_probe(struct device *pdev, unsigned int dev)
{
- int dev = pdev->id;
struct snd_card *card;
+ struct soundscape *sscape;
int ret;
- dma[dev] &= 0x03;
- ret = create_sscape(dev, &card);
+ ret = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct soundscape), &card);
if (ret < 0)
return ret;
- snd_card_set_dev(card, &pdev->dev);
- if ((ret = snd_card_register(card)) < 0) {
- printk(KERN_ERR "sscape: Failed to register sound card\n");
- return ret;
+
+ sscape = get_card_soundscape(card);
+ sscape->type = SSCAPE;
+
+ dma[dev] &= 0x03;
+
+ ret = create_sscape(dev, card);
+ if (ret < 0)
+ goto _release_card;
+
+ ret = snd_card_register(card);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
+ goto _release_card;
}
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(pdev, card);
return 0;
+
+_release_card:
+ snd_card_free(card);
+ return ret;
}
-static int __devexit snd_sscape_remove(struct platform_device *devptr)
+static int snd_sscape_remove(struct device *devptr, unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
return 0;
}
-#define SSCAPE_DRIVER "snd_sscape"
+#define DEV_NAME "sscape"
-static struct platform_driver snd_sscape_driver = {
+static struct isa_driver snd_sscape_driver = {
+ .match = snd_sscape_match,
.probe = snd_sscape_probe,
- .remove = __devexit_p(snd_sscape_remove),
+ .remove = snd_sscape_remove,
/* FIXME: suspend/resume */
.driver = {
- .name = SSCAPE_DRIVER
+ .name = DEV_NAME
},
};
#ifdef CONFIG_PNP
-static inline int __devinit get_next_autoindex(int i)
+static inline int get_next_autoindex(int i)
{
while (i < SNDRV_CARDS && port[i] != SNDRV_AUTO_PORT)
++i;
@@ -1301,77 +1223,92 @@ static inline int __devinit get_next_autoindex(int i)
}
-static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int sscape_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
static int idx = 0;
struct pnp_dev *dev;
struct snd_card *card;
+ struct soundscape *sscape;
int ret;
/*
* Allow this function to fail *quietly* if all the ISA PnP
* devices were configured using module parameters instead.
*/
- if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS)
+ idx = get_next_autoindex(idx);
+ if (idx >= SNDRV_CARDS)
return -ENOSPC;
/*
- * We have found a candidate ISA PnP card. Now we
- * have to check that it has the devices that we
- * expect it to have.
- *
- * We will NOT try and autoconfigure all of the resources
- * needed and then activate the card as we are assuming that
- * has already been done at boot-time using /proc/isapnp.
- * We shall simply try to give each active card the resources
- * that it wants. This is a sensible strategy for a modular
- * system where unused modules are unloaded regularly.
- *
- * This strategy is utterly useless if we compile the driver
- * into the kernel, of course.
- */
- // printk(KERN_INFO "sscape: %s\n", card->name);
-
- /*
* Check that we still have room for another sound card ...
*/
dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
- if (! dev)
+ if (!dev)
return -ENODEV;
if (!pnp_is_active(dev)) {
if (pnp_activate_dev(dev) < 0) {
- printk(KERN_INFO "sscape: device is inactive\n");
+ snd_printk(KERN_INFO "sscape: device is inactive\n");
return -EBUSY;
}
}
/*
+ * Create a new ALSA sound card entry, in anticipation
+ * of detecting our hardware ...
+ */
+ ret = snd_card_new(&pcard->card->dev,
+ index[idx], id[idx], THIS_MODULE,
+ sizeof(struct soundscape), &card);
+ if (ret < 0)
+ return ret;
+
+ sscape = get_card_soundscape(card);
+
+ /*
+ * Identify card model ...
+ */
+ if (!strncmp("ENS4081", pid->id, 7))
+ sscape->type = SSCAPE_VIVO;
+ else
+ sscape->type = SSCAPE_PNP;
+
+ /*
* Read the correct parameters off the ISA PnP bus ...
*/
port[idx] = pnp_port_start(dev, 0);
irq[idx] = pnp_irq(dev, 0);
mpu_irq[idx] = pnp_irq(dev, 1);
dma[idx] = pnp_dma(dev, 0) & 0x03;
+ if (sscape->type == SSCAPE_PNP) {
+ dma2[idx] = dma[idx];
+ wss_port[idx] = CODEC_IO(port[idx]);
+ } else {
+ wss_port[idx] = pnp_port_start(dev, 1);
+ dma2[idx] = pnp_dma(dev, 1);
+ }
- ret = create_sscape(idx, &card);
+ ret = create_sscape(idx, card);
if (ret < 0)
- return ret;
- snd_card_set_dev(card, &pcard->card->dev);
- if ((ret = snd_card_register(card)) < 0) {
- printk(KERN_ERR "sscape: Failed to register sound card\n");
- snd_card_free(card);
- return ret;
+ goto _release_card;
+
+ ret = snd_card_register(card);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
+ goto _release_card;
}
pnp_set_card_drvdata(pcard, card);
++idx;
+ return 0;
+_release_card:
+ snd_card_free(card);
return ret;
}
-static void __devexit sscape_pnp_remove(struct pnp_card_link * pcard)
+static void sscape_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -1382,93 +1319,38 @@ static struct pnp_card_driver sscape_pnpc_driver = {
.name = "sscape",
.id_table = sscape_pnpids,
.probe = sscape_pnp_detect,
- .remove = __devexit_p(sscape_pnp_remove),
+ .remove = sscape_pnp_remove,
};
#endif /* CONFIG_PNP */
-static void __init_or_module sscape_unregister_all(void)
-{
- int i;
-
- if (pnp_registered)
- pnp_unregister_card_driver(&sscape_pnpc_driver);
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&snd_sscape_driver);
-}
-
-static int __init sscape_manual_probe(void)
+static int __init sscape_init(void)
{
- struct platform_device *device;
- int i, ret;
-
- ret = platform_driver_register(&snd_sscape_driver);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < SNDRV_CARDS; ++i) {
- /*
- * We do NOT probe for ports.
- * If we're not given a port number for this
- * card then we completely ignore this line
- * of parameters.
- */
- if (port[i] == SNDRV_AUTO_PORT)
- continue;
-
- /*
- * Make sure we were given ALL of the other parameters.
- */
- if (irq[i] == SNDRV_AUTO_IRQ ||
- mpu_irq[i] == SNDRV_AUTO_IRQ ||
- dma[i] == SNDRV_AUTO_DMA) {
- printk(KERN_INFO
- "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n");
- ret = -ENXIO;
- goto errout;
- }
+ int err;
- /*
- * This cards looks OK ...
- */
- device = platform_device_register_simple(SSCAPE_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- ret = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- }
- return 0;
+ err = isa_register_driver(&snd_sscape_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+ if (!err)
+ isa_registered = 1;
- errout:
- sscape_unregister_all();
- return ret;
-}
+ err = pnp_register_card_driver(&sscape_pnpc_driver);
+ if (!err)
+ pnp_registered = 1;
-static void sscape_exit(void)
-{
- sscape_unregister_all();
+ if (isa_registered)
+ err = 0;
+#endif
+ return err;
}
-
-static int __init sscape_init(void)
+static void __exit sscape_exit(void)
{
- int ret;
-
- /*
- * First check whether we were passed any parameters.
- * These MUST take precedence over ANY automatic way
- * of allocating cards, because the operator is
- * S-P-E-L-L-I-N-G it out for us...
- */
- ret = sscape_manual_probe();
- if (ret < 0)
- return ret;
- if (pnp_register_card_driver(&sscape_pnpc_driver) >= 0)
- pnp_registered = 1;
- return 0;
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&sscape_pnpc_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_sscape_driver);
}
module_init(sscape_init);
diff --git a/sound/isa/wavefront/Makefile b/sound/isa/wavefront/Makefile
index b4cb28422db..601bdddd44d 100644
--- a/sound/isa/wavefront/Makefile
+++ b/sound/isa/wavefront/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for ALSA
-# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
snd-wavefront-objs := wavefront.o wavefront_fx.o wavefront_synth.o wavefront_midi.o
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index a6dcb2f970c..bfbf38cf984 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -1,6 +1,6 @@
/*
* ALSA card-level driver for Turtle Beach Wavefront cards
- * (Maui,Tropez,Tropez+)
+ * (Maui,Tropez,Tropez+)
*
* Copyright (c) 1997-1999 by Paul Barton-Davis <pbd@op.net>
*
@@ -19,17 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/isa.h>
#include <linux/pnp.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/opl3.h>
+#include <sound/wss.h>
#include <sound/snd_wavefront.h>
MODULE_AUTHOR("Paul Barton-Davis <pbd@op.net>");
@@ -39,8 +38,10 @@ MODULE_SUPPORTED_DEVICE("{{Turtle Beach,Maui/Tropez/Tropez+}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+#ifdef CONFIG_PNP
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+#endif
static long cs4232_pcm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static int cs4232_pcm_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */
static long cs4232_mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
@@ -50,7 +51,7 @@ static int ics2115_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,9,11,12,15 */
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
-static int use_cs4232_midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static bool use_cs4232_midi[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for WaveFront soundcard.");
@@ -83,11 +84,9 @@ MODULE_PARM_DESC(fm_port, "FM port #.");
module_param_array(use_cs4232_midi, bool, NULL, 0444);
MODULE_PARM_DESC(use_cs4232_midi, "Use CS4232 MPU-401 interface (inaccessibly located inside your computer)");
-static struct platform_device *platform_devices[SNDRV_CARDS];
-static int pnp_registered;
-
-
#ifdef CONFIG_PNP
+static int isa_registered;
+static int pnp_registered;
static struct pnp_card_device_id snd_wavefront_pnpids[] = {
/* Tropez */
@@ -99,26 +98,20 @@ static struct pnp_card_device_id snd_wavefront_pnpids[] = {
MODULE_DEVICE_TABLE(pnp_card, snd_wavefront_pnpids);
-static int __devinit
+static int
snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *card,
const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
int err;
- if (!cfg)
- return -ENOMEM;
-
/* Check for each logical device. */
/* CS4232 chip (aka "windows sound system") is logical device 0 */
acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (acard->wss == NULL) {
- kfree(cfg);
+ if (acard->wss == NULL)
return -EBUSY;
- }
/* there is a game port at logical device 1, but we ignore it completely */
@@ -133,26 +126,20 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
if (use_cs4232_midi[dev]) {
acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
- if (acard->mpu == NULL) {
- kfree(cfg);
+ if (acard->mpu == NULL)
return -EBUSY;
- }
}
/* The ICS2115 synth is logical device 4 */
acard->synth = pnp_request_card_device(card, id->devs[3].id, NULL);
- if (acard->synth == NULL) {
- kfree(cfg);
+ if (acard->synth == NULL)
return -EBUSY;
- }
/* PCM/FM initialization */
pdev = acard->wss;
- pnp_init_resource_table(cfg);
-
/* An interesting note from the Tropez+ FAQ:
Q. [Ports] Why is the base address of the WSS I/O ports off by 4?
@@ -165,23 +152,9 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
*/
- if (cs4232_pcm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], cs4232_pcm_port[dev], 4);
- if (fm_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
- if (dma1[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
- if (dma2[dev] != SNDRV_AUTO_DMA)
- pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
- if (cs4232_pcm_irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->irq_resource[0], cs4232_pcm_irq[dev], 1);
-
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR "PnP WSS the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR "PnP WSS pnp configure failure\n");
- kfree(cfg);
return err;
}
@@ -195,22 +168,9 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
pdev = acard->synth;
- pnp_init_resource_table(cfg);
-
- if (ics2115_port[dev] != SNDRV_AUTO_PORT) {
- pnp_resource_change(&cfg->port_resource[0], ics2115_port[dev], 16);
- }
-
- if (ics2115_port[dev] != SNDRV_AUTO_IRQ) {
- pnp_resource_change(&cfg->irq_resource[0], ics2115_irq[dev], 1);
- }
-
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR "PnP ICS2115 the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR "PnP ICS2115 pnp configure failure\n");
- kfree(cfg);
return err;
}
@@ -226,15 +186,6 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
pdev = acard->mpu;
- pnp_init_resource_table(cfg);
-
- if (cs4232_mpu_port[dev] != SNDRV_AUTO_PORT)
- pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_port[dev], 2);
- if (cs4232_mpu_irq[dev] != SNDRV_AUTO_IRQ)
- pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_irq[dev], 1);
-
- if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
- snd_printk(KERN_ERR "PnP MPU401 the requested resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR "PnP MPU401 pnp configure failure\n");
@@ -258,15 +209,12 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
ics2115_port[dev],
ics2115_irq[dev]);
- kfree(cfg);
return 0;
}
#endif /* CONFIG_PNP */
-static irqreturn_t snd_wavefront_ics2115_interrupt(int irq,
- void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_wavefront_ics2115_interrupt(int irq, void *dev_id)
{
snd_wavefront_card_t *acard;
@@ -283,10 +231,9 @@ static irqreturn_t snd_wavefront_ics2115_interrupt(int irq,
return IRQ_HANDLED;
}
-static struct snd_hwdep * __devinit
-snd_wavefront_new_synth (struct snd_card *card,
- int hw_dev,
- snd_wavefront_card_t *acard)
+static struct snd_hwdep *snd_wavefront_new_synth(struct snd_card *card,
+ int hw_dev,
+ snd_wavefront_card_t *acard)
{
struct snd_hwdep *wavefront_synth;
@@ -309,11 +256,10 @@ snd_wavefront_new_synth (struct snd_card *card,
return wavefront_synth;
}
-static struct snd_hwdep * __devinit
-snd_wavefront_new_fx (struct snd_card *card,
- int hw_dev,
- snd_wavefront_card_t *acard,
- unsigned long port)
+static struct snd_hwdep *snd_wavefront_new_fx(struct snd_card *card,
+ int hw_dev,
+ snd_wavefront_card_t *acard,
+ unsigned long port)
{
struct snd_hwdep *fx_processor;
@@ -336,12 +282,11 @@ snd_wavefront_new_fx (struct snd_card *card,
static snd_wavefront_mpu_id internal_id = internal_mpu;
static snd_wavefront_mpu_id external_id = external_mpu;
-static struct snd_rawmidi *__devinit
-snd_wavefront_new_midi (struct snd_card *card,
- int midi_dev,
- snd_wavefront_card_t *acard,
- unsigned long port,
- snd_wavefront_mpu_id mpu)
+static struct snd_rawmidi *snd_wavefront_new_midi(struct snd_card *card,
+ int midi_dev,
+ snd_wavefront_card_t *acard,
+ unsigned long port,
+ snd_wavefront_mpu_id mpu)
{
struct snd_rawmidi *rmidi;
@@ -371,8 +316,8 @@ snd_wavefront_new_midi (struct snd_card *card,
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_wavefront_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
- SNDRV_RAWMIDI_INFO_INPUT |
- SNDRV_RAWMIDI_INFO_DUPLEX;
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
return rmidi;
}
@@ -389,15 +334,17 @@ snd_wavefront_free(struct snd_card *card)
}
}
-static struct snd_card *snd_wavefront_card_new(int dev)
+static int snd_wavefront_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
snd_wavefront_card_t *acard;
+ int err;
- card = snd_card_new (index[dev], id[dev], THIS_MODULE,
- sizeof(snd_wavefront_card_t));
- if (card == NULL)
- return NULL;
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(snd_wavefront_card_t), &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
acard->wavefront.irq = -1;
@@ -405,16 +352,18 @@ 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;
+ *cardp = card;
+ return 0;
}
-static int __devinit
+static int
snd_wavefront_probe (struct snd_card *card, int dev)
{
snd_wavefront_card_t *acard = card->private_data;
- struct snd_cs4231 *chip;
+ struct snd_wss *chip;
struct snd_hwdep *wavefront_synth;
struct snd_rawmidi *ics2115_internal_rmidi = NULL;
struct snd_rawmidi *ics2115_external_rmidi = NULL;
@@ -423,21 +372,20 @@ snd_wavefront_probe (struct snd_card *card, int dev)
/* --------- PCM --------------- */
- if ((err = snd_cs4231_create (card,
- cs4232_pcm_port[dev],
- -1,
- cs4232_pcm_irq[dev],
- dma1[dev],
- dma2[dev],
- CS4231_HW_DETECT, 0, &chip)) < 0) {
- snd_printk (KERN_ERR "can't allocate CS4231 device\n");
+ err = snd_wss_create(card, cs4232_pcm_port[dev], -1,
+ cs4232_pcm_irq[dev], dma1[dev], dma2[dev],
+ WSS_HW_DETECT, 0, &chip);
+ if (err < 0) {
+ snd_printk(KERN_ERR "can't allocate WSS device\n");
return err;
}
- if ((err = snd_cs4231_pcm (chip, 0, NULL)) < 0)
+ err = snd_wss_pcm(chip, 0, NULL);
+ if (err < 0)
return err;
- if ((err = snd_cs4231_timer (chip, 0, NULL)) < 0)
+ err = snd_wss_timer(chip, 0, NULL);
+ if (err < 0)
return err;
/* ---------- OPL3 synth --------- */
@@ -445,30 +393,30 @@ snd_wavefront_probe (struct snd_card *card, int dev)
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
struct snd_opl3 *opl3;
- if ((err = snd_opl3_create(card,
- fm_port[dev],
- fm_port[dev] + 2,
- OPL3_HW_OPL3_CS,
- 0, &opl3)) < 0) {
+ err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
+ OPL3_HW_OPL3_CS, 0, &opl3);
+ if (err < 0) {
snd_printk (KERN_ERR "can't allocate or detect OPL3 synth\n");
return err;
}
- if ((err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL)) < 0)
+ err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL);
+ if (err < 0)
return err;
hw_dev++;
}
/* ------- ICS2115 Wavetable synth ------- */
- if ((acard->wavefront.res_base = request_region(ics2115_port[dev], 16,
- "ICS2115")) == NULL) {
+ acard->wavefront.res_base = request_region(ics2115_port[dev], 16,
+ "ICS2115");
+ if (acard->wavefront.res_base == NULL) {
snd_printk(KERN_ERR "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n",
ics2115_port[dev], ics2115_port[dev] + 16 - 1);
return -EBUSY;
}
if (request_irq(ics2115_irq[dev], snd_wavefront_ics2115_interrupt,
- SA_INTERRUPT, "ICS2115", acard)) {
+ 0, "ICS2115", acard)) {
snd_printk(KERN_ERR "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]);
return -EBUSY;
}
@@ -476,7 +424,8 @@ snd_wavefront_probe (struct snd_card *card, int dev)
acard->wavefront.irq = ics2115_irq[dev];
acard->wavefront.base = ics2115_port[dev];
- if ((wavefront_synth = snd_wavefront_new_synth (card, hw_dev, acard)) == NULL) {
+ wavefront_synth = snd_wavefront_new_synth(card, hw_dev, acard);
+ if (wavefront_synth == NULL) {
snd_printk (KERN_ERR "can't create WaveFront synth device\n");
return -ENOMEM;
}
@@ -487,7 +436,8 @@ snd_wavefront_probe (struct snd_card *card, int dev)
/* --------- Mixer ------------ */
- if ((err = snd_cs4231_mixer(chip)) < 0) {
+ err = snd_wss_mixer(chip);
+ if (err < 0) {
snd_printk (KERN_ERR "can't allocate mixer device\n");
return err;
}
@@ -495,11 +445,10 @@ snd_wavefront_probe (struct snd_card *card, int dev)
/* -------- CS4232 MPU-401 interface -------- */
if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) {
- if ((err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232,
- cs4232_mpu_port[dev], 0,
- cs4232_mpu_irq[dev],
- SA_INTERRUPT,
- NULL)) < 0) {
+ err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232,
+ cs4232_mpu_port[dev], 0,
+ cs4232_mpu_irq[dev], NULL);
+ if (err < 0) {
snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n");
return err;
}
@@ -590,57 +539,67 @@ snd_wavefront_probe (struct snd_card *card, int dev)
return snd_card_register(card);
}
-static int __init snd_wavefront_nonpnp_probe(struct platform_device *pdev)
+static int snd_wavefront_isa_match(struct device *pdev,
+ unsigned int dev)
{
- int dev = pdev->id;
- struct snd_card *card;
- int err;
-
+ if (!enable[dev])
+ return 0;
+#ifdef CONFIG_PNP
+ if (isapnp[dev])
+ return 0;
+#endif
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk("specify CS4232 port\n");
- return -EINVAL;
+ snd_printk(KERN_ERR "specify CS4232 port\n");
+ return 0;
}
if (ics2115_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk("specify ICS2115 port\n");
- return -ENODEV;
+ snd_printk(KERN_ERR "specify ICS2115 port\n");
+ return 0;
}
+ return 1;
+}
- card = snd_wavefront_card_new(dev);
- if (! card)
- return -ENOMEM;
- snd_card_set_dev(card, &pdev->dev);
+static int snd_wavefront_isa_probe(struct device *pdev,
+ unsigned int dev)
+{
+ struct snd_card *card;
+ int err;
+
+ err = snd_wavefront_card_new(pdev, dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_wavefront_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
}
- platform_set_drvdata(pdev, card);
+ dev_set_drvdata(pdev, card);
return 0;
}
-static int __devexit snd_wavefront_nonpnp_remove(struct platform_device *devptr)
+static int snd_wavefront_isa_remove(struct device *devptr,
+ unsigned int dev)
{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
+ snd_card_free(dev_get_drvdata(devptr));
return 0;
}
-#define WAVEFRONT_DRIVER "snd_wavefront"
+#define DEV_NAME "wavefront"
-static struct platform_driver snd_wavefront_driver = {
- .probe = snd_wavefront_nonpnp_probe,
- .remove = __devexit_p(snd_wavefront_nonpnp_remove),
+static struct isa_driver snd_wavefront_driver = {
+ .match = snd_wavefront_isa_match,
+ .probe = snd_wavefront_isa_probe,
+ .remove = snd_wavefront_isa_remove,
/* FIXME: suspend, resume */
.driver = {
- .name = WAVEFRONT_DRIVER
+ .name = DEV_NAME
},
};
#ifdef CONFIG_PNP
-
-static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
- const struct pnp_card_device_id *pid)
+static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
{
static int dev;
struct snd_card *card;
@@ -653,9 +612,9 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_wavefront_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_wavefront_card_new(&pcard->card->dev, dev, &card);
+ if (res < 0)
+ return res;
if (snd_wavefront_pnp (dev, card->private_data, pcard, pid) < 0) {
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
@@ -664,7 +623,6 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
return -ENODEV;
}
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_wavefront_probe(card, dev)) < 0)
return res;
@@ -674,7 +632,7 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
return 0;
}
-static void __devexit snd_wavefront_pnp_remove(struct pnp_card_link * pcard)
+static void snd_wavefront_pnp_remove(struct pnp_card_link *pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
@@ -685,69 +643,39 @@ static struct pnp_card_driver wavefront_pnpc_driver = {
.name = "wavefront",
.id_table = snd_wavefront_pnpids,
.probe = snd_wavefront_pnp_detect,
- .remove = __devexit_p(snd_wavefront_pnp_remove),
+ .remove = snd_wavefront_pnp_remove,
/* FIXME: suspend,resume */
};
#endif /* CONFIG_PNP */
-static void __init_or_module snd_wavefront_unregister_all(void)
-{
- int i;
-
- if (pnp_registered)
- pnp_unregister_card_driver(&wavefront_pnpc_driver);
- for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
- platform_device_unregister(platform_devices[i]);
- platform_driver_unregister(&snd_wavefront_driver);
-}
-
static int __init alsa_card_wavefront_init(void)
{
- int i, err, cards = 0;
-
- if ((err = platform_driver_register(&snd_wavefront_driver)) < 0)
- return err;
+ int err;
- for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
- struct platform_device *device;
+ err = isa_register_driver(&snd_wavefront_driver, SNDRV_CARDS);
#ifdef CONFIG_PNP
- if (isapnp[i])
- continue;
-#endif
- device = platform_device_register_simple(WAVEFRONT_DRIVER,
- i, NULL, 0);
- if (IS_ERR(device)) {
- err = PTR_ERR(device);
- goto errout;
- }
- platform_devices[i] = device;
- cards++;
- }
+ if (!err)
+ isa_registered = 1;
- i = pnp_register_card_driver(&wavefront_pnpc_driver);
- if (i >= 0) {
+ err = pnp_register_card_driver(&wavefront_pnpc_driver);
+ if (!err)
pnp_registered = 1;
- cards += i;
- }
- if (!cards) {
-#ifdef MODULE
- printk (KERN_ERR "No WaveFront cards found or devices busy\n");
+ if (isa_registered)
+ err = 0;
#endif
- err = -ENODEV;
- goto errout;
- }
- return 0;
-
- errout:
- snd_wavefront_unregister_all();
return err;
}
static void __exit alsa_card_wavefront_exit(void)
{
- snd_wavefront_unregister_all();
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&wavefront_pnpc_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_wavefront_driver);
}
module_init(alsa_card_wavefront_init)
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 180661c5ffd..b77883c7ee7 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -16,11 +16,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/snd_wavefront.h>
#include <sound/initval.h>
@@ -32,325 +34,7 @@
#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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 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[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 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_seven_v2[] __initdata = {
-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
-};
-
-static unsigned char mod_v2[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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[] __initdata = {
-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
-};
+#define WAIT_IDLE 0xff
static int
wavefront_fx_idle (snd_wavefront_t *dev)
@@ -490,11 +174,11 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
unsigned short *pd;
int err = 0;
- snd_assert(sdev->card != NULL, return -ENODEV);
-
card = sdev->card;
-
- snd_assert(card->private_data != NULL, return -ENODEV);
+ if (snd_BUG_ON(!card))
+ return -ENODEV;
+ if (snd_BUG_ON(!card->private_data))
+ return -ENODEV;
acard = card->private_data;
dev = &acard->wavefront;
@@ -520,15 +204,11 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
"> 512 bytes to FX\n");
return -EIO;
}
- page_data = kmalloc(r.data[2] * sizeof(short), GFP_KERNEL);
- if (!page_data)
- return -ENOMEM;
- if (copy_from_user (page_data,
- (unsigned char __user *) r.data[3],
- r.data[2] * sizeof(short))) {
- kfree(page_data);
- return -EFAULT;
- }
+ page_data = memdup_user((unsigned char __user *)
+ r.data[3],
+ r.data[2] * sizeof(short));
+ if (IS_ERR(page_data))
+ return PTR_ERR(page_data);
pd = page_data;
}
@@ -555,465 +235,51 @@ 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 __init
+int
snd_wavefront_fx_start (snd_wavefront_t *dev)
-
{
- unsigned int i, j;
+ unsigned int i;
+ int err;
+ const struct firmware *firmware = NULL;
- /* 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) {
+ err = -1;
+ goto out;
+ }
+
+ 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);
+ dev->fx_initialized = 1;
+ err = 0;
-
- 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);
- }
-
- 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:
+ release_firmware(firmware);
+ return err;
}
+
+MODULE_FIRMWARE("yamaha/yss225_registers.bin");
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index 15888ba2169..7dc99168229 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -47,7 +47,6 @@
*
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/time.h>
@@ -236,8 +235,10 @@ static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
- snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
- snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+ if (snd_BUG_ON(!substream || !substream->rmidi))
+ return -ENXIO;
+ if (snd_BUG_ON(!substream->rmidi->private_data))
+ return -ENXIO;
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
@@ -258,8 +259,10 @@ static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substrea
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
- snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
- snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+ if (snd_BUG_ON(!substream || !substream->rmidi))
+ return -ENXIO;
+ if (snd_BUG_ON(!substream->rmidi->private_data))
+ return -ENXIO;
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
@@ -280,8 +283,10 @@ static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substrea
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
- snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
- snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+ if (snd_BUG_ON(!substream || !substream->rmidi))
+ return -ENXIO;
+ if (snd_BUG_ON(!substream->rmidi->private_data))
+ return -ENXIO;
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
@@ -301,8 +306,10 @@ static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substre
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
- snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO);
- snd_assert(substream->rmidi->private_data != NULL, return -EIO);
+ if (snd_BUG_ON(!substream || !substream->rmidi))
+ return -ENXIO;
+ if (snd_BUG_ON(!substream->rmidi->private_data))
+ return -ENXIO;
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
@@ -474,7 +481,7 @@ snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
}
-int __init
+int
snd_wavefront_midi_start (snd_wavefront_card_t *card)
{
@@ -530,7 +537,7 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
}
/* Turn on Virtual MIDI, but first *always* turn it off,
- since otherwise consectutive reloads of the driver will
+ since otherwise consecutive reloads of the driver will
never cause the hardware to generate the initial "internal" or
"external" source bytes in the MIDI data stream. This
is pretty important, since the internal hardware generally will
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index ed81eec6e73..e5db001363e 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -20,14 +20,16 @@
*
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/wait.h>
+#include <linux/firmware.h>
#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/snd_wavefront.h>
#include <sound/initval.h>
@@ -53,9 +55,8 @@ static int debug_default = 0; /* you can set this to control debugging
/* XXX this needs to be made firmware and hardware version dependent */
-static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed
- version of the WaveFront OS
- */
+#define DEFAULT_OSPATH "wavefront.os"
+static char *ospath = DEFAULT_OSPATH; /* the firmware file name */
static int wait_usecs = 150; /* This magic number seems to give pretty optimal
throughput based on my limited experimentation.
@@ -97,7 +98,7 @@ MODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply");
module_param(sleep_tries, int, 0444);
MODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait");
module_param(ospath, charp, 0444);
-MODULE_PARM_DESC(ospath, "full pathname to processed ICS2115 OS firmware");
+MODULE_PARM_DESC(ospath, "pathname to processed ICS2115 OS firmware");
module_param(reset_time, int, 0444);
MODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect");
module_param(ramcheck_time, int, 0444);
@@ -537,7 +538,7 @@ munge_int32 (unsigned int src,
/* Note: we leave the upper bits in place */
dst++;
- };
+ }
return dst;
};
@@ -634,7 +635,7 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
wbuf[1] = i >> 7;
if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
- snd_printk("cannot identify sample "
+ snd_printk(KERN_WARNING "cannot identify sample "
"type of slot %d\n", i);
dev->sample_status[i] = WF_ST_EMPTY;
continue;
@@ -866,7 +867,7 @@ wavefront_send_sample (snd_wavefront_t *dev,
divided by 2.
*/
- u16 sample_short;
+ u16 sample_short = 0;
u32 length;
u16 __user *data_end = NULL;
unsigned int i;
@@ -1068,7 +1069,7 @@ wavefront_send_sample (snd_wavefront_t *dev,
blocksize = max_blksize;
} else {
/* round to nearest 16-byte value */
- blocksize = ((length-written+7)&~0x7);
+ blocksize = ALIGN(length - written, 8);
}
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
@@ -1195,7 +1196,7 @@ wavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header)
int num_samples;
unsigned char *msample_hdr;
- msample_hdr = kmalloc(sizeof(WF_MSAMPLE_BYTES), GFP_KERNEL);
+ msample_hdr = kmalloc(WF_MSAMPLE_BYTES, GFP_KERNEL);
if (! msample_hdr)
return -ENOMEM;
@@ -1649,9 +1650,10 @@ snd_wavefront_synth_ioctl (struct snd_hwdep *hw, struct file *file,
card = (struct snd_card *) hw->card;
- snd_assert(card != NULL, return -ENODEV);
-
- snd_assert(card->private_data != NULL, return -ENODEV);
+ if (snd_BUG_ON(!card))
+ return -ENODEV;
+ if (snd_BUG_ON(!card->private_data))
+ return -ENODEV;
acard = card->private_data;
dev = &acard->wavefront;
@@ -1664,12 +1666,11 @@ snd_wavefront_synth_ioctl (struct snd_hwdep *hw, struct file *file,
break;
case WFCTL_WFCMD:
- wc = kmalloc(sizeof(*wc), GFP_KERNEL);
- if (! wc)
- return -ENOMEM;
- if (copy_from_user (wc, argp, sizeof (*wc)))
- err = -EFAULT;
- else if (wavefront_synth_control (acard, wc) < 0)
+ wc = memdup_user(argp, sizeof(*wc));
+ if (IS_ERR(wc))
+ return PTR_ERR(wc);
+
+ if (wavefront_synth_control (acard, wc) < 0)
err = -EIO;
else if (copy_to_user (argp, wc, sizeof (*wc)))
err = -EFAULT;
@@ -1738,7 +1739,7 @@ snd_wavefront_internal_interrupt (snd_wavefront_card_t *card)
7 Unused
*/
-static int __init
+static int
snd_wavefront_interrupt_bits (int irq)
{
@@ -1766,9 +1767,9 @@ snd_wavefront_interrupt_bits (int irq)
return bits;
}
-static void __init
+static void
wavefront_should_cause_interrupt (snd_wavefront_t *dev,
- int val, int port, int timeout)
+ int val, int port, unsigned long timeout)
{
wait_queue_t wait;
@@ -1779,15 +1780,13 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev,
dev->irq_ok = 0;
outb (val,port);
spin_unlock_irq(&dev->irq_lock);
- while (1) {
- if ((timeout = schedule_timeout_interruptible(timeout)) == 0)
- return;
- if (dev->irq_ok)
- return;
+ while (!dev->irq_ok && time_before(jiffies, timeout)) {
+ schedule_timeout_uninterruptible(1);
+ barrier();
}
}
-static int __init
+static int
wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
{
@@ -1938,116 +1937,80 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
return (1);
}
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/syscalls.h>
-#include <asm/uaccess.h>
-
-
-static int __init
+static int
wavefront_download_firmware (snd_wavefront_t *dev, char *path)
{
- unsigned char section[WF_SECTION_MAX];
- signed char section_length; /* yes, just a char; max value is WF_SECTION_MAX */
+ const unsigned char *buf;
+ int len, err;
int section_cnt_downloaded = 0;
- int fd;
- int c;
- int i;
- mm_segment_t fs;
-
- /* This tries to be a bit cleverer than the stuff Alan Cox did for
- the generic sound firmware, in that it actually knows
- something about the structure of the Motorola firmware. In
- particular, it uses a version that has been stripped of the
- 20K of useless header information, and had section lengths
- added, making it possible to load the entire OS without any
- [kv]malloc() activity, since the longest entity we ever read is
- 42 bytes (well, WF_SECTION_MAX) long.
- */
+ const struct firmware *firmware;
- fs = get_fs();
- set_fs (get_ds());
-
- if ((fd = sys_open ((char __user *) path, 0, 0)) < 0) {
- snd_printk ("Unable to load \"%s\".\n",
- path);
+ err = request_firmware(&firmware, path, dev->card->dev);
+ if (err < 0) {
+ snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path);
return 1;
}
- while (1) {
- int x;
-
- if ((x = sys_read (fd, (char __user *) &section_length, sizeof (section_length))) !=
- sizeof (section_length)) {
- snd_printk ("firmware read error.\n");
- goto failure;
- }
-
- if (section_length == 0) {
+ len = 0;
+ buf = firmware->data;
+ for (;;) {
+ int section_length = *(signed char *)buf;
+ if (section_length == 0)
break;
- }
-
if (section_length < 0 || section_length > WF_SECTION_MAX) {
- snd_printk ("invalid firmware section length %d\n",
- section_length);
+ snd_printk(KERN_ERR
+ "invalid firmware section length %d\n",
+ section_length);
goto failure;
}
+ buf++;
+ len++;
- if (sys_read (fd, (char __user *) section, section_length) != section_length) {
- snd_printk ("firmware section "
- "read error.\n");
+ if (firmware->size < len + section_length) {
+ snd_printk(KERN_ERR "firmware section read error.\n");
goto failure;
}
/* Send command */
-
- if (wavefront_write (dev, WFC_DOWNLOAD_OS)) {
+ if (wavefront_write(dev, WFC_DOWNLOAD_OS))
goto failure;
- }
- for (i = 0; i < section_length; i++) {
- if (wavefront_write (dev, section[i])) {
+ for (; section_length; section_length--) {
+ if (wavefront_write(dev, *buf))
goto failure;
- }
+ buf++;
+ len++;
}
/* get ACK */
-
- if (wavefront_wait (dev, STAT_CAN_READ)) {
-
- if ((c = inb (dev->data_port)) != WF_ACK) {
-
- snd_printk ("download "
- "of section #%d not "
- "acknowledged, ack = 0x%x\n",
- section_cnt_downloaded + 1, c);
- goto failure;
-
- }
-
- } else {
- snd_printk ("time out for firmware ACK.\n");
+ if (!wavefront_wait(dev, STAT_CAN_READ)) {
+ snd_printk(KERN_ERR "time out for firmware ACK.\n");
+ goto failure;
+ }
+ err = inb(dev->data_port);
+ if (err != WF_ACK) {
+ snd_printk(KERN_ERR
+ "download of section #%d not "
+ "acknowledged, ack = 0x%x\n",
+ section_cnt_downloaded + 1, err);
goto failure;
}
+ section_cnt_downloaded++;
}
- sys_close (fd);
- set_fs (fs);
+ release_firmware(firmware);
return 0;
failure:
- sys_close (fd);
- set_fs (fs);
- snd_printk ("firmware download failed!!!\n");
+ release_firmware(firmware);
+ snd_printk(KERN_ERR "firmware download failed!!!\n");
return 1;
}
-static int __init
+static int
wavefront_do_reset (snd_wavefront_t *dev)
{
@@ -2136,7 +2099,7 @@ wavefront_do_reset (snd_wavefront_t *dev)
return 1;
}
-int __init
+int
snd_wavefront_start (snd_wavefront_t *dev)
{
@@ -2178,7 +2141,7 @@ snd_wavefront_start (snd_wavefront_t *dev)
return (0);
}
-int __init
+int
snd_wavefront_detect (snd_wavefront_card_t *card)
{
@@ -2232,3 +2195,5 @@ snd_wavefront_detect (snd_wavefront_card_t *card)
return 0;
}
+
+MODULE_FIRMWARE(DEFAULT_OSPATH);
diff --git a/sound/isa/wss/Makefile b/sound/isa/wss/Makefile
new file mode 100644
index 00000000000..454fee769a3
--- /dev/null
+++ b/sound/isa/wss/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2008 by Jaroslav Kysela <perex@perex.cz>
+#
+
+snd-wss-lib-objs := wss_lib.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_WSS_LIB) += snd-wss-lib.o
+
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
new file mode 100644
index 00000000000..360b08b03e1
--- /dev/null
+++ b/sound/isa/wss/wss_lib.c
@@ -0,0 +1,2307 @@
+/*
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips
+ *
+ * Bugs:
+ * - sometimes record brokes playback with WSS portion of
+ * Yamaha OPL3-SA3 chip
+ * - CS4231 (GUS MAX) - still trouble with occasional noises
+ * - broken initialization?
+ *
+ * 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 <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
+MODULE_LICENSE("GPL");
+
+#if 0
+#define SNDRV_DEBUG_MCE
+#endif
+
+/*
+ * Some variables
+ */
+
+static unsigned char freq_bits[14] = {
+ /* 5510 */ 0x00 | CS4231_XTAL2,
+ /* 6620 */ 0x0E | CS4231_XTAL2,
+ /* 8000 */ 0x00 | CS4231_XTAL1,
+ /* 9600 */ 0x0E | CS4231_XTAL1,
+ /* 11025 */ 0x02 | CS4231_XTAL2,
+ /* 16000 */ 0x02 | CS4231_XTAL1,
+ /* 18900 */ 0x04 | CS4231_XTAL2,
+ /* 22050 */ 0x06 | CS4231_XTAL2,
+ /* 27042 */ 0x04 | CS4231_XTAL1,
+ /* 32000 */ 0x06 | CS4231_XTAL1,
+ /* 33075 */ 0x0C | CS4231_XTAL2,
+ /* 37800 */ 0x08 | CS4231_XTAL2,
+ /* 44100 */ 0x0A | CS4231_XTAL2,
+ /* 48000 */ 0x0C | CS4231_XTAL1
+};
+
+static unsigned int rates[14] = {
+ 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
+ 27042, 32000, 33075, 37800, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static int snd_wss_xrate(struct snd_pcm_runtime *runtime)
+{
+ return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &hw_constraints_rates);
+}
+
+static unsigned char snd_wss_original_image[32] =
+{
+ 0x00, /* 00/00 - lic */
+ 0x00, /* 01/01 - ric */
+ 0x9f, /* 02/02 - la1ic */
+ 0x9f, /* 03/03 - ra1ic */
+ 0x9f, /* 04/04 - la2ic */
+ 0x9f, /* 05/05 - ra2ic */
+ 0xbf, /* 06/06 - loc */
+ 0xbf, /* 07/07 - roc */
+ 0x20, /* 08/08 - pdfr */
+ CS4231_AUTOCALIB, /* 09/09 - ic */
+ 0x00, /* 0a/10 - pc */
+ 0x00, /* 0b/11 - ti */
+ CS4231_MODE2, /* 0c/12 - mi */
+ 0xfc, /* 0d/13 - lbc */
+ 0x00, /* 0e/14 - pbru */
+ 0x00, /* 0f/15 - pbrl */
+ 0x80, /* 10/16 - afei */
+ 0x01, /* 11/17 - afeii */
+ 0x9f, /* 12/18 - llic */
+ 0x9f, /* 13/19 - rlic */
+ 0x00, /* 14/20 - tlb */
+ 0x00, /* 15/21 - thb */
+ 0x00, /* 16/22 - la3mic/reserved */
+ 0x00, /* 17/23 - ra3mic/reserved */
+ 0x00, /* 18/24 - afs */
+ 0x00, /* 19/25 - lamoc/version */
+ 0xcf, /* 1a/26 - mioc */
+ 0x00, /* 1b/27 - ramoc/reserved */
+ 0x20, /* 1c/28 - cdfr */
+ 0x00, /* 1d/29 - res4 */
+ 0x00, /* 1e/30 - cbru */
+ 0x00, /* 1f/31 - cbrl */
+};
+
+static unsigned char snd_opti93x_original_image[32] =
+{
+ 0x00, /* 00/00 - l_mixout_outctrl */
+ 0x00, /* 01/01 - r_mixout_outctrl */
+ 0x88, /* 02/02 - l_cd_inctrl */
+ 0x88, /* 03/03 - r_cd_inctrl */
+ 0x88, /* 04/04 - l_a1/fm_inctrl */
+ 0x88, /* 05/05 - r_a1/fm_inctrl */
+ 0x80, /* 06/06 - l_dac_inctrl */
+ 0x80, /* 07/07 - r_dac_inctrl */
+ 0x00, /* 08/08 - ply_dataform_reg */
+ 0x00, /* 09/09 - if_conf */
+ 0x00, /* 0a/10 - pin_ctrl */
+ 0x00, /* 0b/11 - err_init_reg */
+ 0x0a, /* 0c/12 - id_reg */
+ 0x00, /* 0d/13 - reserved */
+ 0x00, /* 0e/14 - ply_upcount_reg */
+ 0x00, /* 0f/15 - ply_lowcount_reg */
+ 0x88, /* 10/16 - reserved/l_a1_inctrl */
+ 0x88, /* 11/17 - reserved/r_a1_inctrl */
+ 0x88, /* 12/18 - l_line_inctrl */
+ 0x88, /* 13/19 - r_line_inctrl */
+ 0x88, /* 14/20 - l_mic_inctrl */
+ 0x88, /* 15/21 - r_mic_inctrl */
+ 0x80, /* 16/22 - l_out_outctrl */
+ 0x80, /* 17/23 - r_out_outctrl */
+ 0x00, /* 18/24 - reserved */
+ 0x00, /* 19/25 - reserved */
+ 0x00, /* 1a/26 - reserved */
+ 0x00, /* 1b/27 - reserved */
+ 0x00, /* 1c/28 - cap_dataform_reg */
+ 0x00, /* 1d/29 - reserved */
+ 0x00, /* 1e/30 - cap_upcount_reg */
+ 0x00 /* 1f/31 - cap_lowcount_reg */
+};
+
+/*
+ * Basic I/O functions
+ */
+
+static inline void wss_outb(struct snd_wss *chip, u8 offset, u8 val)
+{
+ outb(val, chip->port + offset);
+}
+
+static inline u8 wss_inb(struct snd_wss *chip, u8 offset)
+{
+ return inb(chip->port + offset);
+}
+
+static void snd_wss_wait(struct snd_wss *chip)
+{
+ int timeout;
+
+ for (timeout = 250;
+ timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+ timeout--)
+ udelay(100);
+}
+
+static void snd_wss_dout(struct snd_wss *chip, unsigned char reg,
+ unsigned char value)
+{
+ int timeout;
+
+ for (timeout = 250;
+ timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+ timeout--)
+ udelay(10);
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+ wss_outb(chip, CS4231P(REG), value);
+ mb();
+}
+
+void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value)
+{
+ snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+ if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+ snd_printk(KERN_DEBUG "out: auto calibration time out "
+ "- reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+ wss_outb(chip, CS4231P(REG), value);
+ chip->image[reg] = value;
+ mb();
+ snd_printdd("codec out - reg 0x%x = 0x%x\n",
+ chip->mce_bit | reg, value);
+}
+EXPORT_SYMBOL(snd_wss_out);
+
+unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg)
+{
+ snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+ if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+ snd_printk(KERN_DEBUG "in: auto calibration time out "
+ "- reg = 0x%x\n", reg);
+#endif
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+ mb();
+ return wss_inb(chip, CS4231P(REG));
+}
+EXPORT_SYMBOL(snd_wss_in);
+
+void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg,
+ unsigned char val)
+{
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+ wss_outb(chip, CS4231P(REG),
+ reg | (chip->image[CS4236_EXT_REG] & 0x01));
+ wss_outb(chip, CS4231P(REG), val);
+ chip->eimage[CS4236_REG(reg)] = val;
+#if 0
+ printk(KERN_DEBUG "ext out : reg = 0x%x, val = 0x%x\n", reg, val);
+#endif
+}
+EXPORT_SYMBOL(snd_cs4236_ext_out);
+
+unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg)
+{
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+ wss_outb(chip, CS4231P(REG),
+ reg | (chip->image[CS4236_EXT_REG] & 0x01));
+#if 1
+ return wss_inb(chip, CS4231P(REG));
+#else
+ {
+ unsigned char res;
+ res = wss_inb(chip, CS4231P(REG));
+ printk(KERN_DEBUG "ext in : reg = 0x%x, val = 0x%x\n",
+ reg, res);
+ return res;
+ }
+#endif
+}
+EXPORT_SYMBOL(snd_cs4236_ext_in);
+
+#if 0
+
+static void snd_wss_debug(struct snd_wss *chip)
+{
+ printk(KERN_DEBUG
+ "CS4231 REGS: INDEX = 0x%02x "
+ " STATUS = 0x%02x\n",
+ wss_inb(chip, CS4231P(REGSEL)),
+ wss_inb(chip, CS4231P(STATUS)));
+ printk(KERN_DEBUG
+ " 0x00: left input = 0x%02x "
+ " 0x10: alt 1 (CFIG 2) = 0x%02x\n",
+ snd_wss_in(chip, 0x00),
+ snd_wss_in(chip, 0x10));
+ printk(KERN_DEBUG
+ " 0x01: right input = 0x%02x "
+ " 0x11: alt 2 (CFIG 3) = 0x%02x\n",
+ snd_wss_in(chip, 0x01),
+ snd_wss_in(chip, 0x11));
+ printk(KERN_DEBUG
+ " 0x02: GF1 left input = 0x%02x "
+ " 0x12: left line in = 0x%02x\n",
+ snd_wss_in(chip, 0x02),
+ snd_wss_in(chip, 0x12));
+ printk(KERN_DEBUG
+ " 0x03: GF1 right input = 0x%02x "
+ " 0x13: right line in = 0x%02x\n",
+ snd_wss_in(chip, 0x03),
+ snd_wss_in(chip, 0x13));
+ printk(KERN_DEBUG
+ " 0x04: CD left input = 0x%02x "
+ " 0x14: timer low = 0x%02x\n",
+ snd_wss_in(chip, 0x04),
+ snd_wss_in(chip, 0x14));
+ printk(KERN_DEBUG
+ " 0x05: CD right input = 0x%02x "
+ " 0x15: timer high = 0x%02x\n",
+ snd_wss_in(chip, 0x05),
+ snd_wss_in(chip, 0x15));
+ printk(KERN_DEBUG
+ " 0x06: left output = 0x%02x "
+ " 0x16: left MIC (PnP) = 0x%02x\n",
+ snd_wss_in(chip, 0x06),
+ snd_wss_in(chip, 0x16));
+ printk(KERN_DEBUG
+ " 0x07: right output = 0x%02x "
+ " 0x17: right MIC (PnP) = 0x%02x\n",
+ snd_wss_in(chip, 0x07),
+ snd_wss_in(chip, 0x17));
+ printk(KERN_DEBUG
+ " 0x08: playback format = 0x%02x "
+ " 0x18: IRQ status = 0x%02x\n",
+ snd_wss_in(chip, 0x08),
+ snd_wss_in(chip, 0x18));
+ printk(KERN_DEBUG
+ " 0x09: iface (CFIG 1) = 0x%02x "
+ " 0x19: left line out = 0x%02x\n",
+ snd_wss_in(chip, 0x09),
+ snd_wss_in(chip, 0x19));
+ printk(KERN_DEBUG
+ " 0x0a: pin control = 0x%02x "
+ " 0x1a: mono control = 0x%02x\n",
+ snd_wss_in(chip, 0x0a),
+ snd_wss_in(chip, 0x1a));
+ printk(KERN_DEBUG
+ " 0x0b: init & status = 0x%02x "
+ " 0x1b: right line out = 0x%02x\n",
+ snd_wss_in(chip, 0x0b),
+ snd_wss_in(chip, 0x1b));
+ printk(KERN_DEBUG
+ " 0x0c: revision & mode = 0x%02x "
+ " 0x1c: record format = 0x%02x\n",
+ snd_wss_in(chip, 0x0c),
+ snd_wss_in(chip, 0x1c));
+ printk(KERN_DEBUG
+ " 0x0d: loopback = 0x%02x "
+ " 0x1d: var freq (PnP) = 0x%02x\n",
+ snd_wss_in(chip, 0x0d),
+ snd_wss_in(chip, 0x1d));
+ printk(KERN_DEBUG
+ " 0x0e: ply upr count = 0x%02x "
+ " 0x1e: ply lwr count = 0x%02x\n",
+ snd_wss_in(chip, 0x0e),
+ snd_wss_in(chip, 0x1e));
+ printk(KERN_DEBUG
+ " 0x0f: rec upr count = 0x%02x "
+ " 0x1f: rec lwr count = 0x%02x\n",
+ snd_wss_in(chip, 0x0f),
+ snd_wss_in(chip, 0x1f));
+}
+
+#endif
+
+/*
+ * CS4231 detection / MCE routines
+ */
+
+static void snd_wss_busy_wait(struct snd_wss *chip)
+{
+ int timeout;
+
+ /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
+ for (timeout = 5; timeout > 0; timeout--)
+ wss_inb(chip, CS4231P(REGSEL));
+ /* end of cleanup sequence */
+ for (timeout = 25000;
+ timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
+ timeout--)
+ udelay(10);
+}
+
+void snd_wss_mce_up(struct snd_wss *chip)
+{
+ unsigned long flags;
+ int timeout;
+
+ snd_wss_wait(chip);
+#ifdef CONFIG_SND_DEBUG
+ if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+ snd_printk(KERN_DEBUG
+ "mce_up - auto calibration time out (0)\n");
+#endif
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->mce_bit |= CS4231_MCE;
+ timeout = wss_inb(chip, CS4231P(REGSEL));
+ if (timeout == 0x80)
+ snd_printk(KERN_DEBUG "mce_up [0x%lx]: "
+ "serious init problem - codec still busy\n",
+ chip->port);
+ if (!(timeout & CS4231_MCE))
+ wss_outb(chip, CS4231P(REGSEL),
+ chip->mce_bit | (timeout & 0x1f));
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
+EXPORT_SYMBOL(snd_wss_mce_up);
+
+void snd_wss_mce_down(struct snd_wss *chip)
+{
+ unsigned long flags;
+ unsigned long end_time;
+ int timeout;
+ int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848;
+
+ snd_wss_busy_wait(chip);
+
+#ifdef CONFIG_SND_DEBUG
+ if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+ snd_printk(KERN_DEBUG "mce_down [0x%lx] - "
+ "auto calibration time out (0)\n",
+ (long)CS4231P(REGSEL));
+#endif
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->mce_bit &= ~CS4231_MCE;
+ timeout = wss_inb(chip, CS4231P(REGSEL));
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (timeout == 0x80)
+ snd_printk(KERN_DEBUG "mce_down [0x%lx]: "
+ "serious init problem - codec still busy\n",
+ chip->port);
+ if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
+ return;
+
+ /*
+ * Wait for (possible -- during init auto-calibration may not be set)
+ * calibration process to start. Needs up to 5 sample periods on AD1848
+ * which at the slowest possible rate of 5.5125 kHz means 907 us.
+ */
+ msleep(1);
+
+ snd_printdd("(1) jiffies = %lu\n", jiffies);
+
+ /* check condition up to 250 ms */
+ end_time = jiffies + msecs_to_jiffies(250);
+ while (snd_wss_in(chip, CS4231_TEST_INIT) &
+ CS4231_CALIB_IN_PROGRESS) {
+
+ if (time_after(jiffies, end_time)) {
+ snd_printk(KERN_ERR "mce_down - "
+ "auto calibration time out (2)\n");
+ return;
+ }
+ msleep(1);
+ }
+
+ snd_printdd("(2) jiffies = %lu\n", jiffies);
+
+ /* check condition up to 100 ms */
+ end_time = jiffies + msecs_to_jiffies(100);
+ while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
+ if (time_after(jiffies, end_time)) {
+ snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
+ return;
+ }
+ msleep(1);
+ }
+
+ snd_printdd("(3) jiffies = %lu\n", jiffies);
+ snd_printd("mce_down - exit = 0x%x\n", wss_inb(chip, CS4231P(REGSEL)));
+}
+EXPORT_SYMBOL(snd_wss_mce_down);
+
+static unsigned int snd_wss_get_count(unsigned char format, unsigned int size)
+{
+ switch (format & 0xe0) {
+ case CS4231_LINEAR_16:
+ case CS4231_LINEAR_16_BIG:
+ size >>= 1;
+ break;
+ case CS4231_ADPCM_16:
+ return size >> 2;
+ }
+ if (format & CS4231_STEREO)
+ size >>= 1;
+ return size;
+}
+
+static int snd_wss_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ int result = 0;
+ unsigned int what;
+ struct snd_pcm_substream *s;
+ int do_start;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ do_start = 1; break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ do_start = 0; break;
+ default:
+ return -EINVAL;
+ }
+
+ what = 0;
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s == chip->playback_substream) {
+ what |= CS4231_PLAYBACK_ENABLE;
+ snd_pcm_trigger_done(s, substream);
+ } else if (s == chip->capture_substream) {
+ what |= CS4231_RECORD_ENABLE;
+ snd_pcm_trigger_done(s, substream);
+ }
+ }
+ spin_lock(&chip->reg_lock);
+ if (do_start) {
+ chip->image[CS4231_IFACE_CTRL] |= what;
+ if (chip->trigger)
+ chip->trigger(chip, what, 1);
+ } else {
+ chip->image[CS4231_IFACE_CTRL] &= ~what;
+ if (chip->trigger)
+ chip->trigger(chip, what, 0);
+ }
+ snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+ spin_unlock(&chip->reg_lock);
+#if 0
+ snd_wss_debug(chip);
+#endif
+ return result;
+}
+
+/*
+ * CODEC I/O
+ */
+
+static unsigned char snd_wss_get_rate(unsigned int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rates); i++)
+ if (rate == rates[i])
+ return freq_bits[i];
+ // snd_BUG();
+ return freq_bits[ARRAY_SIZE(rates) - 1];
+}
+
+static unsigned char snd_wss_get_format(struct snd_wss *chip,
+ int format,
+ int channels)
+{
+ unsigned char rformat;
+
+ rformat = CS4231_LINEAR_8;
+ switch (format) {
+ case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break;
+ case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break;
+ case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break;
+ case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break;
+ case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break;
+ }
+ if (channels > 1)
+ rformat |= CS4231_STEREO;
+#if 0
+ snd_printk(KERN_DEBUG "get_format: 0x%x (mode=0x%x)\n", format, mode);
+#endif
+ return rformat;
+}
+
+static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
+{
+ unsigned long flags;
+
+ mute = mute ? 0x80 : 0;
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if (chip->calibrate_mute == mute) {
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return;
+ }
+ if (!mute) {
+ snd_wss_dout(chip, CS4231_LEFT_INPUT,
+ chip->image[CS4231_LEFT_INPUT]);
+ snd_wss_dout(chip, CS4231_RIGHT_INPUT,
+ chip->image[CS4231_RIGHT_INPUT]);
+ snd_wss_dout(chip, CS4231_LOOPBACK,
+ chip->image[CS4231_LOOPBACK]);
+ } else {
+ snd_wss_dout(chip, CS4231_LEFT_INPUT,
+ 0);
+ snd_wss_dout(chip, CS4231_RIGHT_INPUT,
+ 0);
+ snd_wss_dout(chip, CS4231_LOOPBACK,
+ 0xfd);
+ }
+
+ snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
+ mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
+ snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
+ mute | chip->image[CS4231_AUX1_RIGHT_INPUT]);
+ snd_wss_dout(chip, CS4231_AUX2_LEFT_INPUT,
+ mute | chip->image[CS4231_AUX2_LEFT_INPUT]);
+ snd_wss_dout(chip, CS4231_AUX2_RIGHT_INPUT,
+ mute | chip->image[CS4231_AUX2_RIGHT_INPUT]);
+ snd_wss_dout(chip, CS4231_LEFT_OUTPUT,
+ mute | chip->image[CS4231_LEFT_OUTPUT]);
+ snd_wss_dout(chip, CS4231_RIGHT_OUTPUT,
+ mute | chip->image[CS4231_RIGHT_OUTPUT]);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+ snd_wss_dout(chip, CS4231_LEFT_LINE_IN,
+ mute | chip->image[CS4231_LEFT_LINE_IN]);
+ snd_wss_dout(chip, CS4231_RIGHT_LINE_IN,
+ mute | chip->image[CS4231_RIGHT_LINE_IN]);
+ snd_wss_dout(chip, CS4231_MONO_CTRL,
+ mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
+ }
+ if (chip->hardware == WSS_HW_INTERWAVE) {
+ snd_wss_dout(chip, CS4231_LEFT_MIC_INPUT,
+ mute | chip->image[CS4231_LEFT_MIC_INPUT]);
+ snd_wss_dout(chip, CS4231_RIGHT_MIC_INPUT,
+ mute | chip->image[CS4231_RIGHT_MIC_INPUT]);
+ snd_wss_dout(chip, CS4231_LINE_LEFT_OUTPUT,
+ mute | chip->image[CS4231_LINE_LEFT_OUTPUT]);
+ snd_wss_dout(chip, CS4231_LINE_RIGHT_OUTPUT,
+ mute | chip->image[CS4231_LINE_RIGHT_OUTPUT]);
+ }
+ chip->calibrate_mute = mute;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
+
+static void snd_wss_playback_format(struct snd_wss *chip,
+ struct snd_pcm_hw_params *params,
+ unsigned char pdfr)
+{
+ unsigned long flags;
+ int full_calib = 1;
+
+ mutex_lock(&chip->mce_mutex);
+ if (chip->hardware == WSS_HW_CS4231A ||
+ (chip->hardware & WSS_HW_CS4232_MASK)) {
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) { /* rate is same? */
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] | 0x10);
+ chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+ chip->image[CS4231_PLAYBK_FORMAT]);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] &= ~0x10);
+ udelay(100); /* Fixes audible clicks at least on GUS MAX */
+ full_calib = 0;
+ }
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ } else if (chip->hardware == WSS_HW_AD1845) {
+ unsigned rate = params_rate(params);
+
+ /*
+ * Program the AD1845 correctly for the playback stream.
+ * Note that we do NOT need to toggle the MCE bit because
+ * the PLAYBACK_ENABLE bit of the Interface Configuration
+ * register is set.
+ *
+ * NOTE: We seem to need to write to the MSB before the LSB
+ * to get the correct sample frequency.
+ */
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (pdfr & 0xf0));
+ snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+ snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+ full_calib = 0;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ }
+ if (full_calib) {
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) {
+ if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)
+ pdfr = (pdfr & 0xf0) |
+ (chip->image[CS4231_REC_FORMAT] & 0x0f);
+ } else {
+ chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+ }
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (chip->hardware == WSS_HW_OPL3SA2)
+ udelay(100); /* this seems to help */
+ snd_wss_mce_down(chip);
+ }
+ mutex_unlock(&chip->mce_mutex);
+}
+
+static void snd_wss_capture_format(struct snd_wss *chip,
+ struct snd_pcm_hw_params *params,
+ unsigned char cdfr)
+{
+ unsigned long flags;
+ int full_calib = 1;
+
+ mutex_lock(&chip->mce_mutex);
+ if (chip->hardware == WSS_HW_CS4231A ||
+ (chip->hardware & WSS_HW_CS4232_MASK)) {
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) || /* rate is same? */
+ (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] | 0x20);
+ snd_wss_out(chip, CS4231_REC_FORMAT,
+ chip->image[CS4231_REC_FORMAT] = cdfr);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
+ full_calib = 0;
+ }
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ } else if (chip->hardware == WSS_HW_AD1845) {
+ unsigned rate = params_rate(params);
+
+ /*
+ * Program the AD1845 correctly for the capture stream.
+ * Note that we do NOT need to toggle the MCE bit because
+ * the PLAYBACK_ENABLE bit of the Interface Configuration
+ * register is set.
+ *
+ * NOTE: We seem to need to write to the MSB before the LSB
+ * to get the correct sample frequency.
+ */
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_REC_FORMAT, (cdfr & 0xf0));
+ snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+ snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+ full_calib = 0;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ }
+ if (full_calib) {
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if (chip->hardware != WSS_HW_INTERWAVE &&
+ !(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
+ if (chip->single_dma)
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr);
+ else
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+ (chip->image[CS4231_PLAYBK_FORMAT] & 0xf0) |
+ (cdfr & 0x0f));
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ }
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr);
+ else
+ snd_wss_out(chip, CS4231_REC_FORMAT, cdfr);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
+ }
+ mutex_unlock(&chip->mce_mutex);
+}
+
+/*
+ * Timer interface
+ */
+
+static unsigned long snd_wss_timer_resolution(struct snd_timer *timer)
+{
+ struct snd_wss *chip = snd_timer_chip(timer);
+ if (chip->hardware & WSS_HW_CS4236B_MASK)
+ return 14467;
+ else
+ return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
+}
+
+static int snd_wss_timer_start(struct snd_timer *timer)
+{
+ unsigned long flags;
+ unsigned int ticks;
+ struct snd_wss *chip = snd_timer_chip(timer);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ ticks = timer->sticks;
+ if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
+ (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
+ (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
+ chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8);
+ snd_wss_out(chip, CS4231_TIMER_HIGH,
+ chip->image[CS4231_TIMER_HIGH]);
+ chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks;
+ snd_wss_out(chip, CS4231_TIMER_LOW,
+ chip->image[CS4231_TIMER_LOW]);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1] |
+ CS4231_TIMER_ENABLE);
+ }
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return 0;
+}
+
+static int snd_wss_timer_stop(struct snd_timer *timer)
+{
+ unsigned long flags;
+ struct snd_wss *chip = snd_timer_chip(timer);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE;
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1,
+ chip->image[CS4231_ALT_FEATURE_1]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return 0;
+}
+
+static void snd_wss_init(struct snd_wss *chip)
+{
+ unsigned long flags;
+
+ snd_wss_calibrate_mute(chip, 1);
+ snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+ snd_printk(KERN_DEBUG "init: (1)\n");
+#endif
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
+ CS4231_PLAYBACK_PIO |
+ CS4231_RECORD_ENABLE |
+ CS4231_RECORD_PIO |
+ CS4231_CALIB_MODE);
+ chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
+ snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+ snd_printk(KERN_DEBUG "init: (2)\n");
+#endif
+
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB;
+ snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+ snd_wss_out(chip,
+ CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+ snd_printk(KERN_DEBUG "init: (3) - afei = 0x%x\n",
+ chip->image[CS4231_ALT_FEATURE_1]);
+#endif
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_ALT_FEATURE_2,
+ chip->image[CS4231_ALT_FEATURE_2]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+ chip->image[CS4231_PLAYBK_FORMAT]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+ snd_printk(KERN_DEBUG "init: (4)\n");
+#endif
+
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ snd_wss_out(chip, CS4231_REC_FORMAT,
+ chip->image[CS4231_REC_FORMAT]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
+ snd_wss_calibrate_mute(chip, 0);
+
+#ifdef SNDRV_DEBUG_MCE
+ snd_printk(KERN_DEBUG "init: (5)\n");
+#endif
+}
+
+static int snd_wss_open(struct snd_wss *chip, unsigned int mode)
+{
+ unsigned long flags;
+
+ mutex_lock(&chip->open_mutex);
+ if ((chip->mode & mode) ||
+ ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) {
+ mutex_unlock(&chip->open_mutex);
+ return -EAGAIN;
+ }
+ if (chip->mode & WSS_MODE_OPEN) {
+ chip->mode |= mode;
+ mutex_unlock(&chip->open_mutex);
+ return 0;
+ }
+ /* ok. now enable and ack CODEC IRQ */
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+ snd_wss_out(chip, CS4231_IRQ_STATUS,
+ CS4231_PLAYBACK_IRQ |
+ CS4231_RECORD_IRQ |
+ CS4231_TIMER_IRQ);
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ }
+ wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
+ wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
+ chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
+ snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
+ snd_wss_out(chip, CS4231_IRQ_STATUS,
+ CS4231_PLAYBACK_IRQ |
+ CS4231_RECORD_IRQ |
+ CS4231_TIMER_IRQ);
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ }
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+ chip->mode = mode;
+ mutex_unlock(&chip->open_mutex);
+ return 0;
+}
+
+static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
+{
+ unsigned long flags;
+
+ mutex_lock(&chip->open_mutex);
+ chip->mode &= ~mode;
+ if (chip->mode & WSS_MODE_OPEN) {
+ mutex_unlock(&chip->open_mutex);
+ return;
+ }
+ /* disable IRQ */
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
+ wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
+ chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
+ snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
+
+ /* now disable record & playback */
+
+ if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+ CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+ CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
+ snd_wss_out(chip, CS4231_IFACE_CTRL,
+ chip->image[CS4231_IFACE_CTRL]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_down(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ }
+
+ /* clear IRQ again */
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
+ wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
+ wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+ chip->mode = 0;
+ mutex_unlock(&chip->open_mutex);
+}
+
+/*
+ * timer open/close
+ */
+
+static int snd_wss_timer_open(struct snd_timer *timer)
+{
+ struct snd_wss *chip = snd_timer_chip(timer);
+ snd_wss_open(chip, WSS_MODE_TIMER);
+ return 0;
+}
+
+static int snd_wss_timer_close(struct snd_timer *timer)
+{
+ struct snd_wss *chip = snd_timer_chip(timer);
+ snd_wss_close(chip, WSS_MODE_TIMER);
+ return 0;
+}
+
+static struct snd_timer_hardware snd_wss_timer_table =
+{
+ .flags = SNDRV_TIMER_HW_AUTO,
+ .resolution = 9945,
+ .ticks = 65535,
+ .open = snd_wss_timer_open,
+ .close = snd_wss_timer_close,
+ .c_resolution = snd_wss_timer_resolution,
+ .start = snd_wss_timer_start,
+ .stop = snd_wss_timer_stop,
+};
+
+/*
+ * ok.. exported functions..
+ */
+
+static int snd_wss_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ unsigned char new_pdfr;
+ int err;
+
+ if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+ return err;
+ new_pdfr = snd_wss_get_format(chip, params_format(hw_params),
+ params_channels(hw_params)) |
+ snd_wss_get_rate(params_rate(hw_params));
+ chip->set_playback_format(chip, hw_params, new_pdfr);
+ return 0;
+}
+
+static int snd_wss_playback_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_wss_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long flags;
+ unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int count = snd_pcm_lib_period_bytes(substream);
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->p_dma_size = size;
+ chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
+ snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
+ count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
+ snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
+ snd_wss_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+#if 0
+ snd_wss_debug(chip);
+#endif
+ return 0;
+}
+
+static int snd_wss_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ unsigned char new_cdfr;
+ int err;
+
+ if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+ return err;
+ new_cdfr = snd_wss_get_format(chip, params_format(hw_params),
+ params_channels(hw_params)) |
+ snd_wss_get_rate(params_rate(hw_params));
+ chip->set_capture_format(chip, hw_params, new_cdfr);
+ return 0;
+}
+
+static int snd_wss_capture_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_wss_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long flags;
+ unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int count = snd_pcm_lib_period_bytes(substream);
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->c_dma_size = size;
+ chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
+ snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT],
+ count);
+ else
+ count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT],
+ count);
+ count--;
+ if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) {
+ snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
+ snd_wss_out(chip, CS4231_PLY_UPR_CNT,
+ (unsigned char) (count >> 8));
+ } else {
+ snd_wss_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count);
+ snd_wss_out(chip, CS4231_REC_UPR_CNT,
+ (unsigned char) (count >> 8));
+ }
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return 0;
+}
+
+void snd_wss_overrange(struct snd_wss *chip)
+{
+ unsigned long flags;
+ unsigned char res;
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ res = snd_wss_in(chip, CS4231_TEST_INIT);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */
+ chip->capture_substream->runtime->overrange++;
+}
+EXPORT_SYMBOL(snd_wss_overrange);
+
+irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
+{
+ struct snd_wss *chip = dev_id;
+ unsigned char status;
+
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ /* pretend it was the only possible irq for AD1848 */
+ status = CS4231_PLAYBACK_IRQ;
+ else
+ status = snd_wss_in(chip, CS4231_IRQ_STATUS);
+ if (status & CS4231_TIMER_IRQ) {
+ if (chip->timer)
+ snd_timer_interrupt(chip->timer, chip->timer->sticks);
+ }
+ if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) {
+ if (status & CS4231_PLAYBACK_IRQ) {
+ if (chip->mode & WSS_MODE_PLAY) {
+ if (chip->playback_substream)
+ snd_pcm_period_elapsed(chip->playback_substream);
+ }
+ if (chip->mode & WSS_MODE_RECORD) {
+ if (chip->capture_substream) {
+ snd_wss_overrange(chip);
+ snd_pcm_period_elapsed(chip->capture_substream);
+ }
+ }
+ }
+ } else {
+ if (status & CS4231_PLAYBACK_IRQ) {
+ if (chip->playback_substream)
+ snd_pcm_period_elapsed(chip->playback_substream);
+ }
+ if (status & CS4231_RECORD_IRQ) {
+ if (chip->capture_substream) {
+ snd_wss_overrange(chip);
+ snd_pcm_period_elapsed(chip->capture_substream);
+ }
+ }
+ }
+
+ spin_lock(&chip->reg_lock);
+ status = ~CS4231_ALL_IRQS | ~status;
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ wss_outb(chip, CS4231P(STATUS), 0);
+ else
+ snd_wss_out(chip, CS4231_IRQ_STATUS, status);
+ spin_unlock(&chip->reg_lock);
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(snd_wss_interrupt);
+
+static snd_pcm_uframes_t snd_wss_playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ size_t ptr;
+
+ if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
+ return 0;
+ ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
+ return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ size_t ptr;
+
+ if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
+ return 0;
+ ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
+ return bytes_to_frames(substream->runtime, ptr);
+}
+
+/*
+
+ */
+
+static int snd_ad1848_probe(struct snd_wss *chip)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ unsigned long flags;
+ unsigned char r;
+ unsigned short hardware = 0;
+ int err = 0;
+ int i;
+
+ while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
+ if (time_after(jiffies, timeout))
+ return -ENODEV;
+ cond_resched();
+ }
+ spin_lock_irqsave(&chip->reg_lock, flags);
+
+ /* set CS423x MODE 1 */
+ snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+
+ snd_wss_dout(chip, CS4231_RIGHT_INPUT, 0x45); /* 0x55 & ~0x10 */
+ r = snd_wss_in(chip, CS4231_RIGHT_INPUT);
+ if (r != 0x45) {
+ /* RMGE always high on AD1847 */
+ if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) {
+ err = -ENODEV;
+ goto out;
+ }
+ hardware = WSS_HW_AD1847;
+ } else {
+ snd_wss_dout(chip, CS4231_LEFT_INPUT, 0xaa);
+ r = snd_wss_in(chip, CS4231_LEFT_INPUT);
+ /* L/RMGE always low on AT2320 */
+ if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) {
+ err = -ENODEV;
+ goto out;
+ }
+ }
+
+ /* clear pending IRQ */
+ wss_inb(chip, CS4231P(STATUS));
+ wss_outb(chip, CS4231P(STATUS), 0);
+ mb();
+
+ if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT)
+ goto out;
+
+ if (hardware) {
+ chip->hardware = hardware;
+ goto out;
+ }
+
+ r = snd_wss_in(chip, CS4231_MISC_INFO);
+
+ /* set CS423x MODE 2 */
+ snd_wss_dout(chip, CS4231_MISC_INFO, CS4231_MODE2);
+ for (i = 0; i < 16; i++) {
+ if (snd_wss_in(chip, i) != snd_wss_in(chip, 16 + i)) {
+ /* we have more than 16 registers: check ID */
+ if ((r & 0xf) != 0xa)
+ goto out_mode;
+ /*
+ * on CMI8330, CS4231_VERSION is volume control and
+ * can be set to 0
+ */
+ snd_wss_dout(chip, CS4231_VERSION, 0);
+ r = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+ if (!r)
+ chip->hardware = WSS_HW_CMI8330;
+ goto out_mode;
+ }
+ }
+ if (r & 0x80)
+ chip->hardware = WSS_HW_CS4248;
+ else
+ chip->hardware = WSS_HW_AD1848;
+out_mode:
+ snd_wss_dout(chip, CS4231_MISC_INFO, 0);
+out:
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return err;
+}
+
+static int snd_wss_probe(struct snd_wss *chip)
+{
+ unsigned long flags;
+ int i, id, rev, regnum;
+ unsigned char *ptr;
+ unsigned int hw;
+
+ id = snd_ad1848_probe(chip);
+ if (id < 0)
+ return id;
+
+ hw = chip->hardware;
+ if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+ for (i = 0; i < 50; i++) {
+ mb();
+ if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+ msleep(2);
+ else {
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_MISC_INFO,
+ CS4231_MODE2);
+ id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (id == 0x0a)
+ break; /* this is valid value */
+ }
+ }
+ snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
+ if (id != 0x0a)
+ return -ENODEV; /* no valid device found */
+
+ rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+ snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
+ if (rev == 0x80) {
+ unsigned char tmp = snd_wss_in(chip, 23);
+ snd_wss_out(chip, 23, ~tmp);
+ if (snd_wss_in(chip, 23) != tmp)
+ chip->hardware = WSS_HW_AD1845;
+ else
+ chip->hardware = WSS_HW_CS4231;
+ } else if (rev == 0xa0) {
+ chip->hardware = WSS_HW_CS4231A;
+ } else if (rev == 0xa2) {
+ chip->hardware = WSS_HW_CS4232;
+ } else if (rev == 0xb2) {
+ chip->hardware = WSS_HW_CS4232A;
+ } else if (rev == 0x83) {
+ chip->hardware = WSS_HW_CS4236;
+ } else if (rev == 0x03) {
+ chip->hardware = WSS_HW_CS4236B;
+ } else {
+ snd_printk(KERN_ERR
+ "unknown CS chip with version 0x%x\n", rev);
+ return -ENODEV; /* unknown CS4231 chip? */
+ }
+ }
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ wss_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */
+ wss_outb(chip, CS4231P(STATUS), 0);
+ mb();
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
+ switch (chip->hardware) {
+ case WSS_HW_INTERWAVE:
+ chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
+ break;
+ case WSS_HW_CS4235:
+ case WSS_HW_CS4236B:
+ case WSS_HW_CS4237B:
+ case WSS_HW_CS4238B:
+ case WSS_HW_CS4239:
+ if (hw == WSS_HW_DETECT3)
+ chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;
+ else
+ chip->hardware = WSS_HW_CS4236;
+ break;
+ }
+
+ chip->image[CS4231_IFACE_CTRL] =
+ (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
+ (chip->single_dma ? CS4231_SINGLE_DMA : 0);
+ if (chip->hardware != WSS_HW_OPTI93X) {
+ chip->image[CS4231_ALT_FEATURE_1] = 0x80;
+ chip->image[CS4231_ALT_FEATURE_2] =
+ chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
+ }
+ /* enable fine grained frequency selection */
+ if (chip->hardware == WSS_HW_AD1845)
+ chip->image[AD1845_PWR_DOWN] = 8;
+
+ ptr = (unsigned char *) &chip->image;
+ regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
+ snd_wss_mce_down(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ for (i = 0; i < regnum; i++) /* ok.. fill all registers */
+ snd_wss_out(chip, i, *ptr++);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ snd_wss_mce_up(chip);
+ snd_wss_mce_down(chip);
+
+ mdelay(2);
+
+ /* ok.. try check hardware version for CS4236+ chips */
+ if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+ if (chip->hardware == WSS_HW_CS4236B) {
+ rev = snd_cs4236_ext_in(chip, CS4236_VERSION);
+ snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
+ id = snd_cs4236_ext_in(chip, CS4236_VERSION);
+ snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
+ snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
+ if ((id & 0x1f) == 0x1d) { /* CS4235 */
+ chip->hardware = WSS_HW_CS4235;
+ switch (id >> 5) {
+ case 4:
+ case 5:
+ case 6:
+ break;
+ default:
+ snd_printk(KERN_WARNING
+ "unknown CS4235 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
+ }
+ } else if ((id & 0x1f) == 0x0b) { /* CS4236/B */
+ switch (id >> 5) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ chip->hardware = WSS_HW_CS4236B;
+ break;
+ default:
+ snd_printk(KERN_WARNING
+ "unknown CS4236 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
+ }
+ } else if ((id & 0x1f) == 0x08) { /* CS4237B */
+ chip->hardware = WSS_HW_CS4237B;
+ switch (id >> 5) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ break;
+ default:
+ snd_printk(KERN_WARNING
+ "unknown CS4237B chip "
+ "(enhanced version = 0x%x)\n",
+ id);
+ }
+ } else if ((id & 0x1f) == 0x09) { /* CS4238B */
+ chip->hardware = WSS_HW_CS4238B;
+ switch (id >> 5) {
+ case 5:
+ case 6:
+ case 7:
+ break;
+ default:
+ snd_printk(KERN_WARNING
+ "unknown CS4238B chip "
+ "(enhanced version = 0x%x)\n",
+ id);
+ }
+ } else if ((id & 0x1f) == 0x1e) { /* CS4239 */
+ chip->hardware = WSS_HW_CS4239;
+ switch (id >> 5) {
+ case 4:
+ case 5:
+ case 6:
+ break;
+ default:
+ snd_printk(KERN_WARNING
+ "unknown CS4239 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
+ }
+ } else {
+ snd_printk(KERN_WARNING
+ "unknown CS4236/CS423xB chip "
+ "(enhanced version = 0x%x)\n", id);
+ }
+ }
+ }
+ return 0; /* all things are ok.. */
+}
+
+/*
+
+ */
+
+static struct snd_pcm_hardware snd_wss_playback =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
+ .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 5510,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (128*1024),
+ .period_bytes_min = 64,
+ .period_bytes_max = (128*1024),
+ .periods_min = 1,
+ .periods_max = 1024,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware snd_wss_capture =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
+ .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 5510,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (128*1024),
+ .period_bytes_min = 64,
+ .period_bytes_max = (128*1024),
+ .periods_min = 1,
+ .periods_max = 1024,
+ .fifo_size = 0,
+};
+
+/*
+
+ */
+
+static int snd_wss_playback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ runtime->hw = snd_wss_playback;
+
+ /* hardware limitation of older chipsets */
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+ SNDRV_PCM_FMTBIT_S16_BE);
+
+ /* hardware bug in InterWave chipset */
+ if (chip->hardware == WSS_HW_INTERWAVE && chip->dma1 > 3)
+ runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;
+
+ /* hardware limitation of cheap chips */
+ if (chip->hardware == WSS_HW_CS4235 ||
+ chip->hardware == WSS_HW_CS4239)
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
+
+ snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
+ snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
+
+ if (chip->claim_dma) {
+ if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
+ return err;
+ }
+
+ err = snd_wss_open(chip, WSS_MODE_PLAY);
+ if (err < 0) {
+ if (chip->release_dma)
+ chip->release_dma(chip, chip->dma_private_data, chip->dma1);
+ snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+ return err;
+ }
+ chip->playback_substream = substream;
+ snd_pcm_set_sync(substream);
+ chip->rate_constraint(runtime);
+ return 0;
+}
+
+static int snd_wss_capture_open(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ runtime->hw = snd_wss_capture;
+
+ /* hardware limitation of older chipsets */
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM |
+ SNDRV_PCM_FMTBIT_S16_BE);
+
+ /* hardware limitation of cheap chips */
+ if (chip->hardware == WSS_HW_CS4235 ||
+ chip->hardware == WSS_HW_CS4239 ||
+ chip->hardware == WSS_HW_OPTI93X)
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S16_LE;
+
+ snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
+ snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
+
+ if (chip->claim_dma) {
+ if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
+ return err;
+ }
+
+ err = snd_wss_open(chip, WSS_MODE_RECORD);
+ if (err < 0) {
+ if (chip->release_dma)
+ chip->release_dma(chip, chip->dma_private_data, chip->dma2);
+ snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+ return err;
+ }
+ chip->capture_substream = substream;
+ snd_pcm_set_sync(substream);
+ chip->rate_constraint(runtime);
+ return 0;
+}
+
+static int snd_wss_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+
+ chip->playback_substream = NULL;
+ snd_wss_close(chip, WSS_MODE_PLAY);
+ return 0;
+}
+
+static int snd_wss_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_wss *chip = snd_pcm_substream_chip(substream);
+
+ chip->capture_substream = NULL;
+ snd_wss_close(chip, WSS_MODE_RECORD);
+ return 0;
+}
+
+static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on)
+{
+ int tmp;
+
+ if (!chip->thinkpad_flag)
+ return;
+
+ outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
+ tmp = inb(AD1848_THINKPAD_CTL_PORT2);
+
+ if (on)
+ /* turn it on */
+ tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
+ else
+ /* turn it off */
+ tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
+
+ outb(tmp, AD1848_THINKPAD_CTL_PORT2);
+}
+
+#ifdef CONFIG_PM
+
+/* lowlevel suspend callback for CS4231 */
+static void snd_wss_suspend(struct snd_wss *chip)
+{
+ int reg;
+ unsigned long flags;
+
+ snd_pcm_suspend_all(chip->pcm);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ for (reg = 0; reg < 32; reg++)
+ chip->image[reg] = snd_wss_in(chip, reg);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (chip->thinkpad_flag)
+ snd_wss_thinkpad_twiddle(chip, 0);
+}
+
+/* lowlevel resume callback for CS4231 */
+static void snd_wss_resume(struct snd_wss *chip)
+{
+ int reg;
+ unsigned long flags;
+ /* int timeout; */
+
+ if (chip->thinkpad_flag)
+ snd_wss_thinkpad_twiddle(chip, 1);
+ snd_wss_mce_up(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ for (reg = 0; reg < 32; reg++) {
+ switch (reg) {
+ case CS4231_VERSION:
+ break;
+ default:
+ snd_wss_out(chip, reg, chip->image[reg]);
+ break;
+ }
+ }
+ /* Yamaha needs this to resume properly */
+ if (chip->hardware == WSS_HW_OPL3SA2)
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+ chip->image[CS4231_PLAYBK_FORMAT]);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+#if 1
+ snd_wss_mce_down(chip);
+#else
+ /* The following is a workaround to avoid freeze after resume on TP600E.
+ This is the first half of copy of snd_wss_mce_down(), but doesn't
+ include rescheduling. -- iwai
+ */
+ snd_wss_busy_wait(chip);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->mce_bit &= ~CS4231_MCE;
+ timeout = wss_inb(chip, CS4231P(REGSEL));
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (timeout == 0x80)
+ snd_printk(KERN_ERR "down [0x%lx]: serious init problem "
+ "- codec still busy\n", chip->port);
+ if ((timeout & CS4231_MCE) == 0 ||
+ !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
+ return;
+ }
+ snd_wss_busy_wait(chip);
+#endif
+}
+#endif /* CONFIG_PM */
+
+static int snd_wss_free(struct snd_wss *chip)
+{
+ release_and_free_resource(chip->res_port);
+ release_and_free_resource(chip->res_cport);
+ if (chip->irq >= 0) {
+ disable_irq(chip->irq);
+ if (!(chip->hwshare & WSS_HWSHARE_IRQ))
+ free_irq(chip->irq, (void *) chip);
+ }
+ if (!(chip->hwshare & WSS_HWSHARE_DMA1) && chip->dma1 >= 0) {
+ snd_dma_disable(chip->dma1);
+ free_dma(chip->dma1);
+ }
+ if (!(chip->hwshare & WSS_HWSHARE_DMA2) &&
+ chip->dma2 >= 0 && chip->dma2 != chip->dma1) {
+ snd_dma_disable(chip->dma2);
+ free_dma(chip->dma2);
+ }
+ if (chip->timer)
+ snd_device_free(chip->card, chip->timer);
+ kfree(chip);
+ return 0;
+}
+
+static int snd_wss_dev_free(struct snd_device *device)
+{
+ struct snd_wss *chip = device->device_data;
+ return snd_wss_free(chip);
+}
+
+const char *snd_wss_chip_id(struct snd_wss *chip)
+{
+ switch (chip->hardware) {
+ case WSS_HW_CS4231:
+ return "CS4231";
+ case WSS_HW_CS4231A:
+ return "CS4231A";
+ case WSS_HW_CS4232:
+ return "CS4232";
+ case WSS_HW_CS4232A:
+ return "CS4232A";
+ case WSS_HW_CS4235:
+ return "CS4235";
+ case WSS_HW_CS4236:
+ return "CS4236";
+ case WSS_HW_CS4236B:
+ return "CS4236B";
+ case WSS_HW_CS4237B:
+ return "CS4237B";
+ case WSS_HW_CS4238B:
+ return "CS4238B";
+ case WSS_HW_CS4239:
+ return "CS4239";
+ case WSS_HW_INTERWAVE:
+ return "AMD InterWave";
+ case WSS_HW_OPL3SA2:
+ return chip->card->shortname;
+ case WSS_HW_AD1845:
+ return "AD1845";
+ case WSS_HW_OPTI93X:
+ return "OPTi 93x";
+ case WSS_HW_AD1847:
+ return "AD1847";
+ case WSS_HW_AD1848:
+ return "AD1848";
+ case WSS_HW_CS4248:
+ return "CS4248";
+ case WSS_HW_CMI8330:
+ return "CMI8330/C3D";
+ default:
+ return "???";
+ }
+}
+EXPORT_SYMBOL(snd_wss_chip_id);
+
+static int snd_wss_new(struct snd_card *card,
+ unsigned short hardware,
+ unsigned short hwshare,
+ struct snd_wss **rchip)
+{
+ struct snd_wss *chip;
+
+ *rchip = NULL;
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+ chip->hardware = hardware;
+ chip->hwshare = hwshare;
+
+ spin_lock_init(&chip->reg_lock);
+ mutex_init(&chip->mce_mutex);
+ mutex_init(&chip->open_mutex);
+ chip->card = card;
+ chip->rate_constraint = snd_wss_xrate;
+ chip->set_playback_format = snd_wss_playback_format;
+ chip->set_capture_format = snd_wss_capture_format;
+ if (chip->hardware == WSS_HW_OPTI93X)
+ memcpy(&chip->image, &snd_opti93x_original_image,
+ sizeof(snd_opti93x_original_image));
+ else
+ memcpy(&chip->image, &snd_wss_original_image,
+ sizeof(snd_wss_original_image));
+ if (chip->hardware & WSS_HW_AD1848_MASK) {
+ chip->image[CS4231_PIN_CTRL] = 0;
+ chip->image[CS4231_TEST_INIT] = 0;
+ }
+
+ *rchip = chip;
+ return 0;
+}
+
+int snd_wss_create(struct snd_card *card,
+ unsigned long port,
+ unsigned long cport,
+ int irq, int dma1, int dma2,
+ unsigned short hardware,
+ unsigned short hwshare,
+ struct snd_wss **rchip)
+{
+ static struct snd_device_ops ops = {
+ .dev_free = snd_wss_dev_free,
+ };
+ struct snd_wss *chip;
+ int err;
+
+ err = snd_wss_new(card, hardware, hwshare, &chip);
+ if (err < 0)
+ return err;
+
+ chip->irq = -1;
+ chip->dma1 = -1;
+ chip->dma2 = -1;
+
+ chip->res_port = request_region(port, 4, "WSS");
+ if (!chip->res_port) {
+ snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port);
+ snd_wss_free(chip);
+ return -EBUSY;
+ }
+ chip->port = port;
+ if ((long)cport >= 0) {
+ chip->res_cport = request_region(cport, 8, "CS4232 Control");
+ if (!chip->res_cport) {
+ snd_printk(KERN_ERR
+ "wss: can't grab control port 0x%lx\n", cport);
+ snd_wss_free(chip);
+ return -ENODEV;
+ }
+ }
+ chip->cport = cport;
+ if (!(hwshare & WSS_HWSHARE_IRQ))
+ if (request_irq(irq, snd_wss_interrupt, 0,
+ "WSS", (void *) chip)) {
+ snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq);
+ snd_wss_free(chip);
+ return -EBUSY;
+ }
+ chip->irq = irq;
+ if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "WSS - 1")) {
+ snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1);
+ snd_wss_free(chip);
+ return -EBUSY;
+ }
+ chip->dma1 = dma1;
+ if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 &&
+ dma2 >= 0 && request_dma(dma2, "WSS - 2")) {
+ snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2);
+ snd_wss_free(chip);
+ return -EBUSY;
+ }
+ if (dma1 == dma2 || dma2 < 0) {
+ chip->single_dma = 1;
+ chip->dma2 = chip->dma1;
+ } else
+ chip->dma2 = dma2;
+
+ if (hardware == WSS_HW_THINKPAD) {
+ chip->thinkpad_flag = 1;
+ chip->hardware = WSS_HW_DETECT; /* reset */
+ snd_wss_thinkpad_twiddle(chip, 1);
+ }
+
+ /* global setup */
+ if (snd_wss_probe(chip) < 0) {
+ snd_wss_free(chip);
+ return -ENODEV;
+ }
+ snd_wss_init(chip);
+
+#if 0
+ if (chip->hardware & WSS_HW_CS4232_MASK) {
+ if (chip->res_cport == NULL)
+ snd_printk(KERN_ERR "CS4232 control port features are "
+ "not accessible\n");
+ }
+#endif
+
+ /* Register device */
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0) {
+ snd_wss_free(chip);
+ return err;
+ }
+
+#ifdef CONFIG_PM
+ /* Power Management */
+ chip->suspend = snd_wss_suspend;
+ chip->resume = snd_wss_resume;
+#endif
+
+ *rchip = chip;
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_create);
+
+static struct snd_pcm_ops snd_wss_playback_ops = {
+ .open = snd_wss_playback_open,
+ .close = snd_wss_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_wss_playback_hw_params,
+ .hw_free = snd_wss_playback_hw_free,
+ .prepare = snd_wss_playback_prepare,
+ .trigger = snd_wss_trigger,
+ .pointer = snd_wss_playback_pointer,
+};
+
+static struct snd_pcm_ops snd_wss_capture_ops = {
+ .open = snd_wss_capture_open,
+ .close = snd_wss_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_wss_capture_hw_params,
+ .hw_free = snd_wss_capture_hw_free,
+ .prepare = snd_wss_capture_prepare,
+ .trigger = snd_wss_trigger,
+ .pointer = snd_wss_capture_pointer,
+};
+
+int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(chip->card, "WSS", device, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops);
+
+ /* global setup */
+ pcm->private_data = chip;
+ pcm->info_flags = 0;
+ if (chip->single_dma)
+ pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
+ if (chip->hardware != WSS_HW_INTERWAVE)
+ pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+ strcpy(pcm->name, snd_wss_chip_id(chip));
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ snd_dma_isa_data(),
+ 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
+
+ chip->pcm = pcm;
+ if (rpcm)
+ *rpcm = pcm;
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_pcm);
+
+static void snd_wss_timer_free(struct snd_timer *timer)
+{
+ struct snd_wss *chip = timer->private_data;
+ chip->timer = NULL;
+}
+
+int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
+{
+ struct snd_timer *timer;
+ struct snd_timer_id tid;
+ int err;
+
+ /* Timer initialization */
+ tid.dev_class = SNDRV_TIMER_CLASS_CARD;
+ tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
+ tid.card = chip->card->number;
+ tid.device = device;
+ tid.subdevice = 0;
+ if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
+ return err;
+ strcpy(timer->name, snd_wss_chip_id(chip));
+ timer->private_data = chip;
+ timer->private_free = snd_wss_timer_free;
+ timer->hw = snd_wss_timer_table;
+ chip->timer = timer;
+ if (rtimer)
+ *rtimer = timer;
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_timer);
+
+/*
+ * MIXER part
+ */
+
+static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[4] = {
+ "Line", "Aux", "Mic", "Mix"
+ };
+ static char *opl3sa_texts[4] = {
+ "Line", "CD", "Mic", "Mix"
+ };
+ static char *gusmax_texts[4] = {
+ "Line", "Synth", "Mic", "Mix"
+ };
+ char **ptexts = texts;
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+
+ if (snd_BUG_ON(!chip->card))
+ return -EINVAL;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 2;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item > 3)
+ uinfo->value.enumerated.item = 3;
+ if (!strcmp(chip->card->driver, "GUS MAX"))
+ ptexts = gusmax_texts;
+ switch (chip->hardware) {
+ case WSS_HW_INTERWAVE:
+ ptexts = gusmax_texts;
+ break;
+ case WSS_HW_OPTI93X:
+ case WSS_HW_OPL3SA2:
+ ptexts = opl3sa_texts;
+ break;
+ }
+ strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_wss_get_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
+ ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return 0;
+}
+
+static int snd_wss_put_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ unsigned short left, right;
+ int change;
+
+ if (ucontrol->value.enumerated.item[0] > 3 ||
+ ucontrol->value.enumerated.item[1] > 3)
+ return -EINVAL;
+ left = ucontrol->value.enumerated.item[0] << 6;
+ right = ucontrol->value.enumerated.item[1] << 6;
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
+ right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
+ change = left != chip->image[CS4231_LEFT_INPUT] ||
+ right != chip->image[CS4231_RIGHT_INPUT];
+ snd_wss_out(chip, CS4231_LEFT_INPUT, left);
+ snd_wss_out(chip, CS4231_RIGHT_INPUT, right);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return change;
+}
+
+int snd_wss_info_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+
+ uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask;
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_info_single);
+
+int snd_wss_get_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int reg = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0xff;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0xff;
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (invert)
+ ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_get_single);
+
+int snd_wss_put_single(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int reg = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0xff;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0xff;
+ int change;
+ unsigned short val;
+
+ val = (ucontrol->value.integer.value[0] & mask);
+ if (invert)
+ val = mask - val;
+ val <<= shift;
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ val = (chip->image[reg] & ~(mask << shift)) | val;
+ change = val != chip->image[reg];
+ snd_wss_out(chip, reg, val);
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return change;
+}
+EXPORT_SYMBOL(snd_wss_put_single);
+
+int snd_wss_info_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int mask = (kcontrol->private_value >> 24) & 0xff;
+
+ uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask;
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_info_double);
+
+int snd_wss_get_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int left_reg = kcontrol->private_value & 0xff;
+ int right_reg = (kcontrol->private_value >> 8) & 0xff;
+ int shift_left = (kcontrol->private_value >> 16) & 0x07;
+ int shift_right = (kcontrol->private_value >> 19) & 0x07;
+ int mask = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 22) & 1;
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
+ ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (invert) {
+ ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+ ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
+ }
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_get_double);
+
+int snd_wss_put_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int left_reg = kcontrol->private_value & 0xff;
+ int right_reg = (kcontrol->private_value >> 8) & 0xff;
+ int shift_left = (kcontrol->private_value >> 16) & 0x07;
+ int shift_right = (kcontrol->private_value >> 19) & 0x07;
+ int mask = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 22) & 1;
+ int change;
+ unsigned short val1, val2;
+
+ val1 = ucontrol->value.integer.value[0] & mask;
+ val2 = ucontrol->value.integer.value[1] & mask;
+ if (invert) {
+ val1 = mask - val1;
+ val2 = mask - val2;
+ }
+ val1 <<= shift_left;
+ val2 <<= shift_right;
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ if (left_reg != right_reg) {
+ val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
+ val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
+ change = val1 != chip->image[left_reg] ||
+ val2 != chip->image[right_reg];
+ snd_wss_out(chip, left_reg, val1);
+ snd_wss_out(chip, right_reg, val2);
+ } else {
+ mask = (mask << shift_left) | (mask << shift_right);
+ val1 = (chip->image[left_reg] & ~mask) | val1 | val2;
+ change = val1 != chip->image[left_reg];
+ snd_wss_out(chip, left_reg, val1);
+ }
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return change;
+}
+EXPORT_SYMBOL(snd_wss_put_double);
+
+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 const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+
+static struct snd_kcontrol_new snd_wss_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("PCM Playback Volume", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+ db_scale_6bit),
+WSS_DOUBLE("Aux Playback Switch", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 0,
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_DOUBLE("Aux Playback Switch", 1,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Aux Playback Volume", 1,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
+ 0, 0, 15, 0, db_scale_rec_gain),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_wss_info_mux,
+ .get = snd_wss_get_mux,
+ .put = snd_wss_put_mux,
+},
+WSS_DOUBLE("Mic Boost (+20dB)", 0,
+ CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+WSS_SINGLE("Loopback Capture Switch", 0,
+ CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1,
+ db_scale_6bit),
+WSS_DOUBLE("Line Playback Switch", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+WSS_DOUBLE_TLV("Line Playback Volume", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
+WSS_SINGLE("Beep Playback Switch", 0,
+ CS4231_MONO_CTRL, 7, 1, 1),
+WSS_SINGLE_TLV("Beep Playback Volume", 0,
+ CS4231_MONO_CTRL, 0, 15, 1,
+ db_scale_4bit),
+WSS_SINGLE("Mono Output Playback Switch", 0,
+ CS4231_MONO_CTRL, 6, 1, 1),
+WSS_SINGLE("Beep Bypass Playback Switch", 0,
+ CS4231_MONO_CTRL, 5, 1, 0),
+};
+
+int snd_wss_mixer(struct snd_wss *chip)
+{
+ struct snd_card *card;
+ unsigned int idx;
+ int err;
+ int count = ARRAY_SIZE(snd_wss_controls);
+
+ if (snd_BUG_ON(!chip || !chip->pcm))
+ return -EINVAL;
+
+ card = chip->card;
+
+ strcpy(card->mixername, chip->pcm->name);
+
+ /* Use only the first 11 entries on AD1848 */
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ count = 11;
+ /* There is no loopback on OPTI93X */
+ else if (chip->hardware == WSS_HW_OPTI93X)
+ count = 9;
+
+ for (idx = 0; idx < count; idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_wss_controls[idx],
+ chip));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(snd_wss_mixer);
+
+const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction)
+{
+ return direction == SNDRV_PCM_STREAM_PLAYBACK ?
+ &snd_wss_playback_ops : &snd_wss_capture_ops;
+}
+EXPORT_SYMBOL(snd_wss_get_pcm_ops);
+
+/*
+ * INIT part
+ */
+
+static int __init alsa_wss_init(void)
+{
+ return 0;
+}
+
+static void __exit alsa_wss_exit(void)
+{
+}
+
+module_init(alsa_wss_init);
+module_exit(alsa_wss_exit);