]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Takashi Iwai <tiwai@suse.de> |
2 | Subject: ALSA: hda - keep internal structure binary compatibility | |
3 | Patch-mainline: NEVER EVER PUSH THIS EVIL!! | |
4 | References: bnc#497341 | |
5 | ||
6 | Add evil hacks to keep the *INTERNAL* binary compatibility, which | |
7 | agrmodem driver pokes around. We fake the old bus_ops. | |
8 | ||
9 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
10 | ||
11 | --- | |
12 | sound/pci/hda/hda_codec.c | 28 ++++++++++++++++++++++++++++ | |
13 | sound/pci/hda/hda_codec.h | 22 +++++++++++++++++++--- | |
14 | sound/pci/hda/hda_intel.c | 39 ++++++++++++++++++++++++++++----------- | |
15 | 3 files changed, 75 insertions(+), 14 deletions(-) | |
16 | ||
17 | --- a/sound/pci/hda/hda_codec.h | |
18 | +++ b/sound/pci/hda/hda_codec.h | |
19 | @@ -549,6 +549,17 @@ | |
20 | #endif | |
21 | }; | |
22 | ||
23 | +/* old hda_bus_ops struct -- just for really evil binary compatibility issues */ | |
24 | +struct hda_old_bus_ops { | |
25 | + int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, | |
26 | + unsigned int verb, unsigned int parm); | |
27 | + unsigned int (*get_response)(struct hda_codec *codec); | |
28 | + void (*private_free)(struct hda_bus *); | |
29 | +#ifdef CONFIG_SND_HDA_POWER_SAVE | |
30 | + void (*pm_notify)(struct hda_codec *codec); | |
31 | +#endif | |
32 | +}; | |
33 | + | |
34 | /* template to pass to the bus constructor */ | |
35 | struct hda_bus_template { | |
36 | void *private_data; | |
37 | @@ -570,7 +581,7 @@ | |
38 | void *private_data; | |
39 | struct pci_dev *pci; | |
40 | const char *modelname; | |
41 | - struct hda_bus_ops ops; | |
42 | + struct hda_old_bus_ops old_ops; /* old ops; for binary compatibility */ | |
43 | ||
44 | /* codec linked list */ | |
45 | struct list_head codec_list; | |
46 | @@ -581,8 +592,6 @@ | |
47 | ||
48 | /* unsolicited event queue */ | |
49 | struct hda_bus_unsolicited *unsol; | |
50 | - char workq_name[16]; | |
51 | - struct workqueue_struct *workq; /* common workqueue for codecs */ | |
52 | ||
53 | struct snd_info_entry *proc; | |
54 | ||
55 | @@ -594,6 +603,13 @@ | |
56 | unsigned int rirb_error:1; /* error in codec communication */ | |
57 | unsigned int response_reset:1; /* controller was reset */ | |
58 | unsigned int in_reset:1; /* during reset operation */ | |
59 | + | |
60 | + /* real ops */ | |
61 | + struct hda_bus_ops ops; | |
62 | + | |
63 | + /* additional workq stuff */ | |
64 | + char workq_name[16]; | |
65 | + struct workqueue_struct *workq; /* common workqueue for codecs */ | |
66 | }; | |
67 | ||
68 | /* | |
69 | --- a/sound/pci/hda/hda_intel.c | |
70 | +++ b/sound/pci/hda/hda_intel.c | |
71 | @@ -306,9 +306,6 @@ | |
72 | unsigned int period_bytes; /* size of the period in bytes */ | |
73 | unsigned int frags; /* number for period in the play buffer */ | |
74 | unsigned int fifo_size; /* FIFO size */ | |
75 | - unsigned int start_flag: 1; /* stream full start flag */ | |
76 | - unsigned long start_jiffies; /* start + minimum jiffies */ | |
77 | - unsigned long min_jiffies; /* minimum jiffies before position is valid */ | |
78 | ||
79 | void __iomem *sd_addr; /* stream descriptor pointer */ | |
80 | ||
81 | @@ -327,6 +324,7 @@ | |
82 | unsigned int opened :1; | |
83 | unsigned int running :1; | |
84 | unsigned int irq_pending :1; | |
85 | + unsigned int irq_ignore :1; /* not used; just placeholder for compat */ | |
86 | /* | |
87 | * For VIA: | |
88 | * A flag to ensure DMA position is 0 | |
89 | @@ -335,6 +333,14 @@ | |
90 | unsigned int insufficient :1; | |
91 | }; | |
92 | ||
93 | +/* new stuff; moved here to keep bloody binary compatibility */ | |
94 | +struct azx_dev_ext { | |
95 | + unsigned int start_flag: 1; /* stream full start flag */ | |
96 | + unsigned long start_jiffies; /* start + minimum jiffies */ | |
97 | + unsigned long min_jiffies; /* minimum jiffies before position is valid */ | |
98 | + | |
99 | +}; | |
100 | + | |
101 | /* CORB/RIRB */ | |
102 | struct azx_rb { | |
103 | u32 *buf; /* CORB/RIRB buffer | |
104 | @@ -377,7 +383,6 @@ | |
105 | ||
106 | /* HD codec */ | |
107 | unsigned short codec_mask; | |
108 | - int codec_probe_mask; /* copied from probe_mask option */ | |
109 | struct hda_bus *bus; | |
110 | ||
111 | /* CORB/RIRB */ | |
112 | @@ -407,6 +412,10 @@ | |
113 | ||
114 | /* reboot notifier (for mysterious hangup problem at power-down) */ | |
115 | struct notifier_block reboot_notifier; | |
116 | + | |
117 | + /* moved here for binary compatibility */ | |
118 | + struct azx_dev_ext *azx_dev_ext; | |
119 | + int codec_probe_mask; /* copied from probe_mask option */ | |
120 | }; | |
121 | ||
122 | /* driver types */ | |
123 | @@ -1497,6 +1506,7 @@ | |
124 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | |
125 | struct azx *chip = apcm->chip; | |
126 | struct azx_dev *azx_dev = get_azx_dev(substream); | |
127 | + struct azx_dev_ext *azx_dev_ext; | |
128 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | |
129 | struct snd_pcm_runtime *runtime = substream->runtime; | |
130 | unsigned int bufsize, period_bytes, format_val; | |
131 | @@ -1531,7 +1541,8 @@ | |
132 | return err; | |
133 | } | |
134 | ||
135 | - azx_dev->min_jiffies = (runtime->period_size * HZ) / | |
136 | + azx_dev_ext = &chip->azx_dev_ext[azx_dev->index]; | |
137 | + azx_dev_ext->min_jiffies = (runtime->period_size * HZ) / | |
138 | (runtime->rate * 2); | |
139 | azx_setup_controller(chip, azx_dev); | |
140 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
141 | @@ -1548,6 +1559,7 @@ | |
142 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | |
143 | struct azx *chip = apcm->chip; | |
144 | struct azx_dev *azx_dev; | |
145 | + struct azx_dev_ext *azx_dev_ext; | |
146 | struct snd_pcm_substream *s; | |
147 | int rstart = 0, start, nsync = 0, sbits = 0; | |
148 | int nwait, timeout; | |
149 | @@ -1586,9 +1598,10 @@ | |
150 | if (s->pcm->card != substream->pcm->card) | |
151 | continue; | |
152 | azx_dev = get_azx_dev(s); | |
153 | + azx_dev_ext = &chip->azx_dev_ext[azx_dev->index]; | |
154 | if (rstart) { | |
155 | - azx_dev->start_flag = 1; | |
156 | - azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies; | |
157 | + azx_dev_ext->start_flag = 1; | |
158 | + azx_dev_ext->start_jiffies = jiffies + azx_dev_ext->min_jiffies; | |
159 | } | |
160 | if (start) | |
161 | azx_stream_start(chip, azx_dev); | |
162 | @@ -1738,11 +1751,12 @@ | |
163 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | |
164 | { | |
165 | unsigned int pos; | |
166 | + struct azx_dev_ext *azx_dev_ext = &chip->azx_dev_ext[azx_dev->index]; | |
167 | ||
168 | - if (azx_dev->start_flag && | |
169 | - time_before_eq(jiffies, azx_dev->start_jiffies)) | |
170 | + if (azx_dev_ext->start_flag && | |
171 | + time_before_eq(jiffies, azx_dev_ext->start_jiffies)) | |
172 | return -1; /* bogus (too early) interrupt */ | |
173 | - azx_dev->start_flag = 0; | |
174 | + azx_dev_ext->start_flag = 0; | |
175 | ||
176 | pos = azx_get_position(chip, azx_dev); | |
177 | if (chip->position_fix == POS_FIX_AUTO) { | |
178 | @@ -2144,6 +2158,7 @@ | |
179 | pci_release_regions(chip->pci); | |
180 | pci_disable_device(chip->pci); | |
181 | kfree(chip->azx_dev); | |
182 | + kfree(chip->azx_dev_ext); | |
183 | kfree(chip); | |
184 | ||
185 | return 0; | |
186 | @@ -2376,7 +2391,9 @@ | |
187 | chip->num_streams = chip->playback_streams + chip->capture_streams; | |
188 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), | |
189 | GFP_KERNEL); | |
190 | - if (!chip->azx_dev) { | |
191 | + chip->azx_dev_ext = kcalloc(chip->num_streams, | |
192 | + sizeof(*chip->azx_dev_ext), GFP_KERNEL); | |
193 | + if (!chip->azx_dev || !chip->azx_dev_ext) { | |
194 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); | |
195 | goto errout; | |
196 | } | |
197 | --- a/sound/pci/hda/hda_codec.c | |
198 | +++ b/sound/pci/hda/hda_codec.c | |
199 | @@ -485,6 +485,28 @@ | |
200 | return snd_hda_bus_free(bus); | |
201 | } | |
202 | ||
203 | +/* | |
204 | + * backward-compatible ops | |
205 | + */ | |
206 | +static int old_bus_ops_command(struct hda_codec *codec, hda_nid_t nid, | |
207 | + int direct, unsigned int verb, unsigned int parm) | |
208 | +{ | |
209 | + unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); | |
210 | + return codec->bus->ops.command(codec->bus, cmd); | |
211 | +} | |
212 | + | |
213 | +static unsigned int old_bus_ops_get_response(struct hda_codec *codec) | |
214 | +{ | |
215 | + return codec->bus->ops.get_response(codec->bus); | |
216 | +} | |
217 | + | |
218 | +#ifdef CONFIG_SND_HDA_POWER_SAVE | |
219 | +static void old_bus_ops_pm_notify(struct hda_codec *codec) | |
220 | +{ | |
221 | + codec->bus->ops.pm_notify(codec->bus); | |
222 | +} | |
223 | +#endif | |
224 | + | |
225 | /** | |
226 | * snd_hda_bus_new - create a HDA bus | |
227 | * @card: the card entry | |
228 | @@ -520,6 +542,12 @@ | |
229 | bus->pci = temp->pci; | |
230 | bus->modelname = temp->modelname; | |
231 | bus->ops = temp->ops; | |
232 | + bus->old_ops.command = old_bus_ops_command; | |
233 | + bus->old_ops.get_response = old_bus_ops_get_response; | |
234 | + bus->old_ops.private_free = bus->ops.private_free; | |
235 | +#ifdef CONFIG_SND_HDA_POWER_SAVE | |
236 | + bus->old_ops.pm_notify = old_bus_ops_pm_notify; | |
237 | +#endif | |
238 | ||
239 | mutex_init(&bus->cmd_mutex); | |
240 | INIT_LIST_HEAD(&bus->codec_list); |