diff options
Diffstat (limited to 'sound/pci/oxygen/virtuoso.c')
| -rw-r--r-- | sound/pci/oxygen/virtuoso.c | 594 |
1 files changed, 398 insertions, 196 deletions
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index d163397b85cc..7f84fa5deca2 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
| @@ -18,6 +18,9 @@ | |||
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | /* | 20 | /* |
| 21 | * Xonar D2/D2X | ||
| 22 | * ------------ | ||
| 23 | * | ||
| 21 | * CMI8788: | 24 | * CMI8788: |
| 22 | * | 25 | * |
| 23 | * SPI 0 -> 1st PCM1796 (front) | 26 | * SPI 0 -> 1st PCM1796 (front) |
| @@ -30,10 +33,33 @@ | |||
| 30 | * GPIO 5 <- external power present (D2X only) | 33 | * GPIO 5 <- external power present (D2X only) |
| 31 | * GPIO 7 -> ALT | 34 | * GPIO 7 -> ALT |
| 32 | * GPIO 8 -> enable output to speakers | 35 | * GPIO 8 -> enable output to speakers |
| 36 | */ | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Xonar DX | ||
| 40 | * -------- | ||
| 41 | * | ||
| 42 | * CMI8788: | ||
| 43 | * | ||
| 44 | * I²C <-> CS4398 (front) | ||
| 45 | * <-> CS4362A (surround, center/LFE, back) | ||
| 46 | * | ||
| 47 | * GPI 0 <- external power present | ||
| 33 | * | 48 | * |
| 34 | * CM9780: | 49 | * GPIO 0 -> enable output to speakers |
| 50 | * GPIO 1 -> enable front panel I/O | ||
| 51 | * GPIO 2 -> M0 of CS5361 | ||
| 52 | * GPIO 3 -> M1 of CS5361 | ||
| 53 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
| 35 | * | 54 | * |
| 36 | * GPIO 0 -> enable AC'97 bypass (line in -> ADC) | 55 | * CS4398: |
| 56 | * | ||
| 57 | * AD0 <- 1 | ||
| 58 | * AD1 <- 1 | ||
| 59 | * | ||
| 60 | * CS4362A: | ||
| 61 | * | ||
| 62 | * AD0 <- 0 | ||
| 37 | */ | 63 | */ |
| 38 | 64 | ||
| 39 | #include <linux/pci.h> | 65 | #include <linux/pci.h> |
| @@ -47,11 +73,14 @@ | |||
| 47 | #include <sound/tlv.h> | 73 | #include <sound/tlv.h> |
| 48 | #include "oxygen.h" | 74 | #include "oxygen.h" |
| 49 | #include "cm9780.h" | 75 | #include "cm9780.h" |
| 76 | #include "pcm1796.h" | ||
| 77 | #include "cs4398.h" | ||
| 78 | #include "cs4362a.h" | ||
| 50 | 79 | ||
| 51 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 80 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
| 52 | MODULE_DESCRIPTION("Asus AV200 driver"); | 81 | MODULE_DESCRIPTION("Asus AVx00 driver"); |
| 53 | MODULE_LICENSE("GPL"); | 82 | MODULE_LICENSE("GPL"); |
| 54 | MODULE_SUPPORTED_DEVICE("{{Asus,AV200}}"); | 83 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); |
| 55 | 84 | ||
| 56 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 85 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| 57 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 86 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
| @@ -64,80 +93,44 @@ MODULE_PARM_DESC(id, "ID string"); | |||
| 64 | module_param_array(enable, bool, NULL, 0444); | 93 | module_param_array(enable, bool, NULL, 0444); |
| 65 | MODULE_PARM_DESC(enable, "enable card"); | 94 | MODULE_PARM_DESC(enable, "enable card"); |
| 66 | 95 | ||
| 96 | enum { | ||
| 97 | MODEL_D2, | ||
| 98 | MODEL_D2X, | ||
| 99 | MODEL_DX, | ||
| 100 | }; | ||
| 101 | |||
| 67 | static struct pci_device_id xonar_ids[] __devinitdata = { | 102 | static struct pci_device_id xonar_ids[] __devinitdata = { |
| 68 | { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, /* Asus Xonar D2 */ | 103 | { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 }, |
| 69 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, /* Asus Xonar D2X */ | 104 | { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, |
| 105 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, | ||
| 70 | { } | 106 | { } |
| 71 | }; | 107 | }; |
| 72 | MODULE_DEVICE_TABLE(pci, xonar_ids); | 108 | MODULE_DEVICE_TABLE(pci, xonar_ids); |
| 73 | 109 | ||
| 74 | 110 | ||
| 75 | #define GPIO_CS5381_M_MASK 0x000c | 111 | #define GPIO_CS53x1_M_MASK 0x000c |
| 76 | #define GPIO_CS5381_M_SINGLE 0x0000 | 112 | #define GPIO_CS53x1_M_SINGLE 0x0000 |
| 77 | #define GPIO_CS5381_M_DOUBLE 0x0004 | 113 | #define GPIO_CS53x1_M_DOUBLE 0x0004 |
| 78 | #define GPIO_CS5381_M_QUAD 0x0008 | 114 | #define GPIO_CS53x1_M_QUAD 0x0008 |
| 79 | #define GPIO_EXT_POWER 0x0020 | 115 | |
| 80 | #define GPIO_ALT 0x0080 | 116 | #define GPIO_D2X_EXT_POWER 0x0020 |
| 81 | #define GPIO_OUTPUT_ENABLE 0x0100 | 117 | #define GPIO_D2_ALT 0x0080 |
| 82 | 118 | #define GPIO_D2_OUTPUT_ENABLE 0x0100 | |
| 83 | #define GPIO_LINE_MUTE CM9780_GPO0 | 119 | |
| 84 | 120 | #define GPI_DX_EXT_POWER 0x01 | |
| 85 | /* register 16 */ | 121 | #define GPIO_DX_OUTPUT_ENABLE 0x0001 |
| 86 | #define PCM1796_ATL_MASK 0xff | 122 | #define GPIO_DX_FRONT_PANEL 0x0002 |
| 87 | /* register 17 */ | 123 | #define GPIO_DX_INPUT_ROUTE 0x0100 |
| 88 | #define PCM1796_ATR_MASK 0xff | 124 | |
| 89 | /* register 18 */ | 125 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ |
| 90 | #define PCM1796_MUTE 0x01 | 126 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ |
| 91 | #define PCM1796_DME 0x02 | ||
| 92 | #define PCM1796_DMF_MASK 0x0c | ||
| 93 | #define PCM1796_DMF_DISABLED 0x00 | ||
| 94 | #define PCM1796_DMF_48 0x04 | ||
| 95 | #define PCM1796_DMF_441 0x08 | ||
| 96 | #define PCM1796_DMF_32 0x0c | ||
| 97 | #define PCM1796_FMT_MASK 0x70 | ||
| 98 | #define PCM1796_FMT_16_RJUST 0x00 | ||
| 99 | #define PCM1796_FMT_20_RJUST 0x10 | ||
| 100 | #define PCM1796_FMT_24_RJUST 0x20 | ||
| 101 | #define PCM1796_FMT_24_LJUST 0x30 | ||
| 102 | #define PCM1796_FMT_16_I2S 0x40 | ||
| 103 | #define PCM1796_FMT_24_I2S 0x50 | ||
| 104 | #define PCM1796_ATLD 0x80 | ||
| 105 | /* register 19 */ | ||
| 106 | #define PCM1796_INZD 0x01 | ||
| 107 | #define PCM1796_FLT_MASK 0x02 | ||
| 108 | #define PCM1796_FLT_SHARP 0x00 | ||
| 109 | #define PCM1796_FLT_SLOW 0x02 | ||
| 110 | #define PCM1796_DFMS 0x04 | ||
| 111 | #define PCM1796_OPE 0x10 | ||
| 112 | #define PCM1796_ATS_MASK 0x60 | ||
| 113 | #define PCM1796_ATS_1 0x00 | ||
| 114 | #define PCM1796_ATS_2 0x20 | ||
| 115 | #define PCM1796_ATS_4 0x40 | ||
| 116 | #define PCM1796_ATS_8 0x60 | ||
| 117 | #define PCM1796_REV 0x80 | ||
| 118 | /* register 20 */ | ||
| 119 | #define PCM1796_OS_MASK 0x03 | ||
| 120 | #define PCM1796_OS_64 0x00 | ||
| 121 | #define PCM1796_OS_32 0x01 | ||
| 122 | #define PCM1796_OS_128 0x02 | ||
| 123 | #define PCM1796_CHSL_MASK 0x04 | ||
| 124 | #define PCM1796_CHSL_LEFT 0x00 | ||
| 125 | #define PCM1796_CHSL_RIGHT 0x04 | ||
| 126 | #define PCM1796_MONO 0x08 | ||
| 127 | #define PCM1796_DFTH 0x10 | ||
| 128 | #define PCM1796_DSD 0x20 | ||
| 129 | #define PCM1796_SRST 0x40 | ||
| 130 | /* register 21 */ | ||
| 131 | #define PCM1796_PCMZ 0x01 | ||
| 132 | #define PCM1796_DZ_MASK 0x06 | ||
| 133 | /* register 22 */ | ||
| 134 | #define PCM1796_ZFGL 0x01 | ||
| 135 | #define PCM1796_ZFGR 0x02 | ||
| 136 | /* register 23 */ | ||
| 137 | #define PCM1796_ID_MASK 0x1f | ||
| 138 | 127 | ||
| 139 | struct xonar_data { | 128 | struct xonar_data { |
| 140 | u8 is_d2x; | 129 | unsigned int anti_pop_delay; |
| 130 | u16 output_enable_bit; | ||
| 131 | u8 ext_power_reg; | ||
| 132 | u8 ext_power_int_reg; | ||
| 133 | u8 ext_power_bit; | ||
| 141 | u8 has_power; | 134 | u8 has_power; |
| 142 | }; | 135 | }; |
| 143 | 136 | ||
| @@ -156,62 +149,157 @@ static void pcm1796_write(struct oxygen *chip, unsigned int codec, | |||
| 156 | (reg << 8) | value); | 149 | (reg << 8) | value); |
| 157 | } | 150 | } |
| 158 | 151 | ||
| 159 | static void xonar_init(struct oxygen *chip) | 152 | static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) |
| 153 | { | ||
| 154 | oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) | ||
| 158 | { | ||
| 159 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); | ||
| 160 | } | ||
| 161 | |||
| 162 | static void xonar_common_init(struct oxygen *chip) | ||
| 163 | { | ||
| 164 | struct xonar_data *data = chip->model_data; | ||
| 165 | |||
| 166 | if (data->ext_power_reg) { | ||
| 167 | oxygen_set_bits8(chip, data->ext_power_int_reg, | ||
| 168 | data->ext_power_bit); | ||
| 169 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | ||
| 170 | data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) | ||
| 171 | & data->ext_power_bit); | ||
| 172 | } | ||
| 173 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); | ||
| 174 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
| 175 | GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); | ||
| 176 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | ||
| 177 | msleep(data->anti_pop_delay); | ||
| 178 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); | ||
| 179 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); | ||
| 180 | } | ||
| 181 | |||
| 182 | static void xonar_d2_init(struct oxygen *chip) | ||
| 160 | { | 183 | { |
| 161 | struct xonar_data *data = chip->model_data; | 184 | struct xonar_data *data = chip->model_data; |
| 162 | unsigned int i; | 185 | unsigned int i; |
| 163 | 186 | ||
| 164 | data->is_d2x = chip->pci->subsystem_device == 0x82b7; | 187 | data->anti_pop_delay = 300; |
| 188 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | ||
| 165 | 189 | ||
| 166 | for (i = 0; i < 4; ++i) { | 190 | for (i = 0; i < 4; ++i) { |
| 167 | pcm1796_write(chip, i, 18, PCM1796_FMT_24_LJUST | PCM1796_ATLD); | 191 | pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED | |
| 192 | PCM1796_FMT_24_LJUST | PCM1796_ATLD); | ||
| 168 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | 193 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); |
| 169 | pcm1796_write(chip, i, 20, PCM1796_OS_64); | 194 | pcm1796_write(chip, i, 20, PCM1796_OS_64); |
| 170 | pcm1796_write(chip, i, 21, 0); | 195 | pcm1796_write(chip, i, 21, 0); |
| 171 | pcm1796_write(chip, i, 16, 0xff); /* set ATL/ATR after ATLD */ | 196 | pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */ |
| 172 | pcm1796_write(chip, i, 17, 0xff); | 197 | pcm1796_write(chip, i, 17, 0x0f); |
| 173 | } | 198 | } |
| 174 | 199 | ||
| 175 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | 200 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); |
| 176 | GPIO_CS5381_M_MASK | GPIO_ALT); | 201 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); |
| 177 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | 202 | |
| 178 | GPIO_CS5381_M_SINGLE, | 203 | xonar_common_init(chip); |
| 179 | GPIO_CS5381_M_MASK | GPIO_ALT); | ||
| 180 | if (data->is_d2x) { | ||
| 181 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
| 182 | GPIO_EXT_POWER); | ||
| 183 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, | ||
| 184 | GPIO_EXT_POWER); | ||
| 185 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | ||
| 186 | data->has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) | ||
| 187 | & GPIO_EXT_POWER); | ||
| 188 | } | ||
| 189 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | ||
| 190 | oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE); | ||
| 191 | msleep(300); | ||
| 192 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_OUTPUT_ENABLE); | ||
| 193 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
| 194 | 204 | ||
| 195 | snd_component_add(chip->card, "PCM1796"); | 205 | snd_component_add(chip->card, "PCM1796"); |
| 196 | snd_component_add(chip->card, "CS5381"); | 206 | snd_component_add(chip->card, "CS5381"); |
| 197 | } | 207 | } |
| 198 | 208 | ||
| 209 | static void xonar_d2x_init(struct oxygen *chip) | ||
| 210 | { | ||
| 211 | struct xonar_data *data = chip->model_data; | ||
| 212 | |||
| 213 | data->ext_power_reg = OXYGEN_GPIO_DATA; | ||
| 214 | data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; | ||
| 215 | data->ext_power_bit = GPIO_D2X_EXT_POWER; | ||
| 216 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER); | ||
| 217 | xonar_d2_init(chip); | ||
| 218 | } | ||
| 219 | |||
| 220 | static void xonar_dx_init(struct oxygen *chip) | ||
| 221 | { | ||
| 222 | struct xonar_data *data = chip->model_data; | ||
| 223 | |||
| 224 | data->anti_pop_delay = 800; | ||
| 225 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | ||
| 226 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
| 227 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
| 228 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
| 229 | |||
| 230 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
| 231 | OXYGEN_2WIRE_LENGTH_8 | | ||
| 232 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
| 233 | OXYGEN_2WIRE_SPEED_FAST); | ||
| 234 | |||
| 235 | /* set CPEN (control port mode) and power down */ | ||
| 236 | cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); | ||
| 237 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); | ||
| 238 | /* configure */ | ||
| 239 | cs4398_write(chip, 2, CS4398_FM_SINGLE | | ||
| 240 | CS4398_DEM_NONE | CS4398_DIF_LJUST); | ||
| 241 | cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); | ||
| 242 | cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE); | ||
| 243 | cs4398_write(chip, 5, 0xfe); | ||
| 244 | cs4398_write(chip, 6, 0xfe); | ||
| 245 | cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | | ||
| 246 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); | ||
| 247 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); | ||
| 248 | cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | | ||
| 249 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); | ||
| 250 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); | ||
| 251 | cs4362a_write(chip, 0x05, 0); | ||
| 252 | cs4362a_write(chip, 0x06, CS4362A_FM_SINGLE | | ||
| 253 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
| 254 | cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE); | ||
| 255 | cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE); | ||
| 256 | cs4362a_write(chip, 0x09, CS4362A_FM_SINGLE | | ||
| 257 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
| 258 | cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE); | ||
| 259 | cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE); | ||
| 260 | cs4362a_write(chip, 0x0c, CS4362A_FM_SINGLE | | ||
| 261 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
| 262 | cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE); | ||
| 263 | cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE); | ||
| 264 | /* clear power down */ | ||
| 265 | cs4398_write(chip, 8, CS4398_CPEN); | ||
| 266 | cs4362a_write(chip, 0x01, CS4362A_CPEN); | ||
| 267 | |||
| 268 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
| 269 | GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); | ||
| 270 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | ||
| 271 | GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); | ||
| 272 | |||
| 273 | xonar_common_init(chip); | ||
| 274 | |||
| 275 | snd_component_add(chip->card, "CS4398"); | ||
| 276 | snd_component_add(chip->card, "CS4362A"); | ||
| 277 | snd_component_add(chip->card, "CS5361"); | ||
| 278 | } | ||
| 279 | |||
| 199 | static void xonar_cleanup(struct oxygen *chip) | 280 | static void xonar_cleanup(struct oxygen *chip) |
| 200 | { | 281 | { |
| 201 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | 282 | struct xonar_data *data = chip->model_data; |
| 283 | |||
| 284 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); | ||
| 285 | } | ||
| 286 | |||
| 287 | static void xonar_dx_cleanup(struct oxygen *chip) | ||
| 288 | { | ||
| 289 | xonar_cleanup(chip); | ||
| 290 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); | ||
| 291 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); | ||
| 202 | } | 292 | } |
| 203 | 293 | ||
| 204 | static void set_pcm1796_params(struct oxygen *chip, | 294 | static void set_pcm1796_params(struct oxygen *chip, |
| 205 | struct snd_pcm_hw_params *params) | 295 | struct snd_pcm_hw_params *params) |
| 206 | { | 296 | { |
| 207 | #if 0 | ||
| 208 | unsigned int i; | 297 | unsigned int i; |
| 209 | u8 value; | 298 | u8 value; |
| 210 | 299 | ||
| 211 | value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | 300 | value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; |
| 212 | for (i = 0; i < 4; ++i) | 301 | for (i = 0; i < 4; ++i) |
| 213 | pcm1796_write(chip, i, 20, value); | 302 | pcm1796_write(chip, i, 20, value); |
| 214 | #endif | ||
| 215 | } | 303 | } |
| 216 | 304 | ||
| 217 | static void update_pcm1796_volume(struct oxygen *chip) | 305 | static void update_pcm1796_volume(struct oxygen *chip) |
| @@ -236,19 +324,73 @@ static void update_pcm1796_mute(struct oxygen *chip) | |||
| 236 | pcm1796_write(chip, i, 18, value); | 324 | pcm1796_write(chip, i, 18, value); |
| 237 | } | 325 | } |
| 238 | 326 | ||
| 239 | static void set_cs5381_params(struct oxygen *chip, | 327 | static void set_cs53x1_params(struct oxygen *chip, |
| 240 | struct snd_pcm_hw_params *params) | 328 | struct snd_pcm_hw_params *params) |
| 241 | { | 329 | { |
| 242 | unsigned int value; | 330 | unsigned int value; |
| 243 | 331 | ||
| 244 | if (params_rate(params) <= 54000) | 332 | if (params_rate(params) <= 54000) |
| 245 | value = GPIO_CS5381_M_SINGLE; | 333 | value = GPIO_CS53x1_M_SINGLE; |
| 246 | else if (params_rate(params) <= 108000) | 334 | else if (params_rate(params) <= 108000) |
| 247 | value = GPIO_CS5381_M_DOUBLE; | 335 | value = GPIO_CS53x1_M_DOUBLE; |
| 248 | else | 336 | else |
| 249 | value = GPIO_CS5381_M_QUAD; | 337 | value = GPIO_CS53x1_M_QUAD; |
| 250 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | 338 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, |
| 251 | value, GPIO_CS5381_M_MASK); | 339 | value, GPIO_CS53x1_M_MASK); |
| 340 | } | ||
| 341 | |||
| 342 | static void set_cs43xx_params(struct oxygen *chip, | ||
| 343 | struct snd_pcm_hw_params *params) | ||
| 344 | { | ||
| 345 | u8 fm_cs4398, fm_cs4362a; | ||
| 346 | |||
| 347 | fm_cs4398 = CS4398_DEM_NONE | CS4398_DIF_LJUST; | ||
| 348 | fm_cs4362a = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | ||
| 349 | if (params_rate(params) <= 50000) { | ||
| 350 | fm_cs4398 |= CS4398_FM_SINGLE; | ||
| 351 | fm_cs4362a |= CS4362A_FM_SINGLE; | ||
| 352 | } else if (params_rate(params) <= 100000) { | ||
| 353 | fm_cs4398 |= CS4398_FM_DOUBLE; | ||
| 354 | fm_cs4362a |= CS4362A_FM_DOUBLE; | ||
| 355 | } else { | ||
| 356 | fm_cs4398 |= CS4398_FM_QUAD; | ||
| 357 | fm_cs4362a |= CS4362A_FM_QUAD; | ||
| 358 | } | ||
| 359 | cs4398_write(chip, 2, fm_cs4398); | ||
| 360 | cs4362a_write(chip, 0x06, fm_cs4362a); | ||
| 361 | cs4362a_write(chip, 0x09, fm_cs4362a); | ||
| 362 | cs4362a_write(chip, 0x0c, fm_cs4362a); | ||
| 363 | } | ||
| 364 | |||
| 365 | static void update_cs4362a_volumes(struct oxygen *chip) | ||
| 366 | { | ||
| 367 | u8 mute; | ||
| 368 | |||
| 369 | mute = chip->dac_mute ? CS4362A_MUTE : 0; | ||
| 370 | cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); | ||
| 371 | cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); | ||
| 372 | cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); | ||
| 373 | cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); | ||
| 374 | cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); | ||
| 375 | cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); | ||
| 376 | } | ||
| 377 | |||
| 378 | static void update_cs43xx_volume(struct oxygen *chip) | ||
| 379 | { | ||
| 380 | cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); | ||
| 381 | cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); | ||
| 382 | update_cs4362a_volumes(chip); | ||
| 383 | } | ||
| 384 | |||
| 385 | static void update_cs43xx_mute(struct oxygen *chip) | ||
| 386 | { | ||
| 387 | u8 reg; | ||
| 388 | |||
| 389 | reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; | ||
| 390 | if (chip->dac_mute) | ||
| 391 | reg |= CS4398_MUTE_B | CS4398_MUTE_A; | ||
| 392 | cs4398_write(chip, 4, reg); | ||
| 393 | update_cs4362a_volumes(chip); | ||
| 252 | } | 394 | } |
| 253 | 395 | ||
| 254 | static void xonar_gpio_changed(struct oxygen *chip) | 396 | static void xonar_gpio_changed(struct oxygen *chip) |
| @@ -256,10 +398,8 @@ static void xonar_gpio_changed(struct oxygen *chip) | |||
| 256 | struct xonar_data *data = chip->model_data; | 398 | struct xonar_data *data = chip->model_data; |
| 257 | u8 has_power; | 399 | u8 has_power; |
| 258 | 400 | ||
| 259 | if (!data->is_d2x) | 401 | has_power = !!(oxygen_read8(chip, data->ext_power_reg) |
| 260 | return; | 402 | & data->ext_power_bit); |
| 261 | has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) | ||
| 262 | & GPIO_EXT_POWER); | ||
| 263 | if (has_power != data->has_power) { | 403 | if (has_power != data->has_power) { |
| 264 | data->has_power = has_power; | 404 | data->has_power = has_power; |
| 265 | if (has_power) { | 405 | if (has_power) { |
| @@ -272,66 +412,13 @@ static void xonar_gpio_changed(struct oxygen *chip) | |||
| 272 | } | 412 | } |
| 273 | } | 413 | } |
| 274 | 414 | ||
| 275 | static void mute_ac97_ctl(struct oxygen *chip, unsigned int control) | ||
| 276 | { | ||
| 277 | unsigned int index = chip->controls[control]->private_value & 0xff; | ||
| 278 | u16 value; | ||
| 279 | |||
| 280 | value = oxygen_read_ac97(chip, 0, index); | ||
| 281 | if (!(value & 0x8000)) { | ||
| 282 | oxygen_write_ac97(chip, 0, index, value | 0x8000); | ||
| 283 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 284 | &chip->controls[control]->id); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | static void xonar_ac97_switch_hook(struct oxygen *chip, unsigned int codec, | ||
| 289 | unsigned int reg, int mute) | ||
| 290 | { | ||
| 291 | if (codec != 0) | ||
| 292 | return; | ||
| 293 | /* line-in is exclusive */ | ||
| 294 | switch (reg) { | ||
| 295 | case AC97_LINE: | ||
| 296 | oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, | ||
| 297 | mute ? GPIO_LINE_MUTE : 0, | ||
| 298 | GPIO_LINE_MUTE); | ||
| 299 | if (!mute) { | ||
| 300 | mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); | ||
| 301 | mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); | ||
| 302 | mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH); | ||
| 303 | } | ||
| 304 | break; | ||
| 305 | case AC97_MIC: | ||
| 306 | case AC97_CD: | ||
| 307 | case AC97_VIDEO: | ||
| 308 | case AC97_AUX: | ||
| 309 | if (!mute) { | ||
| 310 | oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_STATUS, | ||
| 311 | GPIO_LINE_MUTE); | ||
| 312 | mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); | ||
| 313 | } | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | static int pcm1796_volume_info(struct snd_kcontrol *ctl, | ||
| 319 | struct snd_ctl_elem_info *info) | ||
| 320 | { | ||
| 321 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 322 | info->count = 8; | ||
| 323 | info->value.integer.min = 0x0f; | ||
| 324 | info->value.integer.max = 0xff; | ||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | static int alt_switch_get(struct snd_kcontrol *ctl, | 415 | static int alt_switch_get(struct snd_kcontrol *ctl, |
| 329 | struct snd_ctl_elem_value *value) | 416 | struct snd_ctl_elem_value *value) |
| 330 | { | 417 | { |
| 331 | struct oxygen *chip = ctl->private_data; | 418 | struct oxygen *chip = ctl->private_data; |
| 332 | 419 | ||
| 333 | value->value.integer.value[0] = | 420 | value->value.integer.value[0] = |
| 334 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_ALT); | 421 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_D2_ALT); |
| 335 | return 0; | 422 | return 0; |
| 336 | } | 423 | } |
| 337 | 424 | ||
| @@ -345,9 +432,9 @@ static int alt_switch_put(struct snd_kcontrol *ctl, | |||
| 345 | spin_lock_irq(&chip->reg_lock); | 432 | spin_lock_irq(&chip->reg_lock); |
| 346 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | 433 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); |
| 347 | if (value->value.integer.value[0]) | 434 | if (value->value.integer.value[0]) |
| 348 | new_bits = old_bits | GPIO_ALT; | 435 | new_bits = old_bits | GPIO_D2_ALT; |
| 349 | else | 436 | else |
| 350 | new_bits = old_bits & ~GPIO_ALT; | 437 | new_bits = old_bits & ~GPIO_D2_ALT; |
| 351 | changed = new_bits != old_bits; | 438 | changed = new_bits != old_bits; |
| 352 | if (changed) | 439 | if (changed) |
| 353 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); | 440 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); |
| @@ -363,20 +450,68 @@ static const struct snd_kcontrol_new alt_switch = { | |||
| 363 | .put = alt_switch_put, | 450 | .put = alt_switch_put, |
| 364 | }; | 451 | }; |
| 365 | 452 | ||
| 453 | static int front_panel_get(struct snd_kcontrol *ctl, | ||
| 454 | struct snd_ctl_elem_value *value) | ||
| 455 | { | ||
| 456 | struct oxygen *chip = ctl->private_data; | ||
| 457 | |||
| 458 | value->value.integer.value[0] = | ||
| 459 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DX_FRONT_PANEL); | ||
| 460 | return 0; | ||
| 461 | } | ||
| 462 | |||
| 463 | static int front_panel_put(struct snd_kcontrol *ctl, | ||
| 464 | struct snd_ctl_elem_value *value) | ||
| 465 | { | ||
| 466 | struct oxygen *chip = ctl->private_data; | ||
| 467 | u16 old_reg, new_reg; | ||
| 468 | |||
| 469 | spin_lock_irq(&chip->reg_lock); | ||
| 470 | old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
| 471 | if (value->value.integer.value[0]) | ||
| 472 | new_reg = old_reg | GPIO_DX_FRONT_PANEL; | ||
| 473 | else | ||
| 474 | new_reg = old_reg & ~GPIO_DX_FRONT_PANEL; | ||
| 475 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); | ||
| 476 | spin_unlock_irq(&chip->reg_lock); | ||
| 477 | return old_reg != new_reg; | ||
| 478 | } | ||
| 479 | |||
| 480 | static const struct snd_kcontrol_new front_panel_switch = { | ||
| 481 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 482 | .name = "Front Panel Switch", | ||
| 483 | .info = snd_ctl_boolean_mono_info, | ||
| 484 | .get = front_panel_get, | ||
| 485 | .put = front_panel_put, | ||
| 486 | }; | ||
| 487 | |||
| 488 | static void xonar_dx_ac97_switch(struct oxygen *chip, | ||
| 489 | unsigned int reg, unsigned int mute) | ||
| 490 | { | ||
| 491 | if (reg == AC97_LINE) { | ||
| 492 | spin_lock_irq(&chip->reg_lock); | ||
| 493 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
| 494 | mute ? GPIO_DX_INPUT_ROUTE : 0, | ||
| 495 | GPIO_DX_INPUT_ROUTE); | ||
| 496 | spin_unlock_irq(&chip->reg_lock); | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 366 | static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0); | 500 | static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0); |
| 501 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0); | ||
| 367 | 502 | ||
| 368 | static int xonar_control_filter(struct snd_kcontrol_new *template) | 503 | static int xonar_d2_control_filter(struct snd_kcontrol_new *template) |
| 369 | { | 504 | { |
| 370 | if (!strcmp(template->name, "Master Playback Volume")) { | 505 | if (!strncmp(template->name, "CD Capture ", 11)) |
| 371 | template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
| 372 | template->info = pcm1796_volume_info, | ||
| 373 | template->tlv.p = pcm1796_db_scale; | ||
| 374 | } else if (!strncmp(template->name, "CD Capture ", 11)) { | ||
| 375 | /* CD in is actually connected to the video in pin */ | 506 | /* CD in is actually connected to the video in pin */ |
| 376 | template->private_value ^= AC97_CD ^ AC97_VIDEO; | 507 | template->private_value ^= AC97_CD ^ AC97_VIDEO; |
| 377 | } else if (!strcmp(template->name, "Line Capture Volume")) { | 508 | return 0; |
| 378 | return 1; /* line-in bypasses the AC'97 mixer */ | 509 | } |
| 379 | } | 510 | |
| 511 | static int xonar_dx_control_filter(struct snd_kcontrol_new *template) | ||
| 512 | { | ||
| 513 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
| 514 | return 1; /* no CD input */ | ||
| 380 | return 0; | 515 | return 0; |
| 381 | } | 516 | } |
| 382 | 517 | ||
| @@ -385,30 +520,96 @@ static int xonar_mixer_init(struct oxygen *chip) | |||
| 385 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | 520 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); |
| 386 | } | 521 | } |
| 387 | 522 | ||
| 388 | static const struct oxygen_model model_xonar = { | 523 | static int xonar_dx_mixer_init(struct oxygen *chip) |
| 389 | .shortname = "Asus AV200", | 524 | { |
| 390 | .longname = "Asus Virtuoso 200", | 525 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); |
| 391 | .chip = "AV200", | 526 | } |
| 392 | .owner = THIS_MODULE, | 527 | |
| 393 | .init = xonar_init, | 528 | static const struct oxygen_model xonar_models[] = { |
| 394 | .control_filter = xonar_control_filter, | 529 | [MODEL_D2] = { |
| 395 | .mixer_init = xonar_mixer_init, | 530 | .shortname = "Xonar D2", |
| 396 | .cleanup = xonar_cleanup, | 531 | .longname = "Asus Virtuoso 200", |
| 397 | .set_dac_params = set_pcm1796_params, | 532 | .chip = "AV200", |
| 398 | .set_adc_params = set_cs5381_params, | 533 | .owner = THIS_MODULE, |
| 399 | .update_dac_volume = update_pcm1796_volume, | 534 | .init = xonar_d2_init, |
| 400 | .update_dac_mute = update_pcm1796_mute, | 535 | .control_filter = xonar_d2_control_filter, |
| 401 | .ac97_switch_hook = xonar_ac97_switch_hook, | 536 | .mixer_init = xonar_mixer_init, |
| 402 | .gpio_changed = xonar_gpio_changed, | 537 | .cleanup = xonar_cleanup, |
| 403 | .model_data_size = sizeof(struct xonar_data), | 538 | .set_dac_params = set_pcm1796_params, |
| 404 | .dac_channels = 8, | 539 | .set_adc_params = set_cs53x1_params, |
| 405 | .used_channels = OXYGEN_CHANNEL_B | | 540 | .update_dac_volume = update_pcm1796_volume, |
| 406 | OXYGEN_CHANNEL_C | | 541 | .update_dac_mute = update_pcm1796_mute, |
| 407 | OXYGEN_CHANNEL_SPDIF | | 542 | .dac_tlv = pcm1796_db_scale, |
| 408 | OXYGEN_CHANNEL_MULTICH, | 543 | .model_data_size = sizeof(struct xonar_data), |
| 409 | .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5, | 544 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | |
| 410 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 545 | PLAYBACK_1_TO_SPDIF | |
| 411 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 546 | CAPTURE_0_FROM_I2S_2 | |
| 547 | CAPTURE_1_FROM_SPDIF, | ||
| 548 | .dac_channels = 8, | ||
| 549 | .dac_volume_min = 0x0f, | ||
| 550 | .dac_volume_max = 0xff, | ||
| 551 | .misc_flags = OXYGEN_MISC_MIDI, | ||
| 552 | .function_flags = OXYGEN_FUNCTION_SPI | | ||
| 553 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
| 554 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 555 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 556 | }, | ||
| 557 | [MODEL_D2X] = { | ||
| 558 | .shortname = "Xonar D2X", | ||
| 559 | .longname = "Asus Virtuoso 200", | ||
| 560 | .chip = "AV200", | ||
| 561 | .owner = THIS_MODULE, | ||
| 562 | .init = xonar_d2x_init, | ||
| 563 | .control_filter = xonar_d2_control_filter, | ||
| 564 | .mixer_init = xonar_mixer_init, | ||
| 565 | .cleanup = xonar_cleanup, | ||
| 566 | .set_dac_params = set_pcm1796_params, | ||
| 567 | .set_adc_params = set_cs53x1_params, | ||
| 568 | .update_dac_volume = update_pcm1796_volume, | ||
| 569 | .update_dac_mute = update_pcm1796_mute, | ||
| 570 | .gpio_changed = xonar_gpio_changed, | ||
| 571 | .dac_tlv = pcm1796_db_scale, | ||
| 572 | .model_data_size = sizeof(struct xonar_data), | ||
| 573 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | | ||
| 574 | PLAYBACK_1_TO_SPDIF | | ||
| 575 | CAPTURE_0_FROM_I2S_2 | | ||
| 576 | CAPTURE_1_FROM_SPDIF, | ||
| 577 | .dac_channels = 8, | ||
| 578 | .dac_volume_min = 0x0f, | ||
| 579 | .dac_volume_max = 0xff, | ||
| 580 | .misc_flags = OXYGEN_MISC_MIDI, | ||
| 581 | .function_flags = OXYGEN_FUNCTION_SPI | | ||
| 582 | OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
| 583 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 584 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 585 | }, | ||
| 586 | [MODEL_DX] = { | ||
| 587 | .shortname = "Xonar DX", | ||
| 588 | .longname = "Asus Virtuoso 100", | ||
| 589 | .chip = "AV200", | ||
| 590 | .owner = THIS_MODULE, | ||
| 591 | .init = xonar_dx_init, | ||
| 592 | .control_filter = xonar_dx_control_filter, | ||
| 593 | .mixer_init = xonar_dx_mixer_init, | ||
| 594 | .cleanup = xonar_dx_cleanup, | ||
| 595 | .set_dac_params = set_cs43xx_params, | ||
| 596 | .set_adc_params = set_cs53x1_params, | ||
| 597 | .update_dac_volume = update_cs43xx_volume, | ||
| 598 | .update_dac_mute = update_cs43xx_mute, | ||
| 599 | .gpio_changed = xonar_gpio_changed, | ||
| 600 | .ac97_switch = xonar_dx_ac97_switch, | ||
| 601 | .dac_tlv = cs4362a_db_scale, | ||
| 602 | .model_data_size = sizeof(struct xonar_data), | ||
| 603 | .pcm_dev_cfg = PLAYBACK_0_TO_I2S | | ||
| 604 | PLAYBACK_1_TO_SPDIF | | ||
| 605 | CAPTURE_0_FROM_I2S_2, | ||
| 606 | .dac_channels = 8, | ||
| 607 | .dac_volume_min = 0, | ||
| 608 | .dac_volume_max = 127, | ||
| 609 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
| 610 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 611 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 612 | }, | ||
| 412 | }; | 613 | }; |
| 413 | 614 | ||
| 414 | static int __devinit xonar_probe(struct pci_dev *pci, | 615 | static int __devinit xonar_probe(struct pci_dev *pci, |
| @@ -423,7 +624,8 @@ static int __devinit xonar_probe(struct pci_dev *pci, | |||
| 423 | ++dev; | 624 | ++dev; |
| 424 | return -ENOENT; | 625 | return -ENOENT; |
| 425 | } | 626 | } |
| 426 | err = oxygen_pci_probe(pci, index[dev], id[dev], 1, &model_xonar); | 627 | err = oxygen_pci_probe(pci, index[dev], id[dev], |
| 628 | &xonar_models[pci_id->driver_data]); | ||
| 427 | if (err >= 0) | 629 | if (err >= 0) |
| 428 | ++dev; | 630 | ++dev; |
| 429 | return err; | 631 | return err; |
