Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
b54fc8dd
Commit
b54fc8dd
authored
Mar 24, 2009
by
Takashi Iwai
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/oxygen' into for-linus
parents
9fb5430c
873591db
Changes
8
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
507 additions
and
116 deletions
+507
-116
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/ALSA-Configuration.txt
+1
-1
sound/pci/Kconfig
sound/pci/Kconfig
+2
-1
sound/pci/oxygen/hifier.c
sound/pci/oxygen/hifier.c
+10
-2
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.c
+88
-26
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen.h
+18
-4
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_io.c
+31
-0
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_lib.c
+87
-13
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/virtuoso.c
+270
-69
No files found.
Documentation/sound/alsa/ALSA-Configuration.txt
View file @
b54fc8dd
...
@@ -1859,7 +1859,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
...
@@ -1859,7 +1859,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
-------------------
-------------------
Module for sound cards based on the Asus AV100/AV200 chips,
Module for sound cards based on the Asus AV100/AV200 chips,
i.e., Xonar D1, DX, D2, D2X
and HDAV1.3 (Deluxe)
.
i.e., Xonar D1, DX, D2, D2X
, HDAV1.3 (Deluxe), and Essence STX
.
This module supports autoprobe and multiple cards.
This module supports autoprobe and multiple cards.
...
...
sound/pci/Kconfig
View file @
b54fc8dd
...
@@ -764,7 +764,8 @@ config SND_VIRTUOSO
...
@@ -764,7 +764,8 @@ config SND_VIRTUOSO
select SND_OXYGEN_LIB
select SND_OXYGEN_LIB
help
help
Say Y here to include support for sound cards based on the
Say Y here to include support for sound cards based on the
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X.
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and
Essence STX.
Support for the HDAV1.3 (Deluxe) is very experimental.
Support for the HDAV1.3 (Deluxe) is very experimental.
To compile this driver as a module, choose M here: the module
To compile this driver as a module, choose M here: the module
...
...
sound/pci/oxygen/hifier.c
View file @
b54fc8dd
...
@@ -45,6 +45,7 @@ MODULE_PARM_DESC(enable, "enable card");
...
@@ -45,6 +45,7 @@ MODULE_PARM_DESC(enable, "enable card");
static
struct
pci_device_id
hifier_ids
[]
__devinitdata
=
{
static
struct
pci_device_id
hifier_ids
[]
__devinitdata
=
{
{
OXYGEN_PCI_SUBID
(
0x14c3
,
0x1710
)
},
{
OXYGEN_PCI_SUBID
(
0x14c3
,
0x1710
)
},
{
OXYGEN_PCI_SUBID
(
0x14c3
,
0x1711
)
},
{
OXYGEN_PCI_SUBID
(
0x14c3
,
0x1711
)
},
{
OXYGEN_PCI_SUBID_BROKEN_EEPROM
},
{
}
{
}
};
};
MODULE_DEVICE_TABLE
(
pci
,
hifier_ids
);
MODULE_DEVICE_TABLE
(
pci
,
hifier_ids
);
...
@@ -151,7 +152,6 @@ static const struct oxygen_model model_hifier = {
...
@@ -151,7 +152,6 @@ static const struct oxygen_model model_hifier = {
.
shortname
=
"C-Media CMI8787"
,
.
shortname
=
"C-Media CMI8787"
,
.
longname
=
"C-Media Oxygen HD Audio"
,
.
longname
=
"C-Media Oxygen HD Audio"
,
.
chip
=
"CMI8788"
,
.
chip
=
"CMI8788"
,
.
owner
=
THIS_MODULE
,
.
init
=
hifier_init
,
.
init
=
hifier_init
,
.
control_filter
=
hifier_control_filter
,
.
control_filter
=
hifier_control_filter
,
.
cleanup
=
hifier_cleanup
,
.
cleanup
=
hifier_cleanup
,
...
@@ -173,6 +173,13 @@ static const struct oxygen_model model_hifier = {
...
@@ -173,6 +173,13 @@ static const struct oxygen_model model_hifier = {
.
adc_i2s_format
=
OXYGEN_I2S_FORMAT_LJUST
,
.
adc_i2s_format
=
OXYGEN_I2S_FORMAT_LJUST
,
};
};
static
int
__devinit
get_hifier_model
(
struct
oxygen
*
chip
,
const
struct
pci_device_id
*
id
)
{
chip
->
model
=
model_hifier
;
return
0
;
}
static
int
__devinit
hifier_probe
(
struct
pci_dev
*
pci
,
static
int
__devinit
hifier_probe
(
struct
pci_dev
*
pci
,
const
struct
pci_device_id
*
pci_id
)
const
struct
pci_device_id
*
pci_id
)
{
{
...
@@ -185,7 +192,8 @@ static int __devinit hifier_probe(struct pci_dev *pci,
...
@@ -185,7 +192,8 @@ static int __devinit hifier_probe(struct pci_dev *pci,
++
dev
;
++
dev
;
return
-
ENOENT
;
return
-
ENOENT
;
}
}
err
=
oxygen_pci_probe
(
pci
,
index
[
dev
],
id
[
dev
],
&
model_hifier
,
0
);
err
=
oxygen_pci_probe
(
pci
,
index
[
dev
],
id
[
dev
],
THIS_MODULE
,
hifier_ids
,
get_hifier_model
);
if
(
err
>=
0
)
if
(
err
>=
0
)
++
dev
;
++
dev
;
return
err
;
return
err
;
...
...
sound/pci/oxygen/oxygen.c
View file @
b54fc8dd
/*
/*
* C-Media CMI8788 driver for C-Media's reference design and
for the X-Meridian
* C-Media CMI8788 driver for C-Media's reference design and
similar models
*
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
*
*
...
@@ -26,6 +26,7 @@
...
@@ -26,6 +26,7 @@
*
*
* GPIO 0 -> DFS0 of AK5385
* GPIO 0 -> DFS0 of AK5385
* GPIO 1 -> DFS1 of AK5385
* GPIO 1 -> DFS1 of AK5385
* GPIO 8 -> enable headphone amplifier on HT-Omega models
*/
*/
#include <linux/delay.h>
#include <linux/delay.h>
...
@@ -61,7 +62,8 @@ MODULE_PARM_DESC(enable, "enable card");
...
@@ -61,7 +62,8 @@ MODULE_PARM_DESC(enable, "enable card");
enum
{
enum
{
MODEL_CMEDIA_REF
,
/* C-Media's reference design */
MODEL_CMEDIA_REF
,
/* C-Media's reference design */
MODEL_MERIDIAN
,
/* AuzenTech X-Meridian */
MODEL_MERIDIAN
,
/* AuzenTech X-Meridian */
MODEL_HALO
,
/* HT-Omega Claro halo */
MODEL_CLARO
,
/* HT-Omega Claro */
MODEL_CLARO_HALO
,
/* HT-Omega Claro halo */
};
};
static
struct
pci_device_id
oxygen_ids
[]
__devinitdata
=
{
static
struct
pci_device_id
oxygen_ids
[]
__devinitdata
=
{
...
@@ -74,8 +76,8 @@ static struct pci_device_id oxygen_ids[] __devinitdata = {
...
@@ -74,8 +76,8 @@ static struct pci_device_id oxygen_ids[] __devinitdata = {
{
OXYGEN_PCI_SUBID
(
0x147a
,
0xa017
),
.
driver_data
=
MODEL_CMEDIA_REF
},
{
OXYGEN_PCI_SUBID
(
0x147a
,
0xa017
),
.
driver_data
=
MODEL_CMEDIA_REF
},
{
OXYGEN_PCI_SUBID
(
0x1a58
,
0x0910
),
.
driver_data
=
MODEL_CMEDIA_REF
},
{
OXYGEN_PCI_SUBID
(
0x1a58
,
0x0910
),
.
driver_data
=
MODEL_CMEDIA_REF
},
{
OXYGEN_PCI_SUBID
(
0x415a
,
0x5431
),
.
driver_data
=
MODEL_MERIDIAN
},
{
OXYGEN_PCI_SUBID
(
0x415a
,
0x5431
),
.
driver_data
=
MODEL_MERIDIAN
},
{
OXYGEN_PCI_SUBID
(
0x7284
,
0x9761
),
.
driver_data
=
MODEL_C
MEDIA_REF
},
{
OXYGEN_PCI_SUBID
(
0x7284
,
0x9761
),
.
driver_data
=
MODEL_C
LARO
},
{
OXYGEN_PCI_SUBID
(
0x7284
,
0x9781
),
.
driver_data
=
MODEL_HALO
},
{
OXYGEN_PCI_SUBID
(
0x7284
,
0x9781
),
.
driver_data
=
MODEL_
CLARO_
HALO
},
{
}
{
}
};
};
MODULE_DEVICE_TABLE
(
pci
,
oxygen_ids
);
MODULE_DEVICE_TABLE
(
pci
,
oxygen_ids
);
...
@@ -86,6 +88,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
...
@@ -86,6 +88,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
#define GPIO_AK5385_DFS_DOUBLE 0x0001
#define GPIO_AK5385_DFS_DOUBLE 0x0001
#define GPIO_AK5385_DFS_QUAD 0x0002
#define GPIO_AK5385_DFS_QUAD 0x0002
#define GPIO_CLARO_HP 0x0100
struct
generic_data
{
struct
generic_data
{
u8
ak4396_ctl2
;
u8
ak4396_ctl2
;
u16
saved_wm8785_registers
[
2
];
u16
saved_wm8785_registers
[
2
];
...
@@ -196,10 +200,46 @@ static void meridian_init(struct oxygen *chip)
...
@@ -196,10 +200,46 @@ static void meridian_init(struct oxygen *chip)
ak5385_init
(
chip
);
ak5385_init
(
chip
);
}
}
static
void
claro_enable_hp
(
struct
oxygen
*
chip
)
{
msleep
(
300
);
oxygen_set_bits16
(
chip
,
OXYGEN_GPIO_CONTROL
,
GPIO_CLARO_HP
);
oxygen_set_bits16
(
chip
,
OXYGEN_GPIO_DATA
,
GPIO_CLARO_HP
);
}
static
void
claro_init
(
struct
oxygen
*
chip
)
{
ak4396_init
(
chip
);
wm8785_init
(
chip
);
claro_enable_hp
(
chip
);
}
static
void
claro_halo_init
(
struct
oxygen
*
chip
)
{
ak4396_init
(
chip
);
ak5385_init
(
chip
);
claro_enable_hp
(
chip
);
}
static
void
generic_cleanup
(
struct
oxygen
*
chip
)
static
void
generic_cleanup
(
struct
oxygen
*
chip
)
{
{
}
}
static
void
claro_disable_hp
(
struct
oxygen
*
chip
)
{
oxygen_clear_bits16
(
chip
,
OXYGEN_GPIO_DATA
,
GPIO_CLARO_HP
);
}
static
void
claro_cleanup
(
struct
oxygen
*
chip
)
{
claro_disable_hp
(
chip
);
}
static
void
claro_suspend
(
struct
oxygen
*
chip
)
{
claro_disable_hp
(
chip
);
}
static
void
generic_resume
(
struct
oxygen
*
chip
)
static
void
generic_resume
(
struct
oxygen
*
chip
)
{
{
ak4396_registers_init
(
chip
);
ak4396_registers_init
(
chip
);
...
@@ -211,6 +251,12 @@ static void meridian_resume(struct oxygen *chip)
...
@@ -211,6 +251,12 @@ static void meridian_resume(struct oxygen *chip)
ak4396_registers_init
(
chip
);
ak4396_registers_init
(
chip
);
}
}
static
void
claro_resume
(
struct
oxygen
*
chip
)
{
ak4396_registers_init
(
chip
);
claro_enable_hp
(
chip
);
}
static
void
set_ak4396_params
(
struct
oxygen
*
chip
,
static
void
set_ak4396_params
(
struct
oxygen
*
chip
,
struct
snd_pcm_hw_params
*
params
)
struct
snd_pcm_hw_params
*
params
)
{
{
...
@@ -293,30 +339,10 @@ static void set_ak5385_params(struct oxygen *chip,
...
@@ -293,30 +339,10 @@ static void set_ak5385_params(struct oxygen *chip,
static
const
DECLARE_TLV_DB_LINEAR
(
ak4396_db_scale
,
TLV_DB_GAIN_MUTE
,
0
);
static
const
DECLARE_TLV_DB_LINEAR
(
ak4396_db_scale
,
TLV_DB_GAIN_MUTE
,
0
);
static
int
generic_probe
(
struct
oxygen
*
chip
,
unsigned
long
driver_data
)
{
if
(
driver_data
==
MODEL_MERIDIAN
)
{
chip
->
model
.
init
=
meridian_init
;
chip
->
model
.
resume
=
meridian_resume
;
chip
->
model
.
set_adc_params
=
set_ak5385_params
;
chip
->
model
.
device_config
=
PLAYBACK_0_TO_I2S
|
PLAYBACK_1_TO_SPDIF
|
CAPTURE_0_FROM_I2S_2
|
CAPTURE_1_FROM_SPDIF
;
}
if
(
driver_data
==
MODEL_MERIDIAN
||
driver_data
==
MODEL_HALO
)
{
chip
->
model
.
misc_flags
=
OXYGEN_MISC_MIDI
;
chip
->
model
.
device_config
|=
MIDI_OUTPUT
|
MIDI_INPUT
;
}
return
0
;
}
static
const
struct
oxygen_model
model_generic
=
{
static
const
struct
oxygen_model
model_generic
=
{
.
shortname
=
"C-Media CMI8788"
,
.
shortname
=
"C-Media CMI8788"
,
.
longname
=
"C-Media Oxygen HD Audio"
,
.
longname
=
"C-Media Oxygen HD Audio"
,
.
chip
=
"CMI8788"
,
.
chip
=
"CMI8788"
,
.
owner
=
THIS_MODULE
,
.
probe
=
generic_probe
,
.
init
=
generic_init
,
.
init
=
generic_init
,
.
cleanup
=
generic_cleanup
,
.
cleanup
=
generic_cleanup
,
.
resume
=
generic_resume
,
.
resume
=
generic_resume
,
...
@@ -341,6 +367,42 @@ static const struct oxygen_model model_generic = {
...
@@ -341,6 +367,42 @@ static const struct oxygen_model model_generic = {
.
adc_i2s_format
=
OXYGEN_I2S_FORMAT_LJUST
,
.
adc_i2s_format
=
OXYGEN_I2S_FORMAT_LJUST
,
};
};
static
int
__devinit
get_oxygen_model
(
struct
oxygen
*
chip
,
const
struct
pci_device_id
*
id
)
{
chip
->
model
=
model_generic
;
switch
(
id
->
driver_data
)
{
case
MODEL_MERIDIAN
:
chip
->
model
.
init
=
meridian_init
;
chip
->
model
.
resume
=
meridian_resume
;
chip
->
model
.
set_adc_params
=
set_ak5385_params
;
chip
->
model
.
device_config
=
PLAYBACK_0_TO_I2S
|
PLAYBACK_1_TO_SPDIF
|
CAPTURE_0_FROM_I2S_2
|
CAPTURE_1_FROM_SPDIF
;
break
;
case
MODEL_CLARO
:
chip
->
model
.
init
=
claro_init
;
chip
->
model
.
cleanup
=
claro_cleanup
;
chip
->
model
.
suspend
=
claro_suspend
;
chip
->
model
.
resume
=
claro_resume
;
break
;
case
MODEL_CLARO_HALO
:
chip
->
model
.
init
=
claro_halo_init
;
chip
->
model
.
cleanup
=
claro_cleanup
;
chip
->
model
.
suspend
=
claro_suspend
;
chip
->
model
.
resume
=
claro_resume
;
chip
->
model
.
set_adc_params
=
set_ak5385_params
;
break
;
}
if
(
id
->
driver_data
==
MODEL_MERIDIAN
||
id
->
driver_data
==
MODEL_CLARO_HALO
)
{
chip
->
model
.
misc_flags
=
OXYGEN_MISC_MIDI
;
chip
->
model
.
device_config
|=
MIDI_OUTPUT
|
MIDI_INPUT
;
}
return
0
;
}
static
int
__devinit
generic_oxygen_probe
(
struct
pci_dev
*
pci
,
static
int
__devinit
generic_oxygen_probe
(
struct
pci_dev
*
pci
,
const
struct
pci_device_id
*
pci_id
)
const
struct
pci_device_id
*
pci_id
)
{
{
...
@@ -353,8 +415,8 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
...
@@ -353,8 +415,8 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
++
dev
;
++
dev
;
return
-
ENOENT
;
return
-
ENOENT
;
}
}
err
=
oxygen_pci_probe
(
pci
,
index
[
dev
],
id
[
dev
],
err
=
oxygen_pci_probe
(
pci
,
index
[
dev
],
id
[
dev
],
THIS_MODULE
,
&
model_generic
,
pci_id
->
driver_data
);
oxygen_ids
,
get_oxygen_model
);
if
(
err
>=
0
)
if
(
err
>=
0
)
++
dev
;
++
dev
;
return
err
;
return
err
;
...
...
sound/pci/oxygen/oxygen.h
View file @
b54fc8dd
...
@@ -18,6 +18,8 @@
...
@@ -18,6 +18,8 @@
#define OXYGEN_IO_SIZE 0x100
#define OXYGEN_IO_SIZE 0x100
#define OXYGEN_EEPROM_ID 0x434d
/* "CM" */
/* model-specific configuration of outputs/inputs */
/* model-specific configuration of outputs/inputs */
#define PLAYBACK_0_TO_I2S 0x0001
#define PLAYBACK_0_TO_I2S 0x0001
/* PLAYBACK_0_TO_AC97_0 not implemented */
/* PLAYBACK_0_TO_AC97_0 not implemented */
...
@@ -49,7 +51,13 @@ enum {
...
@@ -49,7 +51,13 @@ enum {
.subvendor = sv, \
.subvendor = sv, \
.subdevice = sd
.subdevice = sd
#define BROKEN_EEPROM_DRIVER_DATA ((unsigned long)-1)
#define OXYGEN_PCI_SUBID_BROKEN_EEPROM \
OXYGEN_PCI_SUBID(PCI_VENDOR_ID_CMEDIA, 0x8788), \
.driver_data = BROKEN_EEPROM_DRIVER_DATA
struct
pci_dev
;
struct
pci_dev
;
struct
pci_device_id
;
struct
snd_card
;
struct
snd_card
;
struct
snd_pcm_substream
;
struct
snd_pcm_substream
;
struct
snd_pcm_hardware
;
struct
snd_pcm_hardware
;
...
@@ -62,8 +70,6 @@ struct oxygen_model {
...
@@ -62,8 +70,6 @@ struct oxygen_model {
const
char
*
shortname
;
const
char
*
shortname
;
const
char
*
longname
;
const
char
*
longname
;
const
char
*
chip
;
const
char
*
chip
;
struct
module
*
owner
;
int
(
*
probe
)(
struct
oxygen
*
chip
,
unsigned
long
driver_data
);
void
(
*
init
)(
struct
oxygen
*
chip
);
void
(
*
init
)(
struct
oxygen
*
chip
);
int
(
*
control_filter
)(
struct
snd_kcontrol_new
*
template
);
int
(
*
control_filter
)(
struct
snd_kcontrol_new
*
template
);
int
(
*
mixer_init
)(
struct
oxygen
*
chip
);
int
(
*
mixer_init
)(
struct
oxygen
*
chip
);
...
@@ -83,6 +89,7 @@ struct oxygen_model {
...
@@ -83,6 +89,7 @@ struct oxygen_model {
void
(
*
ac97_switch
)(
struct
oxygen
*
chip
,
void
(
*
ac97_switch
)(
struct
oxygen
*
chip
,
unsigned
int
reg
,
unsigned
int
mute
);
unsigned
int
reg
,
unsigned
int
mute
);
const
unsigned
int
*
dac_tlv
;
const
unsigned
int
*
dac_tlv
;
unsigned
long
private_data
;
size_t
model_data_size
;
size_t
model_data_size
;
unsigned
int
device_config
;
unsigned
int
device_config
;
u8
dac_channels
;
u8
dac_channels
;
...
@@ -134,8 +141,12 @@ struct oxygen {
...
@@ -134,8 +141,12 @@ struct oxygen {
/* oxygen_lib.c */
/* oxygen_lib.c */
int
oxygen_pci_probe
(
struct
pci_dev
*
pci
,
int
index
,
char
*
id
,
int
oxygen_pci_probe
(
struct
pci_dev
*
pci
,
int
index
,
char
*
id
,
const
struct
oxygen_model
*
model
,
struct
module
*
owner
,
unsigned
long
driver_data
);
const
struct
pci_device_id
*
ids
,
int
(
*
get_model
)(
struct
oxygen
*
chip
,
const
struct
pci_device_id
*
id
)
);
void
oxygen_pci_remove
(
struct
pci_dev
*
pci
);
void
oxygen_pci_remove
(
struct
pci_dev
*
pci
);
#ifdef CONFIG_PM
#ifdef CONFIG_PM
int
oxygen_pci_suspend
(
struct
pci_dev
*
pci
,
pm_message_t
state
);
int
oxygen_pci_suspend
(
struct
pci_dev
*
pci
,
pm_message_t
state
);
...
@@ -180,6 +191,9 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
...
@@ -180,6 +191,9 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
void
oxygen_reset_uart
(
struct
oxygen
*
chip
);
void
oxygen_reset_uart
(
struct
oxygen
*
chip
);
void
oxygen_write_uart
(
struct
oxygen
*
chip
,
u8
data
);
void
oxygen_write_uart
(
struct
oxygen
*
chip
,
u8
data
);
u16
oxygen_read_eeprom
(
struct
oxygen
*
chip
,
unsigned
int
index
);
void
oxygen_write_eeprom
(
struct
oxygen
*
chip
,
unsigned
int
index
,
u16
value
);
static
inline
void
oxygen_set_bits8
(
struct
oxygen
*
chip
,
static
inline
void
oxygen_set_bits8
(
struct
oxygen
*
chip
,
unsigned
int
reg
,
u8
value
)
unsigned
int
reg
,
u8
value
)
{
{
...
...
sound/pci/oxygen/oxygen_io.c
View file @
b54fc8dd
...
@@ -254,3 +254,34 @@ void oxygen_write_uart(struct oxygen *chip, u8 data)
...
@@ -254,3 +254,34 @@ void oxygen_write_uart(struct oxygen *chip, u8 data)
_write_uart
(
chip
,
0
,
data
);
_write_uart
(
chip
,
0
,
data
);
}
}
EXPORT_SYMBOL
(
oxygen_write_uart
);
EXPORT_SYMBOL
(
oxygen_write_uart
);
u16
oxygen_read_eeprom
(
struct
oxygen
*
chip
,
unsigned
int
index
)
{
unsigned
int
timeout
;
oxygen_write8
(
chip
,
OXYGEN_EEPROM_CONTROL
,
index
|
OXYGEN_EEPROM_DIR_READ
);
for
(
timeout
=
0
;
timeout
<
100
;
++
timeout
)
{
udelay
(
1
);
if
(
!
(
oxygen_read8
(
chip
,
OXYGEN_EEPROM_STATUS
)
&
OXYGEN_EEPROM_BUSY
))
break
;
}
return
oxygen_read16
(
chip
,
OXYGEN_EEPROM_DATA
);
}
void
oxygen_write_eeprom
(
struct
oxygen
*
chip
,
unsigned
int
index
,
u16
value
)
{
unsigned
int
timeout
;
oxygen_write16
(
chip
,
OXYGEN_EEPROM_DATA
,
value
);
oxygen_write8
(
chip
,
OXYGEN_EEPROM_CONTROL
,
index
|
OXYGEN_EEPROM_DIR_WRITE
);
for
(
timeout
=
0
;
timeout
<
10
;
++
timeout
)
{
msleep
(
1
);
if
(
!
(
oxygen_read8
(
chip
,
OXYGEN_EEPROM_STATUS
)
&
OXYGEN_EEPROM_BUSY
))
return
;
}
snd_printk
(
KERN_ERR
"EEPROM write timeout
\n
"
);
}
sound/pci/oxygen/oxygen_lib.c
View file @
b54fc8dd
...
@@ -34,6 +34,7 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
...
@@ -34,6 +34,7 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION
(
"C-Media CMI8788 helper library"
);
MODULE_DESCRIPTION
(
"C-Media CMI8788 helper library"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_LICENSE
(
"GPL v2"
);
#define DRIVER "oxygen"
static
inline
int
oxygen_uart_input_ready
(
struct
oxygen
*
chip
)
static
inline
int
oxygen_uart_input_ready
(
struct
oxygen
*
chip
)
{
{
...
@@ -243,6 +244,62 @@ static void oxygen_proc_init(struct oxygen *chip)
...
@@ -243,6 +244,62 @@ static void oxygen_proc_init(struct oxygen *chip)
#define oxygen_proc_init(chip)
#define oxygen_proc_init(chip)
#endif
#endif
static
const
struct
pci_device_id
*
oxygen_search_pci_id
(
struct
oxygen
*
chip
,
const
struct
pci_device_id
ids
[])
{
u16
subdevice
;
/*
* Make sure the EEPROM pins are available, i.e., not used for SPI.
* (This function is called before we initialize or use SPI.)
*/
oxygen_clear_bits8
(
chip
,
OXYGEN_FUNCTION
,
OXYGEN_FUNCTION_ENABLE_SPI_4_5
);
/*
* Read the subsystem device ID directly from the EEPROM, because the
* chip didn't if the first EEPROM word was overwritten.
*/
subdevice
=
oxygen_read_eeprom
(
chip
,
2
);
/*
* We use only the subsystem device ID for searching because it is
* unique even without the subsystem vendor ID, which may have been
* overwritten in the EEPROM.
*/
for
(;
ids
->
vendor
;
++
ids
)
if
(
ids
->
subdevice
==
subdevice
&&
ids
->
driver_data
!=
BROKEN_EEPROM_DRIVER_DATA
)
return
ids
;
return
NULL
;
}
static
void
oxygen_restore_eeprom
(
struct
oxygen
*
chip
,
const
struct
pci_device_id
*
id
)
{
if
(
oxygen_read_eeprom
(
chip
,
0
)
!=
OXYGEN_EEPROM_ID
)
{
/*
* This function gets called only when a known card model has
* been detected, i.e., we know there is a valid subsystem
* product ID at index 2 in the EEPROM. Therefore, we have
* been able to deduce the correct subsystem vendor ID, and
* this is enough information to restore the original EEPROM
* contents.
*/
oxygen_write_eeprom
(
chip
,
1
,
id
->
subvendor
);
oxygen_write_eeprom
(
chip
,
0
,
OXYGEN_EEPROM_ID
);
oxygen_set_bits8
(
chip
,
OXYGEN_MISC
,
OXYGEN_MISC_WRITE_PCI_SUBID
);
pci_write_config_word
(
chip
->
pci
,
PCI_SUBSYSTEM_VENDOR_ID
,
id
->
subvendor
);
pci_write_config_word
(
chip
->
pci
,
PCI_SUBSYSTEM_ID
,
id
->
subdevice
);
oxygen_clear_bits8
(
chip
,
OXYGEN_MISC
,
OXYGEN_MISC_WRITE_PCI_SUBID
);
snd_printk
(
KERN_INFO
"EEPROM ID restored
\n
"
);
}
}
static
void
oxygen_init
(
struct
oxygen
*
chip
)
static
void
oxygen_init
(
struct
oxygen
*
chip
)
{
{
unsigned
int
i
;
unsigned
int
i
;
...
@@ -446,21 +503,26 @@ static void oxygen_card_free(struct snd_card *card)
...
@@ -446,21 +503,26 @@ static void oxygen_card_free(struct snd_card *card)
free_irq
(
chip
->
irq
,
chip
);
free_irq
(
chip
->
irq
,
chip
);
flush_scheduled_work
();
flush_scheduled_work
();
chip
->
model
.
cleanup
(
chip
);
chip
->
model
.
cleanup
(
chip
);
kfree
(
chip
->
model_data
);
mutex_destroy
(
&
chip
->
mutex
);
mutex_destroy
(
&
chip
->
mutex
);
pci_release_regions
(
chip
->
pci
);
pci_release_regions
(
chip
->
pci
);
pci_disable_device
(
chip
->
pci
);
pci_disable_device
(
chip
->
pci
);
}
}
int
oxygen_pci_probe
(
struct
pci_dev
*
pci
,
int
index
,
char
*
id
,
int
oxygen_pci_probe
(
struct
pci_dev
*
pci
,
int
index
,
char
*
id
,
const
struct
oxygen_model
*
model
,
struct
module
*
owner
,
unsigned
long
driver_data
)
const
struct
pci_device_id
*
ids
,
int
(
*
get_model
)(
struct
oxygen
*
chip
,
const
struct
pci_device_id
*
id
)
)
{
{
struct
snd_card
*
card
;
struct
snd_card
*
card
;
struct
oxygen
*
chip
;
struct
oxygen
*
chip
;
const
struct
pci_device_id
*
pci_id
;
int
err
;
int
err
;
err
=
snd_card_create
(
index
,
id
,
model
->
owner
,
err
=
snd_card_create
(
index
,
id
,
owner
,
sizeof
(
*
chip
),
&
card
);
sizeof
(
*
chip
)
+
model
->
model_data_size
,
&
card
);
if
(
err
<
0
)
if
(
err
<
0
)
return
err
;
return
err
;
...
@@ -468,8 +530,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
...
@@ -468,8 +530,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
chip
->
card
=
card
;
chip
->
card
=
card
;
chip
->
pci
=
pci
;
chip
->
pci
=
pci
;
chip
->
irq
=
-
1
;
chip
->
irq
=
-
1
;
chip
->
model
=
*
model
;
chip
->
model_data
=
chip
+
1
;
spin_lock_init
(
&
chip
->
reg_lock
);
spin_lock_init
(
&
chip
->
reg_lock
);
mutex_init
(
&
chip
->
mutex
);
mutex_init
(
&
chip
->
mutex
);
INIT_WORK
(
&
chip
->
spdif_input_bits_work
,
INIT_WORK
(
&
chip
->
spdif_input_bits_work
,
...
@@ -481,7 +541,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
...
@@ -481,7 +541,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
if
(
err
<
0
)
if
(
err
<
0
)
goto
err_card
;
goto
err_card
;
err
=
pci_request_regions
(
pci
,
model
->
chip
);
err
=
pci_request_regions
(
pci
,
DRIVER
);
if
(
err
<
0
)
{
if
(
err
<
0
)
{
snd_printk
(
KERN_ERR
"cannot reserve PCI resources
\n
"
);
snd_printk
(
KERN_ERR
"cannot reserve PCI resources
\n
"
);
goto
err_pci_enable
;
goto
err_pci_enable
;
...
@@ -495,20 +555,34 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
...
@@ -495,20 +555,34 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
}
}
chip
->
addr
=
pci_resource_start
(
pci
,
0
);
chip
->
addr
=
pci_resource_start
(
pci
,
0
);
pci_id
=
oxygen_search_pci_id
(
chip
,
ids
);
if
(
!
pci_id
)
{
err
=
-
ENODEV
;
goto
err_pci_regions
;
}
oxygen_restore_eeprom
(
chip
,
pci_id
);
err
=
get_model
(
chip
,
pci_id
);
if
(
err
<
0
)
goto
err_pci_regions
;
if
(
chip
->
model
.
model_data_size
)
{
chip
->
model_data
=
kzalloc
(
chip
->
model
.
model_data_size
,
GFP_KERNEL
);
if
(
!
chip
->
model_data
)
{
err
=
-
ENOMEM
;
goto
err_pci_regions
;
}
}
pci_set_master
(
pci
);
pci_set_master
(
pci
);
snd_card_set_dev
(
card
,
&
pci
->
dev
);
snd_card_set_dev
(
card
,
&
pci
->
dev
);
card
->
private_free
=
oxygen_card_free
;
card
->
private_free
=
oxygen_card_free
;
if
(
chip
->
model
.
probe
)
{
err
=
chip
->
model
.
probe
(
chip
,
driver_data
);
if
(
err
<
0
)
goto
err_card
;
}
oxygen_init
(
chip
);
oxygen_init
(
chip
);
chip
->
model
.
init
(
chip
);
chip
->
model
.
init
(
chip
);
err
=
request_irq
(
pci
->
irq
,
oxygen_interrupt
,
IRQF_SHARED
,
err
=
request_irq
(
pci
->
irq
,
oxygen_interrupt
,
IRQF_SHARED
,
chip
->
model
.
chip
,
chip
);
DRIVER
,
chip
);
if
(
err
<
0
)
{
if
(
err
<
0
)
{
snd_printk
(
KERN_ERR
"cannot grab interrupt %d
\n
"
,
pci
->
irq
);
snd_printk
(
KERN_ERR
"cannot grab interrupt %d
\n
"
,
pci
->
irq
);
goto
err_card
;
goto
err_card
;
...
...
sound/pci/oxygen/virtuoso.c
View file @
b54fc8dd
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment