Commit f7467452291f7c9e5e1271e8c8e45b77f34b1257
Committed by
Takashi Iwai
1 parent
bb617ee3f8
Exists in
master
and in
7 other branches
ALSA: lx6464es - make 1 bit signed bitfield unsigned
converts a 1 bit signed bitfield to an unsigned. Reported-by: Dr. David Alan Gilbert <linux@treblig.org> Signed-off-by: Tim Blechmann <tim@klingt.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 3 changed files with 4 additions and 4 deletions Inline Diff
sound/pci/lx6464es/lx6464es.c
1 | /* -*- linux-c -*- * | 1 | /* -*- linux-c -*- * |
2 | * | 2 | * |
3 | * ALSA driver for the digigram lx6464es interface | 3 | * ALSA driver for the digigram lx6464es interface |
4 | * | 4 | * |
5 | * Copyright (c) 2008, 2009 Tim Blechmann <tim@klingt.org> | 5 | * Copyright (c) 2008, 2009 Tim Blechmann <tim@klingt.org> |
6 | * | 6 | * |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; see the file COPYING. If not, write to | 19 | * along with this program; see the file COPYING. If not, write to |
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
21 | * Boston, MA 02111-1307, USA. | 21 | * Boston, MA 02111-1307, USA. |
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | 30 | ||
31 | #include <sound/initval.h> | 31 | #include <sound/initval.h> |
32 | #include <sound/control.h> | 32 | #include <sound/control.h> |
33 | #include <sound/info.h> | 33 | #include <sound/info.h> |
34 | 34 | ||
35 | #include "lx6464es.h" | 35 | #include "lx6464es.h" |
36 | 36 | ||
37 | MODULE_AUTHOR("Tim Blechmann"); | 37 | MODULE_AUTHOR("Tim Blechmann"); |
38 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
39 | MODULE_DESCRIPTION("digigram lx6464es"); | 39 | MODULE_DESCRIPTION("digigram lx6464es"); |
40 | MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}"); | 40 | MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}"); |
41 | 41 | ||
42 | 42 | ||
43 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 43 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
44 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 44 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
45 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 45 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
46 | 46 | ||
47 | module_param_array(index, int, NULL, 0444); | 47 | module_param_array(index, int, NULL, 0444); |
48 | MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface."); | 48 | MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface."); |
49 | module_param_array(id, charp, NULL, 0444); | 49 | module_param_array(id, charp, NULL, 0444); |
50 | MODULE_PARM_DESC(id, "ID string for Digigram LX6464ES interface."); | 50 | MODULE_PARM_DESC(id, "ID string for Digigram LX6464ES interface."); |
51 | module_param_array(enable, bool, NULL, 0444); | 51 | module_param_array(enable, bool, NULL, 0444); |
52 | MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards."); | 52 | MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards."); |
53 | 53 | ||
54 | static const char card_name[] = "LX6464ES"; | 54 | static const char card_name[] = "LX6464ES"; |
55 | 55 | ||
56 | 56 | ||
57 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 | 57 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 |
58 | 58 | ||
59 | static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = { | 59 | static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = { |
60 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | 60 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), |
61 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | 61 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, |
62 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM | 62 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM |
63 | }, /* LX6464ES */ | 63 | }, /* LX6464ES */ |
64 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | 64 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), |
65 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | 65 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, |
66 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM | 66 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM |
67 | }, /* LX6464ES-CAE */ | 67 | }, /* LX6464ES-CAE */ |
68 | { 0, }, | 68 | { 0, }, |
69 | }; | 69 | }; |
70 | 70 | ||
71 | MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids); | 71 | MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids); |
72 | 72 | ||
73 | 73 | ||
74 | 74 | ||
75 | /* PGO pour USERo dans le registre pci_0x06/loc_0xEC */ | 75 | /* PGO pour USERo dans le registre pci_0x06/loc_0xEC */ |
76 | #define CHIPSC_RESET_XILINX (1L<<16) | 76 | #define CHIPSC_RESET_XILINX (1L<<16) |
77 | 77 | ||
78 | 78 | ||
79 | /* alsa callbacks */ | 79 | /* alsa callbacks */ |
80 | static struct snd_pcm_hardware lx_caps = { | 80 | static struct snd_pcm_hardware lx_caps = { |
81 | .info = (SNDRV_PCM_INFO_MMAP | | 81 | .info = (SNDRV_PCM_INFO_MMAP | |
82 | SNDRV_PCM_INFO_INTERLEAVED | | 82 | SNDRV_PCM_INFO_INTERLEAVED | |
83 | SNDRV_PCM_INFO_MMAP_VALID | | 83 | SNDRV_PCM_INFO_MMAP_VALID | |
84 | SNDRV_PCM_INFO_SYNC_START), | 84 | SNDRV_PCM_INFO_SYNC_START), |
85 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 85 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
86 | SNDRV_PCM_FMTBIT_S16_BE | | 86 | SNDRV_PCM_FMTBIT_S16_BE | |
87 | SNDRV_PCM_FMTBIT_S24_3LE | | 87 | SNDRV_PCM_FMTBIT_S24_3LE | |
88 | SNDRV_PCM_FMTBIT_S24_3BE), | 88 | SNDRV_PCM_FMTBIT_S24_3BE), |
89 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | 89 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | |
90 | SNDRV_PCM_RATE_8000_192000), | 90 | SNDRV_PCM_RATE_8000_192000), |
91 | .rate_min = 8000, | 91 | .rate_min = 8000, |
92 | .rate_max = 192000, | 92 | .rate_max = 192000, |
93 | .channels_min = 2, | 93 | .channels_min = 2, |
94 | .channels_max = 64, | 94 | .channels_max = 64, |
95 | .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER, | 95 | .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER, |
96 | .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2), | 96 | .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2), |
97 | .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER), | 97 | .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER), |
98 | .periods_min = 2, | 98 | .periods_min = 2, |
99 | .periods_max = MAX_STREAM_BUFFER, | 99 | .periods_max = MAX_STREAM_BUFFER, |
100 | }; | 100 | }; |
101 | 101 | ||
102 | static int lx_set_granularity(struct lx6464es *chip, u32 gran); | 102 | static int lx_set_granularity(struct lx6464es *chip, u32 gran); |
103 | 103 | ||
104 | 104 | ||
105 | static int lx_hardware_open(struct lx6464es *chip, | 105 | static int lx_hardware_open(struct lx6464es *chip, |
106 | struct snd_pcm_substream *substream) | 106 | struct snd_pcm_substream *substream) |
107 | { | 107 | { |
108 | int err = 0; | 108 | int err = 0; |
109 | struct snd_pcm_runtime *runtime = substream->runtime; | 109 | struct snd_pcm_runtime *runtime = substream->runtime; |
110 | int channels = runtime->channels; | 110 | int channels = runtime->channels; |
111 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 111 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
112 | 112 | ||
113 | snd_pcm_uframes_t period_size = runtime->period_size; | 113 | snd_pcm_uframes_t period_size = runtime->period_size; |
114 | 114 | ||
115 | snd_printd(LXP "allocating pipe for %d channels\n", channels); | 115 | snd_printd(LXP "allocating pipe for %d channels\n", channels); |
116 | err = lx_pipe_allocate(chip, 0, is_capture, channels); | 116 | err = lx_pipe_allocate(chip, 0, is_capture, channels); |
117 | if (err < 0) { | 117 | if (err < 0) { |
118 | snd_printk(KERN_ERR LXP "allocating pipe failed\n"); | 118 | snd_printk(KERN_ERR LXP "allocating pipe failed\n"); |
119 | return err; | 119 | return err; |
120 | } | 120 | } |
121 | 121 | ||
122 | err = lx_set_granularity(chip, period_size); | 122 | err = lx_set_granularity(chip, period_size); |
123 | if (err < 0) { | 123 | if (err < 0) { |
124 | snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n", | 124 | snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n", |
125 | period_size); | 125 | period_size); |
126 | return err; | 126 | return err; |
127 | } | 127 | } |
128 | 128 | ||
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | static int lx_hardware_start(struct lx6464es *chip, | 132 | static int lx_hardware_start(struct lx6464es *chip, |
133 | struct snd_pcm_substream *substream) | 133 | struct snd_pcm_substream *substream) |
134 | { | 134 | { |
135 | int err = 0; | 135 | int err = 0; |
136 | struct snd_pcm_runtime *runtime = substream->runtime; | 136 | struct snd_pcm_runtime *runtime = substream->runtime; |
137 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 137 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
138 | 138 | ||
139 | snd_printd(LXP "setting stream format\n"); | 139 | snd_printd(LXP "setting stream format\n"); |
140 | err = lx_stream_set_format(chip, runtime, 0, is_capture); | 140 | err = lx_stream_set_format(chip, runtime, 0, is_capture); |
141 | if (err < 0) { | 141 | if (err < 0) { |
142 | snd_printk(KERN_ERR LXP "setting stream format failed\n"); | 142 | snd_printk(KERN_ERR LXP "setting stream format failed\n"); |
143 | return err; | 143 | return err; |
144 | } | 144 | } |
145 | 145 | ||
146 | snd_printd(LXP "starting pipe\n"); | 146 | snd_printd(LXP "starting pipe\n"); |
147 | err = lx_pipe_start(chip, 0, is_capture); | 147 | err = lx_pipe_start(chip, 0, is_capture); |
148 | if (err < 0) { | 148 | if (err < 0) { |
149 | snd_printk(KERN_ERR LXP "starting pipe failed\n"); | 149 | snd_printk(KERN_ERR LXP "starting pipe failed\n"); |
150 | return err; | 150 | return err; |
151 | } | 151 | } |
152 | 152 | ||
153 | snd_printd(LXP "waiting for pipe to start\n"); | 153 | snd_printd(LXP "waiting for pipe to start\n"); |
154 | err = lx_pipe_wait_for_start(chip, 0, is_capture); | 154 | err = lx_pipe_wait_for_start(chip, 0, is_capture); |
155 | if (err < 0) { | 155 | if (err < 0) { |
156 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); | 156 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); |
157 | return err; | 157 | return err; |
158 | } | 158 | } |
159 | 159 | ||
160 | return err; | 160 | return err; |
161 | } | 161 | } |
162 | 162 | ||
163 | 163 | ||
164 | static int lx_hardware_stop(struct lx6464es *chip, | 164 | static int lx_hardware_stop(struct lx6464es *chip, |
165 | struct snd_pcm_substream *substream) | 165 | struct snd_pcm_substream *substream) |
166 | { | 166 | { |
167 | int err = 0; | 167 | int err = 0; |
168 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 168 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
169 | 169 | ||
170 | snd_printd(LXP "pausing pipe\n"); | 170 | snd_printd(LXP "pausing pipe\n"); |
171 | err = lx_pipe_pause(chip, 0, is_capture); | 171 | err = lx_pipe_pause(chip, 0, is_capture); |
172 | if (err < 0) { | 172 | if (err < 0) { |
173 | snd_printk(KERN_ERR LXP "pausing pipe failed\n"); | 173 | snd_printk(KERN_ERR LXP "pausing pipe failed\n"); |
174 | return err; | 174 | return err; |
175 | } | 175 | } |
176 | 176 | ||
177 | snd_printd(LXP "waiting for pipe to become idle\n"); | 177 | snd_printd(LXP "waiting for pipe to become idle\n"); |
178 | err = lx_pipe_wait_for_idle(chip, 0, is_capture); | 178 | err = lx_pipe_wait_for_idle(chip, 0, is_capture); |
179 | if (err < 0) { | 179 | if (err < 0) { |
180 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); | 180 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); |
181 | return err; | 181 | return err; |
182 | } | 182 | } |
183 | 183 | ||
184 | snd_printd(LXP "stopping pipe\n"); | 184 | snd_printd(LXP "stopping pipe\n"); |
185 | err = lx_pipe_stop(chip, 0, is_capture); | 185 | err = lx_pipe_stop(chip, 0, is_capture); |
186 | if (err < 0) { | 186 | if (err < 0) { |
187 | snd_printk(LXP "stopping pipe failed\n"); | 187 | snd_printk(LXP "stopping pipe failed\n"); |
188 | return err; | 188 | return err; |
189 | } | 189 | } |
190 | 190 | ||
191 | return err; | 191 | return err; |
192 | } | 192 | } |
193 | 193 | ||
194 | 194 | ||
195 | static int lx_hardware_close(struct lx6464es *chip, | 195 | static int lx_hardware_close(struct lx6464es *chip, |
196 | struct snd_pcm_substream *substream) | 196 | struct snd_pcm_substream *substream) |
197 | { | 197 | { |
198 | int err = 0; | 198 | int err = 0; |
199 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 199 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
200 | 200 | ||
201 | snd_printd(LXP "releasing pipe\n"); | 201 | snd_printd(LXP "releasing pipe\n"); |
202 | err = lx_pipe_release(chip, 0, is_capture); | 202 | err = lx_pipe_release(chip, 0, is_capture); |
203 | if (err < 0) { | 203 | if (err < 0) { |
204 | snd_printk(LXP "releasing pipe failed\n"); | 204 | snd_printk(LXP "releasing pipe failed\n"); |
205 | return err; | 205 | return err; |
206 | } | 206 | } |
207 | 207 | ||
208 | return err; | 208 | return err; |
209 | } | 209 | } |
210 | 210 | ||
211 | 211 | ||
212 | static int lx_pcm_open(struct snd_pcm_substream *substream) | 212 | static int lx_pcm_open(struct snd_pcm_substream *substream) |
213 | { | 213 | { |
214 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | 214 | struct lx6464es *chip = snd_pcm_substream_chip(substream); |
215 | struct snd_pcm_runtime *runtime = substream->runtime; | 215 | struct snd_pcm_runtime *runtime = substream->runtime; |
216 | int err = 0; | 216 | int err = 0; |
217 | int board_rate; | 217 | int board_rate; |
218 | 218 | ||
219 | snd_printdd("->lx_pcm_open\n"); | 219 | snd_printdd("->lx_pcm_open\n"); |
220 | mutex_lock(&chip->setup_mutex); | 220 | mutex_lock(&chip->setup_mutex); |
221 | 221 | ||
222 | /* copy the struct snd_pcm_hardware struct */ | 222 | /* copy the struct snd_pcm_hardware struct */ |
223 | runtime->hw = lx_caps; | 223 | runtime->hw = lx_caps; |
224 | 224 | ||
225 | #if 0 | 225 | #if 0 |
226 | /* buffer-size should better be multiple of period-size */ | 226 | /* buffer-size should better be multiple of period-size */ |
227 | err = snd_pcm_hw_constraint_integer(runtime, | 227 | err = snd_pcm_hw_constraint_integer(runtime, |
228 | SNDRV_PCM_HW_PARAM_PERIODS); | 228 | SNDRV_PCM_HW_PARAM_PERIODS); |
229 | if (err < 0) { | 229 | if (err < 0) { |
230 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); | 230 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); |
231 | goto exit; | 231 | goto exit; |
232 | } | 232 | } |
233 | #endif | 233 | #endif |
234 | 234 | ||
235 | /* the clock rate cannot be changed */ | 235 | /* the clock rate cannot be changed */ |
236 | board_rate = chip->board_sample_rate; | 236 | board_rate = chip->board_sample_rate; |
237 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, | 237 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, |
238 | board_rate, board_rate); | 238 | board_rate, board_rate); |
239 | 239 | ||
240 | if (err < 0) { | 240 | if (err < 0) { |
241 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); | 241 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); |
242 | goto exit; | 242 | goto exit; |
243 | } | 243 | } |
244 | 244 | ||
245 | /* constrain period size */ | 245 | /* constrain period size */ |
246 | err = snd_pcm_hw_constraint_minmax(runtime, | 246 | err = snd_pcm_hw_constraint_minmax(runtime, |
247 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 247 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
248 | MICROBLAZE_IBL_MIN, | 248 | MICROBLAZE_IBL_MIN, |
249 | MICROBLAZE_IBL_MAX); | 249 | MICROBLAZE_IBL_MAX); |
250 | if (err < 0) { | 250 | if (err < 0) { |
251 | snd_printk(KERN_WARNING LXP | 251 | snd_printk(KERN_WARNING LXP |
252 | "could not constrain period size\n"); | 252 | "could not constrain period size\n"); |
253 | goto exit; | 253 | goto exit; |
254 | } | 254 | } |
255 | 255 | ||
256 | snd_pcm_hw_constraint_step(runtime, 0, | 256 | snd_pcm_hw_constraint_step(runtime, 0, |
257 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); | 257 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); |
258 | 258 | ||
259 | snd_pcm_set_sync(substream); | 259 | snd_pcm_set_sync(substream); |
260 | err = 0; | 260 | err = 0; |
261 | 261 | ||
262 | exit: | 262 | exit: |
263 | runtime->private_data = chip; | 263 | runtime->private_data = chip; |
264 | 264 | ||
265 | mutex_unlock(&chip->setup_mutex); | 265 | mutex_unlock(&chip->setup_mutex); |
266 | snd_printdd("<-lx_pcm_open, %d\n", err); | 266 | snd_printdd("<-lx_pcm_open, %d\n", err); |
267 | return err; | 267 | return err; |
268 | } | 268 | } |
269 | 269 | ||
270 | static int lx_pcm_close(struct snd_pcm_substream *substream) | 270 | static int lx_pcm_close(struct snd_pcm_substream *substream) |
271 | { | 271 | { |
272 | int err = 0; | 272 | int err = 0; |
273 | snd_printdd("->lx_pcm_close\n"); | 273 | snd_printdd("->lx_pcm_close\n"); |
274 | return err; | 274 | return err; |
275 | } | 275 | } |
276 | 276 | ||
277 | static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream | 277 | static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream |
278 | *substream) | 278 | *substream) |
279 | { | 279 | { |
280 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | 280 | struct lx6464es *chip = snd_pcm_substream_chip(substream); |
281 | snd_pcm_uframes_t pos; | 281 | snd_pcm_uframes_t pos; |
282 | unsigned long flags; | 282 | unsigned long flags; |
283 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 283 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
284 | 284 | ||
285 | struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : | 285 | struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : |
286 | &chip->playback_stream; | 286 | &chip->playback_stream; |
287 | 287 | ||
288 | snd_printdd("->lx_pcm_stream_pointer\n"); | 288 | snd_printdd("->lx_pcm_stream_pointer\n"); |
289 | 289 | ||
290 | spin_lock_irqsave(&chip->lock, flags); | 290 | spin_lock_irqsave(&chip->lock, flags); |
291 | pos = lx_stream->frame_pos * substream->runtime->period_size; | 291 | pos = lx_stream->frame_pos * substream->runtime->period_size; |
292 | spin_unlock_irqrestore(&chip->lock, flags); | 292 | spin_unlock_irqrestore(&chip->lock, flags); |
293 | 293 | ||
294 | snd_printdd(LXP "stream_pointer at %ld\n", pos); | 294 | snd_printdd(LXP "stream_pointer at %ld\n", pos); |
295 | return pos; | 295 | return pos; |
296 | } | 296 | } |
297 | 297 | ||
298 | static int lx_pcm_prepare(struct snd_pcm_substream *substream) | 298 | static int lx_pcm_prepare(struct snd_pcm_substream *substream) |
299 | { | 299 | { |
300 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | 300 | struct lx6464es *chip = snd_pcm_substream_chip(substream); |
301 | int err = 0; | 301 | int err = 0; |
302 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 302 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
303 | 303 | ||
304 | snd_printdd("->lx_pcm_prepare\n"); | 304 | snd_printdd("->lx_pcm_prepare\n"); |
305 | 305 | ||
306 | mutex_lock(&chip->setup_mutex); | 306 | mutex_lock(&chip->setup_mutex); |
307 | 307 | ||
308 | if (chip->hardware_running[is_capture]) { | 308 | if (chip->hardware_running[is_capture]) { |
309 | err = lx_hardware_stop(chip, substream); | 309 | err = lx_hardware_stop(chip, substream); |
310 | if (err < 0) { | 310 | if (err < 0) { |
311 | snd_printk(KERN_ERR LXP "failed to stop hardware. " | 311 | snd_printk(KERN_ERR LXP "failed to stop hardware. " |
312 | "Error code %d\n", err); | 312 | "Error code %d\n", err); |
313 | goto exit; | 313 | goto exit; |
314 | } | 314 | } |
315 | 315 | ||
316 | err = lx_hardware_close(chip, substream); | 316 | err = lx_hardware_close(chip, substream); |
317 | if (err < 0) { | 317 | if (err < 0) { |
318 | snd_printk(KERN_ERR LXP "failed to close hardware. " | 318 | snd_printk(KERN_ERR LXP "failed to close hardware. " |
319 | "Error code %d\n", err); | 319 | "Error code %d\n", err); |
320 | goto exit; | 320 | goto exit; |
321 | } | 321 | } |
322 | } | 322 | } |
323 | 323 | ||
324 | snd_printd(LXP "opening hardware\n"); | 324 | snd_printd(LXP "opening hardware\n"); |
325 | err = lx_hardware_open(chip, substream); | 325 | err = lx_hardware_open(chip, substream); |
326 | if (err < 0) { | 326 | if (err < 0) { |
327 | snd_printk(KERN_ERR LXP "failed to open hardware. " | 327 | snd_printk(KERN_ERR LXP "failed to open hardware. " |
328 | "Error code %d\n", err); | 328 | "Error code %d\n", err); |
329 | goto exit; | 329 | goto exit; |
330 | } | 330 | } |
331 | 331 | ||
332 | err = lx_hardware_start(chip, substream); | 332 | err = lx_hardware_start(chip, substream); |
333 | if (err < 0) { | 333 | if (err < 0) { |
334 | snd_printk(KERN_ERR LXP "failed to start hardware. " | 334 | snd_printk(KERN_ERR LXP "failed to start hardware. " |
335 | "Error code %d\n", err); | 335 | "Error code %d\n", err); |
336 | goto exit; | 336 | goto exit; |
337 | } | 337 | } |
338 | 338 | ||
339 | chip->hardware_running[is_capture] = 1; | 339 | chip->hardware_running[is_capture] = 1; |
340 | 340 | ||
341 | if (chip->board_sample_rate != substream->runtime->rate) { | 341 | if (chip->board_sample_rate != substream->runtime->rate) { |
342 | if (!err) | 342 | if (!err) |
343 | chip->board_sample_rate = substream->runtime->rate; | 343 | chip->board_sample_rate = substream->runtime->rate; |
344 | } | 344 | } |
345 | 345 | ||
346 | exit: | 346 | exit: |
347 | mutex_unlock(&chip->setup_mutex); | 347 | mutex_unlock(&chip->setup_mutex); |
348 | return err; | 348 | return err; |
349 | } | 349 | } |
350 | 350 | ||
351 | static int lx_pcm_hw_params(struct snd_pcm_substream *substream, | 351 | static int lx_pcm_hw_params(struct snd_pcm_substream *substream, |
352 | struct snd_pcm_hw_params *hw_params, int is_capture) | 352 | struct snd_pcm_hw_params *hw_params, int is_capture) |
353 | { | 353 | { |
354 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | 354 | struct lx6464es *chip = snd_pcm_substream_chip(substream); |
355 | int err = 0; | 355 | int err = 0; |
356 | 356 | ||
357 | snd_printdd("->lx_pcm_hw_params\n"); | 357 | snd_printdd("->lx_pcm_hw_params\n"); |
358 | 358 | ||
359 | mutex_lock(&chip->setup_mutex); | 359 | mutex_lock(&chip->setup_mutex); |
360 | 360 | ||
361 | /* set dma buffer */ | 361 | /* set dma buffer */ |
362 | err = snd_pcm_lib_malloc_pages(substream, | 362 | err = snd_pcm_lib_malloc_pages(substream, |
363 | params_buffer_bytes(hw_params)); | 363 | params_buffer_bytes(hw_params)); |
364 | 364 | ||
365 | if (is_capture) | 365 | if (is_capture) |
366 | chip->capture_stream.stream = substream; | 366 | chip->capture_stream.stream = substream; |
367 | else | 367 | else |
368 | chip->playback_stream.stream = substream; | 368 | chip->playback_stream.stream = substream; |
369 | 369 | ||
370 | mutex_unlock(&chip->setup_mutex); | 370 | mutex_unlock(&chip->setup_mutex); |
371 | return err; | 371 | return err; |
372 | } | 372 | } |
373 | 373 | ||
374 | static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream, | 374 | static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream, |
375 | struct snd_pcm_hw_params *hw_params) | 375 | struct snd_pcm_hw_params *hw_params) |
376 | { | 376 | { |
377 | return lx_pcm_hw_params(substream, hw_params, 0); | 377 | return lx_pcm_hw_params(substream, hw_params, 0); |
378 | } | 378 | } |
379 | 379 | ||
380 | static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream, | 380 | static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream, |
381 | struct snd_pcm_hw_params *hw_params) | 381 | struct snd_pcm_hw_params *hw_params) |
382 | { | 382 | { |
383 | return lx_pcm_hw_params(substream, hw_params, 1); | 383 | return lx_pcm_hw_params(substream, hw_params, 1); |
384 | } | 384 | } |
385 | 385 | ||
386 | static int lx_pcm_hw_free(struct snd_pcm_substream *substream) | 386 | static int lx_pcm_hw_free(struct snd_pcm_substream *substream) |
387 | { | 387 | { |
388 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | 388 | struct lx6464es *chip = snd_pcm_substream_chip(substream); |
389 | int err = 0; | 389 | int err = 0; |
390 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 390 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
391 | 391 | ||
392 | snd_printdd("->lx_pcm_hw_free\n"); | 392 | snd_printdd("->lx_pcm_hw_free\n"); |
393 | mutex_lock(&chip->setup_mutex); | 393 | mutex_lock(&chip->setup_mutex); |
394 | 394 | ||
395 | if (chip->hardware_running[is_capture]) { | 395 | if (chip->hardware_running[is_capture]) { |
396 | err = lx_hardware_stop(chip, substream); | 396 | err = lx_hardware_stop(chip, substream); |
397 | if (err < 0) { | 397 | if (err < 0) { |
398 | snd_printk(KERN_ERR LXP "failed to stop hardware. " | 398 | snd_printk(KERN_ERR LXP "failed to stop hardware. " |
399 | "Error code %d\n", err); | 399 | "Error code %d\n", err); |
400 | goto exit; | 400 | goto exit; |
401 | } | 401 | } |
402 | 402 | ||
403 | err = lx_hardware_close(chip, substream); | 403 | err = lx_hardware_close(chip, substream); |
404 | if (err < 0) { | 404 | if (err < 0) { |
405 | snd_printk(KERN_ERR LXP "failed to close hardware. " | 405 | snd_printk(KERN_ERR LXP "failed to close hardware. " |
406 | "Error code %d\n", err); | 406 | "Error code %d\n", err); |
407 | goto exit; | 407 | goto exit; |
408 | } | 408 | } |
409 | 409 | ||
410 | chip->hardware_running[is_capture] = 0; | 410 | chip->hardware_running[is_capture] = 0; |
411 | } | 411 | } |
412 | 412 | ||
413 | err = snd_pcm_lib_free_pages(substream); | 413 | err = snd_pcm_lib_free_pages(substream); |
414 | 414 | ||
415 | if (is_capture) | 415 | if (is_capture) |
416 | chip->capture_stream.stream = 0; | 416 | chip->capture_stream.stream = 0; |
417 | else | 417 | else |
418 | chip->playback_stream.stream = 0; | 418 | chip->playback_stream.stream = 0; |
419 | 419 | ||
420 | exit: | 420 | exit: |
421 | mutex_unlock(&chip->setup_mutex); | 421 | mutex_unlock(&chip->setup_mutex); |
422 | return err; | 422 | return err; |
423 | } | 423 | } |
424 | 424 | ||
425 | static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) | 425 | static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) |
426 | { | 426 | { |
427 | struct snd_pcm_substream *substream = lx_stream->stream; | 427 | struct snd_pcm_substream *substream = lx_stream->stream; |
428 | const int is_capture = lx_stream->is_capture; | 428 | const unsigned int is_capture = lx_stream->is_capture; |
429 | 429 | ||
430 | int err; | 430 | int err; |
431 | 431 | ||
432 | const u32 channels = substream->runtime->channels; | 432 | const u32 channels = substream->runtime->channels; |
433 | const u32 bytes_per_frame = channels * 3; | 433 | const u32 bytes_per_frame = channels * 3; |
434 | const u32 period_size = substream->runtime->period_size; | 434 | const u32 period_size = substream->runtime->period_size; |
435 | const u32 periods = substream->runtime->periods; | 435 | const u32 periods = substream->runtime->periods; |
436 | const u32 period_bytes = period_size * bytes_per_frame; | 436 | const u32 period_bytes = period_size * bytes_per_frame; |
437 | 437 | ||
438 | dma_addr_t buf = substream->dma_buffer.addr; | 438 | dma_addr_t buf = substream->dma_buffer.addr; |
439 | int i; | 439 | int i; |
440 | 440 | ||
441 | u32 needed, freed; | 441 | u32 needed, freed; |
442 | u32 size_array[5]; | 442 | u32 size_array[5]; |
443 | 443 | ||
444 | for (i = 0; i != periods; ++i) { | 444 | for (i = 0; i != periods; ++i) { |
445 | u32 buffer_index = 0; | 445 | u32 buffer_index = 0; |
446 | 446 | ||
447 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, | 447 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, |
448 | size_array); | 448 | size_array); |
449 | snd_printdd(LXP "starting: needed %d, freed %d\n", | 449 | snd_printdd(LXP "starting: needed %d, freed %d\n", |
450 | needed, freed); | 450 | needed, freed); |
451 | 451 | ||
452 | err = lx_buffer_give(chip, 0, is_capture, period_bytes, | 452 | err = lx_buffer_give(chip, 0, is_capture, period_bytes, |
453 | lower_32_bits(buf), upper_32_bits(buf), | 453 | lower_32_bits(buf), upper_32_bits(buf), |
454 | &buffer_index); | 454 | &buffer_index); |
455 | 455 | ||
456 | snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n", | 456 | snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n", |
457 | buffer_index, (void *)buf, period_bytes); | 457 | buffer_index, (void *)buf, period_bytes); |
458 | buf += period_bytes; | 458 | buf += period_bytes; |
459 | } | 459 | } |
460 | 460 | ||
461 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); | 461 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); |
462 | snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed); | 462 | snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed); |
463 | 463 | ||
464 | snd_printd(LXP "starting: starting stream\n"); | 464 | snd_printd(LXP "starting: starting stream\n"); |
465 | err = lx_stream_start(chip, 0, is_capture); | 465 | err = lx_stream_start(chip, 0, is_capture); |
466 | if (err < 0) | 466 | if (err < 0) |
467 | snd_printk(KERN_ERR LXP "couldn't start stream\n"); | 467 | snd_printk(KERN_ERR LXP "couldn't start stream\n"); |
468 | else | 468 | else |
469 | lx_stream->status = LX_STREAM_STATUS_RUNNING; | 469 | lx_stream->status = LX_STREAM_STATUS_RUNNING; |
470 | 470 | ||
471 | lx_stream->frame_pos = 0; | 471 | lx_stream->frame_pos = 0; |
472 | } | 472 | } |
473 | 473 | ||
474 | static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) | 474 | static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) |
475 | { | 475 | { |
476 | const int is_capture = lx_stream->is_capture; | 476 | const unsigned int is_capture = lx_stream->is_capture; |
477 | int err; | 477 | int err; |
478 | 478 | ||
479 | snd_printd(LXP "stopping: stopping stream\n"); | 479 | snd_printd(LXP "stopping: stopping stream\n"); |
480 | err = lx_stream_stop(chip, 0, is_capture); | 480 | err = lx_stream_stop(chip, 0, is_capture); |
481 | if (err < 0) | 481 | if (err < 0) |
482 | snd_printk(KERN_ERR LXP "couldn't stop stream\n"); | 482 | snd_printk(KERN_ERR LXP "couldn't stop stream\n"); |
483 | else | 483 | else |
484 | lx_stream->status = LX_STREAM_STATUS_FREE; | 484 | lx_stream->status = LX_STREAM_STATUS_FREE; |
485 | 485 | ||
486 | } | 486 | } |
487 | 487 | ||
488 | static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, | 488 | static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, |
489 | struct lx_stream *lx_stream) | 489 | struct lx_stream *lx_stream) |
490 | { | 490 | { |
491 | switch (lx_stream->status) { | 491 | switch (lx_stream->status) { |
492 | case LX_STREAM_STATUS_SCHEDULE_RUN: | 492 | case LX_STREAM_STATUS_SCHEDULE_RUN: |
493 | lx_trigger_start(chip, lx_stream); | 493 | lx_trigger_start(chip, lx_stream); |
494 | break; | 494 | break; |
495 | 495 | ||
496 | case LX_STREAM_STATUS_SCHEDULE_STOP: | 496 | case LX_STREAM_STATUS_SCHEDULE_STOP: |
497 | lx_trigger_stop(chip, lx_stream); | 497 | lx_trigger_stop(chip, lx_stream); |
498 | break; | 498 | break; |
499 | 499 | ||
500 | default: | 500 | default: |
501 | break; | 501 | break; |
502 | } | 502 | } |
503 | } | 503 | } |
504 | 504 | ||
505 | static void lx_trigger_tasklet(unsigned long data) | 505 | static void lx_trigger_tasklet(unsigned long data) |
506 | { | 506 | { |
507 | struct lx6464es *chip = (struct lx6464es *)data; | 507 | struct lx6464es *chip = (struct lx6464es *)data; |
508 | unsigned long flags; | 508 | unsigned long flags; |
509 | 509 | ||
510 | snd_printdd("->lx_trigger_tasklet\n"); | 510 | snd_printdd("->lx_trigger_tasklet\n"); |
511 | 511 | ||
512 | spin_lock_irqsave(&chip->lock, flags); | 512 | spin_lock_irqsave(&chip->lock, flags); |
513 | lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); | 513 | lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); |
514 | lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream); | 514 | lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream); |
515 | spin_unlock_irqrestore(&chip->lock, flags); | 515 | spin_unlock_irqrestore(&chip->lock, flags); |
516 | } | 516 | } |
517 | 517 | ||
518 | static int lx_pcm_trigger_dispatch(struct lx6464es *chip, | 518 | static int lx_pcm_trigger_dispatch(struct lx6464es *chip, |
519 | struct lx_stream *lx_stream, int cmd) | 519 | struct lx_stream *lx_stream, int cmd) |
520 | { | 520 | { |
521 | int err = 0; | 521 | int err = 0; |
522 | 522 | ||
523 | switch (cmd) { | 523 | switch (cmd) { |
524 | case SNDRV_PCM_TRIGGER_START: | 524 | case SNDRV_PCM_TRIGGER_START: |
525 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; | 525 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; |
526 | break; | 526 | break; |
527 | 527 | ||
528 | case SNDRV_PCM_TRIGGER_STOP: | 528 | case SNDRV_PCM_TRIGGER_STOP: |
529 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP; | 529 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP; |
530 | break; | 530 | break; |
531 | 531 | ||
532 | default: | 532 | default: |
533 | err = -EINVAL; | 533 | err = -EINVAL; |
534 | goto exit; | 534 | goto exit; |
535 | } | 535 | } |
536 | tasklet_schedule(&chip->trigger_tasklet); | 536 | tasklet_schedule(&chip->trigger_tasklet); |
537 | 537 | ||
538 | exit: | 538 | exit: |
539 | return err; | 539 | return err; |
540 | } | 540 | } |
541 | 541 | ||
542 | 542 | ||
543 | static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 543 | static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
544 | { | 544 | { |
545 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | 545 | struct lx6464es *chip = snd_pcm_substream_chip(substream); |
546 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 546 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
547 | struct lx_stream *stream = is_capture ? &chip->capture_stream : | 547 | struct lx_stream *stream = is_capture ? &chip->capture_stream : |
548 | &chip->playback_stream; | 548 | &chip->playback_stream; |
549 | 549 | ||
550 | snd_printdd("->lx_pcm_trigger\n"); | 550 | snd_printdd("->lx_pcm_trigger\n"); |
551 | 551 | ||
552 | return lx_pcm_trigger_dispatch(chip, stream, cmd); | 552 | return lx_pcm_trigger_dispatch(chip, stream, cmd); |
553 | } | 553 | } |
554 | 554 | ||
555 | static int snd_lx6464es_free(struct lx6464es *chip) | 555 | static int snd_lx6464es_free(struct lx6464es *chip) |
556 | { | 556 | { |
557 | snd_printdd("->snd_lx6464es_free\n"); | 557 | snd_printdd("->snd_lx6464es_free\n"); |
558 | 558 | ||
559 | lx_irq_disable(chip); | 559 | lx_irq_disable(chip); |
560 | 560 | ||
561 | if (chip->irq >= 0) | 561 | if (chip->irq >= 0) |
562 | free_irq(chip->irq, chip); | 562 | free_irq(chip->irq, chip); |
563 | 563 | ||
564 | iounmap(chip->port_dsp_bar); | 564 | iounmap(chip->port_dsp_bar); |
565 | ioport_unmap(chip->port_plx_remapped); | 565 | ioport_unmap(chip->port_plx_remapped); |
566 | 566 | ||
567 | pci_release_regions(chip->pci); | 567 | pci_release_regions(chip->pci); |
568 | pci_disable_device(chip->pci); | 568 | pci_disable_device(chip->pci); |
569 | 569 | ||
570 | kfree(chip); | 570 | kfree(chip); |
571 | 571 | ||
572 | return 0; | 572 | return 0; |
573 | } | 573 | } |
574 | 574 | ||
575 | static int snd_lx6464es_dev_free(struct snd_device *device) | 575 | static int snd_lx6464es_dev_free(struct snd_device *device) |
576 | { | 576 | { |
577 | return snd_lx6464es_free(device->device_data); | 577 | return snd_lx6464es_free(device->device_data); |
578 | } | 578 | } |
579 | 579 | ||
580 | /* reset the dsp during initialization */ | 580 | /* reset the dsp during initialization */ |
581 | static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) | 581 | static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) |
582 | { | 582 | { |
583 | int i; | 583 | int i; |
584 | u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); | 584 | u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); |
585 | 585 | ||
586 | snd_printdd("->lx_init_xilinx_reset\n"); | 586 | snd_printdd("->lx_init_xilinx_reset\n"); |
587 | 587 | ||
588 | /* activate reset of xilinx */ | 588 | /* activate reset of xilinx */ |
589 | plx_reg &= ~CHIPSC_RESET_XILINX; | 589 | plx_reg &= ~CHIPSC_RESET_XILINX; |
590 | 590 | ||
591 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); | 591 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); |
592 | msleep(1); | 592 | msleep(1); |
593 | 593 | ||
594 | lx_plx_reg_write(chip, ePLX_MBOX3, 0); | 594 | lx_plx_reg_write(chip, ePLX_MBOX3, 0); |
595 | msleep(1); | 595 | msleep(1); |
596 | 596 | ||
597 | plx_reg |= CHIPSC_RESET_XILINX; | 597 | plx_reg |= CHIPSC_RESET_XILINX; |
598 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); | 598 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); |
599 | 599 | ||
600 | /* deactivate reset of xilinx */ | 600 | /* deactivate reset of xilinx */ |
601 | for (i = 0; i != 100; ++i) { | 601 | for (i = 0; i != 100; ++i) { |
602 | u32 reg_mbox3; | 602 | u32 reg_mbox3; |
603 | msleep(10); | 603 | msleep(10); |
604 | reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); | 604 | reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); |
605 | if (reg_mbox3) { | 605 | if (reg_mbox3) { |
606 | snd_printd(LXP "xilinx reset done\n"); | 606 | snd_printd(LXP "xilinx reset done\n"); |
607 | snd_printdd(LXP "xilinx took %d loops\n", i); | 607 | snd_printdd(LXP "xilinx took %d loops\n", i); |
608 | break; | 608 | break; |
609 | } | 609 | } |
610 | } | 610 | } |
611 | 611 | ||
612 | /* todo: add some error handling? */ | 612 | /* todo: add some error handling? */ |
613 | 613 | ||
614 | /* clear mr */ | 614 | /* clear mr */ |
615 | lx_dsp_reg_write(chip, eReg_CSM, 0); | 615 | lx_dsp_reg_write(chip, eReg_CSM, 0); |
616 | 616 | ||
617 | /* le xilinx ES peut ne pas etre encore pret, on attend. */ | 617 | /* le xilinx ES peut ne pas etre encore pret, on attend. */ |
618 | msleep(600); | 618 | msleep(600); |
619 | 619 | ||
620 | return 0; | 620 | return 0; |
621 | } | 621 | } |
622 | 622 | ||
623 | static int __devinit lx_init_xilinx_test(struct lx6464es *chip) | 623 | static int __devinit lx_init_xilinx_test(struct lx6464es *chip) |
624 | { | 624 | { |
625 | u32 reg; | 625 | u32 reg; |
626 | 626 | ||
627 | snd_printdd("->lx_init_xilinx_test\n"); | 627 | snd_printdd("->lx_init_xilinx_test\n"); |
628 | 628 | ||
629 | /* TEST if we have access to Xilinx/MicroBlaze */ | 629 | /* TEST if we have access to Xilinx/MicroBlaze */ |
630 | lx_dsp_reg_write(chip, eReg_CSM, 0); | 630 | lx_dsp_reg_write(chip, eReg_CSM, 0); |
631 | 631 | ||
632 | reg = lx_dsp_reg_read(chip, eReg_CSM); | 632 | reg = lx_dsp_reg_read(chip, eReg_CSM); |
633 | 633 | ||
634 | if (reg) { | 634 | if (reg) { |
635 | snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg); | 635 | snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg); |
636 | 636 | ||
637 | /* PCI9056_SPACE0_REMAP */ | 637 | /* PCI9056_SPACE0_REMAP */ |
638 | lx_plx_reg_write(chip, ePLX_PCICR, 1); | 638 | lx_plx_reg_write(chip, ePLX_PCICR, 1); |
639 | 639 | ||
640 | reg = lx_dsp_reg_read(chip, eReg_CSM); | 640 | reg = lx_dsp_reg_read(chip, eReg_CSM); |
641 | if (reg) { | 641 | if (reg) { |
642 | snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg); | 642 | snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg); |
643 | return -EAGAIN; /* seems to be appropriate */ | 643 | return -EAGAIN; /* seems to be appropriate */ |
644 | } | 644 | } |
645 | } | 645 | } |
646 | 646 | ||
647 | snd_printd(LXP "Xilinx/MicroBlaze access test successful\n"); | 647 | snd_printd(LXP "Xilinx/MicroBlaze access test successful\n"); |
648 | 648 | ||
649 | return 0; | 649 | return 0; |
650 | } | 650 | } |
651 | 651 | ||
652 | /* initialize ethersound */ | 652 | /* initialize ethersound */ |
653 | static int __devinit lx_init_ethersound_config(struct lx6464es *chip) | 653 | static int __devinit lx_init_ethersound_config(struct lx6464es *chip) |
654 | { | 654 | { |
655 | int i; | 655 | int i; |
656 | u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); | 656 | u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); |
657 | 657 | ||
658 | /* configure 64 io channels */ | 658 | /* configure 64 io channels */ |
659 | u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) | | 659 | u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) | |
660 | (64 << IOCR_INPUTS_OFFSET) | | 660 | (64 << IOCR_INPUTS_OFFSET) | |
661 | (64 << IOCR_OUTPUTS_OFFSET) | | 661 | (64 << IOCR_OUTPUTS_OFFSET) | |
662 | (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); | 662 | (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); |
663 | 663 | ||
664 | snd_printdd("->lx_init_ethersound\n"); | 664 | snd_printdd("->lx_init_ethersound\n"); |
665 | 665 | ||
666 | chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; | 666 | chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; |
667 | 667 | ||
668 | /* | 668 | /* |
669 | * write it to the card ! | 669 | * write it to the card ! |
670 | * this actually kicks the ES xilinx, the first time since poweron. | 670 | * this actually kicks the ES xilinx, the first time since poweron. |
671 | * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers | 671 | * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers |
672 | * is not ready before this is done, and the bit 2 in Reg_CSES is set. | 672 | * is not ready before this is done, and the bit 2 in Reg_CSES is set. |
673 | * */ | 673 | * */ |
674 | lx_dsp_reg_write(chip, eReg_CONFES, conf_es); | 674 | lx_dsp_reg_write(chip, eReg_CONFES, conf_es); |
675 | 675 | ||
676 | for (i = 0; i != 1000; ++i) { | 676 | for (i = 0; i != 1000; ++i) { |
677 | if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { | 677 | if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { |
678 | snd_printd(LXP "ethersound initialized after %dms\n", | 678 | snd_printd(LXP "ethersound initialized after %dms\n", |
679 | i); | 679 | i); |
680 | goto ethersound_initialized; | 680 | goto ethersound_initialized; |
681 | } | 681 | } |
682 | msleep(1); | 682 | msleep(1); |
683 | } | 683 | } |
684 | snd_printk(KERN_WARNING LXP | 684 | snd_printk(KERN_WARNING LXP |
685 | "ethersound could not be initialized after %dms\n", i); | 685 | "ethersound could not be initialized after %dms\n", i); |
686 | return -ETIMEDOUT; | 686 | return -ETIMEDOUT; |
687 | 687 | ||
688 | ethersound_initialized: | 688 | ethersound_initialized: |
689 | snd_printd(LXP "ethersound initialized\n"); | 689 | snd_printd(LXP "ethersound initialized\n"); |
690 | return 0; | 690 | return 0; |
691 | } | 691 | } |
692 | 692 | ||
693 | static int __devinit lx_init_get_version_features(struct lx6464es *chip) | 693 | static int __devinit lx_init_get_version_features(struct lx6464es *chip) |
694 | { | 694 | { |
695 | u32 dsp_version; | 695 | u32 dsp_version; |
696 | 696 | ||
697 | int err; | 697 | int err; |
698 | 698 | ||
699 | snd_printdd("->lx_init_get_version_features\n"); | 699 | snd_printdd("->lx_init_get_version_features\n"); |
700 | 700 | ||
701 | err = lx_dsp_get_version(chip, &dsp_version); | 701 | err = lx_dsp_get_version(chip, &dsp_version); |
702 | 702 | ||
703 | if (err == 0) { | 703 | if (err == 0) { |
704 | u32 freq; | 704 | u32 freq; |
705 | 705 | ||
706 | snd_printk(LXP "DSP version: V%02d.%02d #%d\n", | 706 | snd_printk(LXP "DSP version: V%02d.%02d #%d\n", |
707 | (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, | 707 | (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, |
708 | dsp_version & 0xff); | 708 | dsp_version & 0xff); |
709 | 709 | ||
710 | /* later: what firmware version do we expect? */ | 710 | /* later: what firmware version do we expect? */ |
711 | 711 | ||
712 | /* retrieve Play/Rec features */ | 712 | /* retrieve Play/Rec features */ |
713 | /* done here because we may have to handle alternate | 713 | /* done here because we may have to handle alternate |
714 | * DSP files. */ | 714 | * DSP files. */ |
715 | /* later */ | 715 | /* later */ |
716 | 716 | ||
717 | /* init the EtherSound sample rate */ | 717 | /* init the EtherSound sample rate */ |
718 | err = lx_dsp_get_clock_frequency(chip, &freq); | 718 | err = lx_dsp_get_clock_frequency(chip, &freq); |
719 | if (err == 0) | 719 | if (err == 0) |
720 | chip->board_sample_rate = freq; | 720 | chip->board_sample_rate = freq; |
721 | snd_printd(LXP "actual clock frequency %d\n", freq); | 721 | snd_printd(LXP "actual clock frequency %d\n", freq); |
722 | } else { | 722 | } else { |
723 | snd_printk(KERN_ERR LXP "DSP corrupted \n"); | 723 | snd_printk(KERN_ERR LXP "DSP corrupted \n"); |
724 | err = -EAGAIN; | 724 | err = -EAGAIN; |
725 | } | 725 | } |
726 | 726 | ||
727 | return err; | 727 | return err; |
728 | } | 728 | } |
729 | 729 | ||
730 | static int lx_set_granularity(struct lx6464es *chip, u32 gran) | 730 | static int lx_set_granularity(struct lx6464es *chip, u32 gran) |
731 | { | 731 | { |
732 | int err = 0; | 732 | int err = 0; |
733 | u32 snapped_gran = MICROBLAZE_IBL_MIN; | 733 | u32 snapped_gran = MICROBLAZE_IBL_MIN; |
734 | 734 | ||
735 | snd_printdd("->lx_set_granularity\n"); | 735 | snd_printdd("->lx_set_granularity\n"); |
736 | 736 | ||
737 | /* blocksize is a power of 2 */ | 737 | /* blocksize is a power of 2 */ |
738 | while ((snapped_gran < gran) && | 738 | while ((snapped_gran < gran) && |
739 | (snapped_gran < MICROBLAZE_IBL_MAX)) { | 739 | (snapped_gran < MICROBLAZE_IBL_MAX)) { |
740 | snapped_gran *= 2; | 740 | snapped_gran *= 2; |
741 | } | 741 | } |
742 | 742 | ||
743 | if (snapped_gran == chip->pcm_granularity) | 743 | if (snapped_gran == chip->pcm_granularity) |
744 | return 0; | 744 | return 0; |
745 | 745 | ||
746 | err = lx_dsp_set_granularity(chip, snapped_gran); | 746 | err = lx_dsp_set_granularity(chip, snapped_gran); |
747 | if (err < 0) { | 747 | if (err < 0) { |
748 | snd_printk(KERN_WARNING LXP "could not set granularity\n"); | 748 | snd_printk(KERN_WARNING LXP "could not set granularity\n"); |
749 | err = -EAGAIN; | 749 | err = -EAGAIN; |
750 | } | 750 | } |
751 | 751 | ||
752 | if (snapped_gran != gran) | 752 | if (snapped_gran != gran) |
753 | snd_printk(LXP "snapped blocksize to %d\n", snapped_gran); | 753 | snd_printk(LXP "snapped blocksize to %d\n", snapped_gran); |
754 | 754 | ||
755 | snd_printd(LXP "set blocksize on board %d\n", snapped_gran); | 755 | snd_printd(LXP "set blocksize on board %d\n", snapped_gran); |
756 | chip->pcm_granularity = snapped_gran; | 756 | chip->pcm_granularity = snapped_gran; |
757 | 757 | ||
758 | return err; | 758 | return err; |
759 | } | 759 | } |
760 | 760 | ||
761 | /* initialize and test the xilinx dsp chip */ | 761 | /* initialize and test the xilinx dsp chip */ |
762 | static int __devinit lx_init_dsp(struct lx6464es *chip) | 762 | static int __devinit lx_init_dsp(struct lx6464es *chip) |
763 | { | 763 | { |
764 | int err; | 764 | int err; |
765 | u8 mac_address[6]; | 765 | u8 mac_address[6]; |
766 | int i; | 766 | int i; |
767 | 767 | ||
768 | snd_printdd("->lx_init_dsp\n"); | 768 | snd_printdd("->lx_init_dsp\n"); |
769 | 769 | ||
770 | snd_printd(LXP "initialize board\n"); | 770 | snd_printd(LXP "initialize board\n"); |
771 | err = lx_init_xilinx_reset(chip); | 771 | err = lx_init_xilinx_reset(chip); |
772 | if (err) | 772 | if (err) |
773 | return err; | 773 | return err; |
774 | 774 | ||
775 | snd_printd(LXP "testing board\n"); | 775 | snd_printd(LXP "testing board\n"); |
776 | err = lx_init_xilinx_test(chip); | 776 | err = lx_init_xilinx_test(chip); |
777 | if (err) | 777 | if (err) |
778 | return err; | 778 | return err; |
779 | 779 | ||
780 | snd_printd(LXP "initialize ethersound configuration\n"); | 780 | snd_printd(LXP "initialize ethersound configuration\n"); |
781 | err = lx_init_ethersound_config(chip); | 781 | err = lx_init_ethersound_config(chip); |
782 | if (err) | 782 | if (err) |
783 | return err; | 783 | return err; |
784 | 784 | ||
785 | lx_irq_enable(chip); | 785 | lx_irq_enable(chip); |
786 | 786 | ||
787 | /** \todo the mac address should be ready by not, but it isn't, | 787 | /** \todo the mac address should be ready by not, but it isn't, |
788 | * so we wait for it */ | 788 | * so we wait for it */ |
789 | for (i = 0; i != 1000; ++i) { | 789 | for (i = 0; i != 1000; ++i) { |
790 | err = lx_dsp_get_mac(chip, mac_address); | 790 | err = lx_dsp_get_mac(chip, mac_address); |
791 | if (err) | 791 | if (err) |
792 | return err; | 792 | return err; |
793 | if (mac_address[0] || mac_address[1] || mac_address[2] || | 793 | if (mac_address[0] || mac_address[1] || mac_address[2] || |
794 | mac_address[3] || mac_address[4] || mac_address[5]) | 794 | mac_address[3] || mac_address[4] || mac_address[5]) |
795 | goto mac_ready; | 795 | goto mac_ready; |
796 | msleep(1); | 796 | msleep(1); |
797 | } | 797 | } |
798 | return -ETIMEDOUT; | 798 | return -ETIMEDOUT; |
799 | 799 | ||
800 | mac_ready: | 800 | mac_ready: |
801 | snd_printd(LXP "mac address ready read after: %dms\n", i); | 801 | snd_printd(LXP "mac address ready read after: %dms\n", i); |
802 | snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", | 802 | snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", |
803 | mac_address[0], mac_address[1], mac_address[2], | 803 | mac_address[0], mac_address[1], mac_address[2], |
804 | mac_address[3], mac_address[4], mac_address[5]); | 804 | mac_address[3], mac_address[4], mac_address[5]); |
805 | 805 | ||
806 | err = lx_init_get_version_features(chip); | 806 | err = lx_init_get_version_features(chip); |
807 | if (err) | 807 | if (err) |
808 | return err; | 808 | return err; |
809 | 809 | ||
810 | lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT); | 810 | lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT); |
811 | 811 | ||
812 | chip->playback_mute = 0; | 812 | chip->playback_mute = 0; |
813 | 813 | ||
814 | return err; | 814 | return err; |
815 | } | 815 | } |
816 | 816 | ||
817 | static struct snd_pcm_ops lx_ops_playback = { | 817 | static struct snd_pcm_ops lx_ops_playback = { |
818 | .open = lx_pcm_open, | 818 | .open = lx_pcm_open, |
819 | .close = lx_pcm_close, | 819 | .close = lx_pcm_close, |
820 | .ioctl = snd_pcm_lib_ioctl, | 820 | .ioctl = snd_pcm_lib_ioctl, |
821 | .prepare = lx_pcm_prepare, | 821 | .prepare = lx_pcm_prepare, |
822 | .hw_params = lx_pcm_hw_params_playback, | 822 | .hw_params = lx_pcm_hw_params_playback, |
823 | .hw_free = lx_pcm_hw_free, | 823 | .hw_free = lx_pcm_hw_free, |
824 | .trigger = lx_pcm_trigger, | 824 | .trigger = lx_pcm_trigger, |
825 | .pointer = lx_pcm_stream_pointer, | 825 | .pointer = lx_pcm_stream_pointer, |
826 | }; | 826 | }; |
827 | 827 | ||
828 | static struct snd_pcm_ops lx_ops_capture = { | 828 | static struct snd_pcm_ops lx_ops_capture = { |
829 | .open = lx_pcm_open, | 829 | .open = lx_pcm_open, |
830 | .close = lx_pcm_close, | 830 | .close = lx_pcm_close, |
831 | .ioctl = snd_pcm_lib_ioctl, | 831 | .ioctl = snd_pcm_lib_ioctl, |
832 | .prepare = lx_pcm_prepare, | 832 | .prepare = lx_pcm_prepare, |
833 | .hw_params = lx_pcm_hw_params_capture, | 833 | .hw_params = lx_pcm_hw_params_capture, |
834 | .hw_free = lx_pcm_hw_free, | 834 | .hw_free = lx_pcm_hw_free, |
835 | .trigger = lx_pcm_trigger, | 835 | .trigger = lx_pcm_trigger, |
836 | .pointer = lx_pcm_stream_pointer, | 836 | .pointer = lx_pcm_stream_pointer, |
837 | }; | 837 | }; |
838 | 838 | ||
839 | static int __devinit lx_pcm_create(struct lx6464es *chip) | 839 | static int __devinit lx_pcm_create(struct lx6464es *chip) |
840 | { | 840 | { |
841 | int err; | 841 | int err; |
842 | struct snd_pcm *pcm; | 842 | struct snd_pcm *pcm; |
843 | 843 | ||
844 | u32 size = 64 * /* channels */ | 844 | u32 size = 64 * /* channels */ |
845 | 3 * /* 24 bit samples */ | 845 | 3 * /* 24 bit samples */ |
846 | MAX_STREAM_BUFFER * /* periods */ | 846 | MAX_STREAM_BUFFER * /* periods */ |
847 | MICROBLAZE_IBL_MAX * /* frames per period */ | 847 | MICROBLAZE_IBL_MAX * /* frames per period */ |
848 | 2; /* duplex */ | 848 | 2; /* duplex */ |
849 | 849 | ||
850 | size = PAGE_ALIGN(size); | 850 | size = PAGE_ALIGN(size); |
851 | 851 | ||
852 | /* hardcoded device name & channel count */ | 852 | /* hardcoded device name & channel count */ |
853 | err = snd_pcm_new(chip->card, (char *)card_name, 0, | 853 | err = snd_pcm_new(chip->card, (char *)card_name, 0, |
854 | 1, 1, &pcm); | 854 | 1, 1, &pcm); |
855 | 855 | ||
856 | pcm->private_data = chip; | 856 | pcm->private_data = chip; |
857 | 857 | ||
858 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback); | 858 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback); |
859 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); | 859 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); |
860 | 860 | ||
861 | pcm->info_flags = 0; | 861 | pcm->info_flags = 0; |
862 | strcpy(pcm->name, card_name); | 862 | strcpy(pcm->name, card_name); |
863 | 863 | ||
864 | err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 864 | err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
865 | snd_dma_pci_data(chip->pci), | 865 | snd_dma_pci_data(chip->pci), |
866 | size, size); | 866 | size, size); |
867 | if (err < 0) | 867 | if (err < 0) |
868 | return err; | 868 | return err; |
869 | 869 | ||
870 | chip->pcm = pcm; | 870 | chip->pcm = pcm; |
871 | chip->capture_stream.is_capture = 1; | 871 | chip->capture_stream.is_capture = 1; |
872 | 872 | ||
873 | return 0; | 873 | return 0; |
874 | } | 874 | } |
875 | 875 | ||
876 | static int lx_control_playback_info(struct snd_kcontrol *kcontrol, | 876 | static int lx_control_playback_info(struct snd_kcontrol *kcontrol, |
877 | struct snd_ctl_elem_info *uinfo) | 877 | struct snd_ctl_elem_info *uinfo) |
878 | { | 878 | { |
879 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 879 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
880 | uinfo->count = 1; | 880 | uinfo->count = 1; |
881 | uinfo->value.integer.min = 0; | 881 | uinfo->value.integer.min = 0; |
882 | uinfo->value.integer.max = 1; | 882 | uinfo->value.integer.max = 1; |
883 | return 0; | 883 | return 0; |
884 | } | 884 | } |
885 | 885 | ||
886 | static int lx_control_playback_get(struct snd_kcontrol *kcontrol, | 886 | static int lx_control_playback_get(struct snd_kcontrol *kcontrol, |
887 | struct snd_ctl_elem_value *ucontrol) | 887 | struct snd_ctl_elem_value *ucontrol) |
888 | { | 888 | { |
889 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); | 889 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); |
890 | ucontrol->value.integer.value[0] = chip->playback_mute; | 890 | ucontrol->value.integer.value[0] = chip->playback_mute; |
891 | return 0; | 891 | return 0; |
892 | } | 892 | } |
893 | 893 | ||
894 | static int lx_control_playback_put(struct snd_kcontrol *kcontrol, | 894 | static int lx_control_playback_put(struct snd_kcontrol *kcontrol, |
895 | struct snd_ctl_elem_value *ucontrol) | 895 | struct snd_ctl_elem_value *ucontrol) |
896 | { | 896 | { |
897 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); | 897 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); |
898 | int changed = 0; | 898 | int changed = 0; |
899 | int current_value = chip->playback_mute; | 899 | int current_value = chip->playback_mute; |
900 | 900 | ||
901 | if (current_value != ucontrol->value.integer.value[0]) { | 901 | if (current_value != ucontrol->value.integer.value[0]) { |
902 | lx_level_unmute(chip, 0, !current_value); | 902 | lx_level_unmute(chip, 0, !current_value); |
903 | chip->playback_mute = !current_value; | 903 | chip->playback_mute = !current_value; |
904 | changed = 1; | 904 | changed = 1; |
905 | } | 905 | } |
906 | return changed; | 906 | return changed; |
907 | } | 907 | } |
908 | 908 | ||
909 | static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { | 909 | static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { |
910 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 910 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
911 | .name = "PCM Playback Switch", | 911 | .name = "PCM Playback Switch", |
912 | .index = 0, | 912 | .index = 0, |
913 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 913 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
914 | .private_value = 0, | 914 | .private_value = 0, |
915 | .info = lx_control_playback_info, | 915 | .info = lx_control_playback_info, |
916 | .get = lx_control_playback_get, | 916 | .get = lx_control_playback_get, |
917 | .put = lx_control_playback_put | 917 | .put = lx_control_playback_put |
918 | }; | 918 | }; |
919 | 919 | ||
920 | 920 | ||
921 | 921 | ||
922 | static void lx_proc_levels_read(struct snd_info_entry *entry, | 922 | static void lx_proc_levels_read(struct snd_info_entry *entry, |
923 | struct snd_info_buffer *buffer) | 923 | struct snd_info_buffer *buffer) |
924 | { | 924 | { |
925 | u32 levels[64]; | 925 | u32 levels[64]; |
926 | int err; | 926 | int err; |
927 | int i, j; | 927 | int i, j; |
928 | struct lx6464es *chip = entry->private_data; | 928 | struct lx6464es *chip = entry->private_data; |
929 | 929 | ||
930 | snd_iprintf(buffer, "capture levels:\n"); | 930 | snd_iprintf(buffer, "capture levels:\n"); |
931 | err = lx_level_peaks(chip, 1, 64, levels); | 931 | err = lx_level_peaks(chip, 1, 64, levels); |
932 | if (err < 0) | 932 | if (err < 0) |
933 | return; | 933 | return; |
934 | 934 | ||
935 | for (i = 0; i != 8; ++i) { | 935 | for (i = 0; i != 8; ++i) { |
936 | for (j = 0; j != 8; ++j) | 936 | for (j = 0; j != 8; ++j) |
937 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); | 937 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); |
938 | snd_iprintf(buffer, "\n"); | 938 | snd_iprintf(buffer, "\n"); |
939 | } | 939 | } |
940 | 940 | ||
941 | snd_iprintf(buffer, "\nplayback levels:\n"); | 941 | snd_iprintf(buffer, "\nplayback levels:\n"); |
942 | 942 | ||
943 | err = lx_level_peaks(chip, 0, 64, levels); | 943 | err = lx_level_peaks(chip, 0, 64, levels); |
944 | if (err < 0) | 944 | if (err < 0) |
945 | return; | 945 | return; |
946 | 946 | ||
947 | for (i = 0; i != 8; ++i) { | 947 | for (i = 0; i != 8; ++i) { |
948 | for (j = 0; j != 8; ++j) | 948 | for (j = 0; j != 8; ++j) |
949 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); | 949 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); |
950 | snd_iprintf(buffer, "\n"); | 950 | snd_iprintf(buffer, "\n"); |
951 | } | 951 | } |
952 | 952 | ||
953 | snd_iprintf(buffer, "\n"); | 953 | snd_iprintf(buffer, "\n"); |
954 | } | 954 | } |
955 | 955 | ||
956 | static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) | 956 | static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) |
957 | { | 957 | { |
958 | struct snd_info_entry *entry; | 958 | struct snd_info_entry *entry; |
959 | int err = snd_card_proc_new(card, "levels", &entry); | 959 | int err = snd_card_proc_new(card, "levels", &entry); |
960 | if (err < 0) | 960 | if (err < 0) |
961 | return err; | 961 | return err; |
962 | 962 | ||
963 | snd_info_set_text_ops(entry, chip, lx_proc_levels_read); | 963 | snd_info_set_text_ops(entry, chip, lx_proc_levels_read); |
964 | return 0; | 964 | return 0; |
965 | } | 965 | } |
966 | 966 | ||
967 | 967 | ||
968 | static int __devinit snd_lx6464es_create(struct snd_card *card, | 968 | static int __devinit snd_lx6464es_create(struct snd_card *card, |
969 | struct pci_dev *pci, | 969 | struct pci_dev *pci, |
970 | struct lx6464es **rchip) | 970 | struct lx6464es **rchip) |
971 | { | 971 | { |
972 | struct lx6464es *chip; | 972 | struct lx6464es *chip; |
973 | int err; | 973 | int err; |
974 | 974 | ||
975 | static struct snd_device_ops ops = { | 975 | static struct snd_device_ops ops = { |
976 | .dev_free = snd_lx6464es_dev_free, | 976 | .dev_free = snd_lx6464es_dev_free, |
977 | }; | 977 | }; |
978 | 978 | ||
979 | snd_printdd("->snd_lx6464es_create\n"); | 979 | snd_printdd("->snd_lx6464es_create\n"); |
980 | 980 | ||
981 | *rchip = NULL; | 981 | *rchip = NULL; |
982 | 982 | ||
983 | /* enable PCI device */ | 983 | /* enable PCI device */ |
984 | err = pci_enable_device(pci); | 984 | err = pci_enable_device(pci); |
985 | if (err < 0) | 985 | if (err < 0) |
986 | return err; | 986 | return err; |
987 | 987 | ||
988 | pci_set_master(pci); | 988 | pci_set_master(pci); |
989 | 989 | ||
990 | /* check if we can restrict PCI DMA transfers to 32 bits */ | 990 | /* check if we can restrict PCI DMA transfers to 32 bits */ |
991 | err = pci_set_dma_mask(pci, DMA_BIT_MASK(32)); | 991 | err = pci_set_dma_mask(pci, DMA_BIT_MASK(32)); |
992 | if (err < 0) { | 992 | if (err < 0) { |
993 | snd_printk(KERN_ERR "architecture does not support " | 993 | snd_printk(KERN_ERR "architecture does not support " |
994 | "32bit PCI busmaster DMA\n"); | 994 | "32bit PCI busmaster DMA\n"); |
995 | pci_disable_device(pci); | 995 | pci_disable_device(pci); |
996 | return -ENXIO; | 996 | return -ENXIO; |
997 | } | 997 | } |
998 | 998 | ||
999 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 999 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
1000 | if (chip == NULL) { | 1000 | if (chip == NULL) { |
1001 | err = -ENOMEM; | 1001 | err = -ENOMEM; |
1002 | goto alloc_failed; | 1002 | goto alloc_failed; |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | chip->card = card; | 1005 | chip->card = card; |
1006 | chip->pci = pci; | 1006 | chip->pci = pci; |
1007 | chip->irq = -1; | 1007 | chip->irq = -1; |
1008 | 1008 | ||
1009 | /* initialize synchronization structs */ | 1009 | /* initialize synchronization structs */ |
1010 | spin_lock_init(&chip->lock); | 1010 | spin_lock_init(&chip->lock); |
1011 | spin_lock_init(&chip->msg_lock); | 1011 | spin_lock_init(&chip->msg_lock); |
1012 | mutex_init(&chip->setup_mutex); | 1012 | mutex_init(&chip->setup_mutex); |
1013 | tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet, | 1013 | tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet, |
1014 | (unsigned long)chip); | 1014 | (unsigned long)chip); |
1015 | tasklet_init(&chip->tasklet_capture, lx_tasklet_capture, | 1015 | tasklet_init(&chip->tasklet_capture, lx_tasklet_capture, |
1016 | (unsigned long)chip); | 1016 | (unsigned long)chip); |
1017 | tasklet_init(&chip->tasklet_playback, lx_tasklet_playback, | 1017 | tasklet_init(&chip->tasklet_playback, lx_tasklet_playback, |
1018 | (unsigned long)chip); | 1018 | (unsigned long)chip); |
1019 | 1019 | ||
1020 | /* request resources */ | 1020 | /* request resources */ |
1021 | err = pci_request_regions(pci, card_name); | 1021 | err = pci_request_regions(pci, card_name); |
1022 | if (err < 0) | 1022 | if (err < 0) |
1023 | goto request_regions_failed; | 1023 | goto request_regions_failed; |
1024 | 1024 | ||
1025 | /* plx port */ | 1025 | /* plx port */ |
1026 | chip->port_plx = pci_resource_start(pci, 1); | 1026 | chip->port_plx = pci_resource_start(pci, 1); |
1027 | chip->port_plx_remapped = ioport_map(chip->port_plx, | 1027 | chip->port_plx_remapped = ioport_map(chip->port_plx, |
1028 | pci_resource_len(pci, 1)); | 1028 | pci_resource_len(pci, 1)); |
1029 | 1029 | ||
1030 | /* dsp port */ | 1030 | /* dsp port */ |
1031 | chip->port_dsp_bar = pci_ioremap_bar(pci, 2); | 1031 | chip->port_dsp_bar = pci_ioremap_bar(pci, 2); |
1032 | 1032 | ||
1033 | err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, | 1033 | err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, |
1034 | card_name, chip); | 1034 | card_name, chip); |
1035 | if (err) { | 1035 | if (err) { |
1036 | snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); | 1036 | snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); |
1037 | goto request_irq_failed; | 1037 | goto request_irq_failed; |
1038 | } | 1038 | } |
1039 | chip->irq = pci->irq; | 1039 | chip->irq = pci->irq; |
1040 | 1040 | ||
1041 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | 1041 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); |
1042 | if (err < 0) | 1042 | if (err < 0) |
1043 | goto device_new_failed; | 1043 | goto device_new_failed; |
1044 | 1044 | ||
1045 | err = lx_init_dsp(chip); | 1045 | err = lx_init_dsp(chip); |
1046 | if (err < 0) { | 1046 | if (err < 0) { |
1047 | snd_printk(KERN_ERR LXP "error during DSP initialization\n"); | 1047 | snd_printk(KERN_ERR LXP "error during DSP initialization\n"); |
1048 | return err; | 1048 | return err; |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | err = lx_pcm_create(chip); | 1051 | err = lx_pcm_create(chip); |
1052 | if (err < 0) | 1052 | if (err < 0) |
1053 | return err; | 1053 | return err; |
1054 | 1054 | ||
1055 | err = lx_proc_create(card, chip); | 1055 | err = lx_proc_create(card, chip); |
1056 | if (err < 0) | 1056 | if (err < 0) |
1057 | return err; | 1057 | return err; |
1058 | 1058 | ||
1059 | err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch, | 1059 | err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch, |
1060 | chip)); | 1060 | chip)); |
1061 | if (err < 0) | 1061 | if (err < 0) |
1062 | return err; | 1062 | return err; |
1063 | 1063 | ||
1064 | snd_card_set_dev(card, &pci->dev); | 1064 | snd_card_set_dev(card, &pci->dev); |
1065 | 1065 | ||
1066 | *rchip = chip; | 1066 | *rchip = chip; |
1067 | return 0; | 1067 | return 0; |
1068 | 1068 | ||
1069 | device_new_failed: | 1069 | device_new_failed: |
1070 | free_irq(pci->irq, chip); | 1070 | free_irq(pci->irq, chip); |
1071 | 1071 | ||
1072 | request_irq_failed: | 1072 | request_irq_failed: |
1073 | pci_release_regions(pci); | 1073 | pci_release_regions(pci); |
1074 | 1074 | ||
1075 | request_regions_failed: | 1075 | request_regions_failed: |
1076 | kfree(chip); | 1076 | kfree(chip); |
1077 | 1077 | ||
1078 | alloc_failed: | 1078 | alloc_failed: |
1079 | pci_disable_device(pci); | 1079 | pci_disable_device(pci); |
1080 | 1080 | ||
1081 | return err; | 1081 | return err; |
1082 | } | 1082 | } |
1083 | 1083 | ||
1084 | static int __devinit snd_lx6464es_probe(struct pci_dev *pci, | 1084 | static int __devinit snd_lx6464es_probe(struct pci_dev *pci, |
1085 | const struct pci_device_id *pci_id) | 1085 | const struct pci_device_id *pci_id) |
1086 | { | 1086 | { |
1087 | static int dev; | 1087 | static int dev; |
1088 | struct snd_card *card; | 1088 | struct snd_card *card; |
1089 | struct lx6464es *chip; | 1089 | struct lx6464es *chip; |
1090 | int err; | 1090 | int err; |
1091 | 1091 | ||
1092 | snd_printdd("->snd_lx6464es_probe\n"); | 1092 | snd_printdd("->snd_lx6464es_probe\n"); |
1093 | 1093 | ||
1094 | if (dev >= SNDRV_CARDS) | 1094 | if (dev >= SNDRV_CARDS) |
1095 | return -ENODEV; | 1095 | return -ENODEV; |
1096 | if (!enable[dev]) { | 1096 | if (!enable[dev]) { |
1097 | dev++; | 1097 | dev++; |
1098 | return -ENOENT; | 1098 | return -ENOENT; |
1099 | } | 1099 | } |
1100 | 1100 | ||
1101 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | 1101 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); |
1102 | if (err < 0) | 1102 | if (err < 0) |
1103 | return err; | 1103 | return err; |
1104 | 1104 | ||
1105 | err = snd_lx6464es_create(card, pci, &chip); | 1105 | err = snd_lx6464es_create(card, pci, &chip); |
1106 | if (err < 0) { | 1106 | if (err < 0) { |
1107 | snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n"); | 1107 | snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n"); |
1108 | goto out_free; | 1108 | goto out_free; |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | strcpy(card->driver, "lx6464es"); | 1111 | strcpy(card->driver, "lx6464es"); |
1112 | strcpy(card->shortname, "Digigram LX6464ES"); | 1112 | strcpy(card->shortname, "Digigram LX6464ES"); |
1113 | sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", | 1113 | sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", |
1114 | card->shortname, chip->port_plx, | 1114 | card->shortname, chip->port_plx, |
1115 | chip->port_dsp_bar, chip->irq); | 1115 | chip->port_dsp_bar, chip->irq); |
1116 | 1116 | ||
1117 | err = snd_card_register(card); | 1117 | err = snd_card_register(card); |
1118 | if (err < 0) | 1118 | if (err < 0) |
1119 | goto out_free; | 1119 | goto out_free; |
1120 | 1120 | ||
1121 | snd_printdd(LXP "initialization successful\n"); | 1121 | snd_printdd(LXP "initialization successful\n"); |
1122 | pci_set_drvdata(pci, card); | 1122 | pci_set_drvdata(pci, card); |
1123 | dev++; | 1123 | dev++; |
1124 | return 0; | 1124 | return 0; |
1125 | 1125 | ||
1126 | out_free: | 1126 | out_free: |
1127 | snd_card_free(card); | 1127 | snd_card_free(card); |
1128 | return err; | 1128 | return err; |
1129 | 1129 | ||
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | static void __devexit snd_lx6464es_remove(struct pci_dev *pci) | 1132 | static void __devexit snd_lx6464es_remove(struct pci_dev *pci) |
1133 | { | 1133 | { |
1134 | snd_card_free(pci_get_drvdata(pci)); | 1134 | snd_card_free(pci_get_drvdata(pci)); |
1135 | pci_set_drvdata(pci, NULL); | 1135 | pci_set_drvdata(pci, NULL); |
1136 | } | 1136 | } |
1137 | 1137 | ||
1138 | 1138 | ||
1139 | static struct pci_driver driver = { | 1139 | static struct pci_driver driver = { |
1140 | .name = "Digigram LX6464ES", | 1140 | .name = "Digigram LX6464ES", |
1141 | .id_table = snd_lx6464es_ids, | 1141 | .id_table = snd_lx6464es_ids, |
1142 | .probe = snd_lx6464es_probe, | 1142 | .probe = snd_lx6464es_probe, |
1143 | .remove = __devexit_p(snd_lx6464es_remove), | 1143 | .remove = __devexit_p(snd_lx6464es_remove), |
1144 | }; | 1144 | }; |
1145 | 1145 | ||
1146 | 1146 | ||
1147 | /* module initialization */ | 1147 | /* module initialization */ |
1148 | static int __init mod_init(void) | 1148 | static int __init mod_init(void) |
1149 | { | 1149 | { |
1150 | return pci_register_driver(&driver); | 1150 | return pci_register_driver(&driver); |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | static void __exit mod_exit(void) | 1153 | static void __exit mod_exit(void) |
1154 | { | 1154 | { |
1155 | pci_unregister_driver(&driver); | 1155 | pci_unregister_driver(&driver); |
1156 | } | 1156 | } |
1157 | 1157 | ||
1158 | module_init(mod_init); | 1158 | module_init(mod_init); |
1159 | module_exit(mod_exit); | 1159 | module_exit(mod_exit); |
1160 | 1160 |
sound/pci/lx6464es/lx6464es.h
1 | /* -*- linux-c -*- * | 1 | /* -*- linux-c -*- * |
2 | * | 2 | * |
3 | * ALSA driver for the digigram lx6464es interface | 3 | * ALSA driver for the digigram lx6464es interface |
4 | * | 4 | * |
5 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> | 5 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> |
6 | * | 6 | * |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; see the file COPYING. If not, write to | 19 | * along with this program; see the file COPYING. If not, write to |
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
21 | * Boston, MA 02111-1307, USA. | 21 | * Boston, MA 02111-1307, USA. |
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #ifndef LX6464ES_H | 25 | #ifndef LX6464ES_H |
26 | #define LX6464ES_H | 26 | #define LX6464ES_H |
27 | 27 | ||
28 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
29 | #include <asm/atomic.h> | 29 | #include <asm/atomic.h> |
30 | 30 | ||
31 | #include <sound/core.h> | 31 | #include <sound/core.h> |
32 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
33 | 33 | ||
34 | #include "lx_core.h" | 34 | #include "lx_core.h" |
35 | 35 | ||
36 | #define LXP "LX6464ES: " | 36 | #define LXP "LX6464ES: " |
37 | 37 | ||
38 | enum { | 38 | enum { |
39 | ES_cmd_free = 0, /* no command executing */ | 39 | ES_cmd_free = 0, /* no command executing */ |
40 | ES_cmd_processing = 1, /* execution of a read/write command */ | 40 | ES_cmd_processing = 1, /* execution of a read/write command */ |
41 | ES_read_pending = 2, /* a asynchron read command is pending */ | 41 | ES_read_pending = 2, /* a asynchron read command is pending */ |
42 | ES_read_finishing = 3, /* a read command has finished waiting (set by | 42 | ES_read_finishing = 3, /* a read command has finished waiting (set by |
43 | * Interrupt or CancelIrp) */ | 43 | * Interrupt or CancelIrp) */ |
44 | }; | 44 | }; |
45 | 45 | ||
46 | enum lx_stream_status { | 46 | enum lx_stream_status { |
47 | LX_STREAM_STATUS_FREE, | 47 | LX_STREAM_STATUS_FREE, |
48 | /* LX_STREAM_STATUS_OPEN, */ | 48 | /* LX_STREAM_STATUS_OPEN, */ |
49 | LX_STREAM_STATUS_SCHEDULE_RUN, | 49 | LX_STREAM_STATUS_SCHEDULE_RUN, |
50 | /* LX_STREAM_STATUS_STARTED, */ | 50 | /* LX_STREAM_STATUS_STARTED, */ |
51 | LX_STREAM_STATUS_RUNNING, | 51 | LX_STREAM_STATUS_RUNNING, |
52 | LX_STREAM_STATUS_SCHEDULE_STOP, | 52 | LX_STREAM_STATUS_SCHEDULE_STOP, |
53 | /* LX_STREAM_STATUS_STOPPED, */ | 53 | /* LX_STREAM_STATUS_STOPPED, */ |
54 | /* LX_STREAM_STATUS_PAUSED */ | 54 | /* LX_STREAM_STATUS_PAUSED */ |
55 | }; | 55 | }; |
56 | 56 | ||
57 | 57 | ||
58 | struct lx_stream { | 58 | struct lx_stream { |
59 | struct snd_pcm_substream *stream; | 59 | struct snd_pcm_substream *stream; |
60 | snd_pcm_uframes_t frame_pos; | 60 | snd_pcm_uframes_t frame_pos; |
61 | enum lx_stream_status status; /* free, open, running, draining | 61 | enum lx_stream_status status; /* free, open, running, draining |
62 | * pause */ | 62 | * pause */ |
63 | int is_capture:1; | 63 | unsigned int is_capture:1; |
64 | }; | 64 | }; |
65 | 65 | ||
66 | 66 | ||
67 | struct lx6464es { | 67 | struct lx6464es { |
68 | struct snd_card *card; | 68 | struct snd_card *card; |
69 | struct pci_dev *pci; | 69 | struct pci_dev *pci; |
70 | int irq; | 70 | int irq; |
71 | 71 | ||
72 | spinlock_t lock; /* interrupt spinlock */ | 72 | spinlock_t lock; /* interrupt spinlock */ |
73 | struct mutex setup_mutex; /* mutex used in hw_params, open | 73 | struct mutex setup_mutex; /* mutex used in hw_params, open |
74 | * and close */ | 74 | * and close */ |
75 | 75 | ||
76 | struct tasklet_struct trigger_tasklet; /* trigger tasklet */ | 76 | struct tasklet_struct trigger_tasklet; /* trigger tasklet */ |
77 | struct tasklet_struct tasklet_capture; | 77 | struct tasklet_struct tasklet_capture; |
78 | struct tasklet_struct tasklet_playback; | 78 | struct tasklet_struct tasklet_playback; |
79 | 79 | ||
80 | /* ports */ | 80 | /* ports */ |
81 | unsigned long port_plx; /* io port (size=256) */ | 81 | unsigned long port_plx; /* io port (size=256) */ |
82 | void __iomem *port_plx_remapped; /* remapped plx port */ | 82 | void __iomem *port_plx_remapped; /* remapped plx port */ |
83 | void __iomem *port_dsp_bar; /* memory port (32-bit, | 83 | void __iomem *port_dsp_bar; /* memory port (32-bit, |
84 | * non-prefetchable, | 84 | * non-prefetchable, |
85 | * size=8K) */ | 85 | * size=8K) */ |
86 | 86 | ||
87 | /* messaging */ | 87 | /* messaging */ |
88 | spinlock_t msg_lock; /* message spinlock */ | 88 | spinlock_t msg_lock; /* message spinlock */ |
89 | struct lx_rmh rmh; | 89 | struct lx_rmh rmh; |
90 | 90 | ||
91 | /* configuration */ | 91 | /* configuration */ |
92 | uint freq_ratio : 2; | 92 | uint freq_ratio : 2; |
93 | uint playback_mute : 1; | 93 | uint playback_mute : 1; |
94 | uint hardware_running[2]; | 94 | uint hardware_running[2]; |
95 | u32 board_sample_rate; /* sample rate read from | 95 | u32 board_sample_rate; /* sample rate read from |
96 | * board */ | 96 | * board */ |
97 | u16 pcm_granularity; /* board blocksize */ | 97 | u16 pcm_granularity; /* board blocksize */ |
98 | 98 | ||
99 | /* dma */ | 99 | /* dma */ |
100 | struct snd_dma_buffer capture_dma_buf; | 100 | struct snd_dma_buffer capture_dma_buf; |
101 | struct snd_dma_buffer playback_dma_buf; | 101 | struct snd_dma_buffer playback_dma_buf; |
102 | 102 | ||
103 | /* pcm */ | 103 | /* pcm */ |
104 | struct snd_pcm *pcm; | 104 | struct snd_pcm *pcm; |
105 | 105 | ||
106 | /* streams */ | 106 | /* streams */ |
107 | struct lx_stream capture_stream; | 107 | struct lx_stream capture_stream; |
108 | struct lx_stream playback_stream; | 108 | struct lx_stream playback_stream; |
109 | }; | 109 | }; |
110 | 110 | ||
111 | 111 | ||
112 | #endif /* LX6464ES_H */ | 112 | #endif /* LX6464ES_H */ |
113 | 113 |
sound/pci/lx6464es/lx_core.c
1 | /* -*- linux-c -*- * | 1 | /* -*- linux-c -*- * |
2 | * | 2 | * |
3 | * ALSA driver for the digigram lx6464es interface | 3 | * ALSA driver for the digigram lx6464es interface |
4 | * low-level interface | 4 | * low-level interface |
5 | * | 5 | * |
6 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> | 6 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; see the file COPYING. If not, write to | 19 | * along with this program; see the file COPYING. If not, write to |
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
21 | * Boston, MA 02111-1307, USA. | 21 | * Boston, MA 02111-1307, USA. |
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | /* #define RMH_DEBUG 1 */ | 25 | /* #define RMH_DEBUG 1 */ |
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | 30 | ||
31 | #include "lx6464es.h" | 31 | #include "lx6464es.h" |
32 | #include "lx_core.h" | 32 | #include "lx_core.h" |
33 | 33 | ||
34 | /* low-level register access */ | 34 | /* low-level register access */ |
35 | 35 | ||
36 | static const unsigned long dsp_port_offsets[] = { | 36 | static const unsigned long dsp_port_offsets[] = { |
37 | 0, | 37 | 0, |
38 | 0x400, | 38 | 0x400, |
39 | 0x401, | 39 | 0x401, |
40 | 0x402, | 40 | 0x402, |
41 | 0x403, | 41 | 0x403, |
42 | 0x404, | 42 | 0x404, |
43 | 0x405, | 43 | 0x405, |
44 | 0x406, | 44 | 0x406, |
45 | 0x407, | 45 | 0x407, |
46 | 0x408, | 46 | 0x408, |
47 | 0x409, | 47 | 0x409, |
48 | 0x40a, | 48 | 0x40a, |
49 | 0x40b, | 49 | 0x40b, |
50 | 0x40c, | 50 | 0x40c, |
51 | 51 | ||
52 | 0x410, | 52 | 0x410, |
53 | 0x411, | 53 | 0x411, |
54 | 0x412, | 54 | 0x412, |
55 | 0x413, | 55 | 0x413, |
56 | 0x414, | 56 | 0x414, |
57 | 0x415, | 57 | 0x415, |
58 | 0x416, | 58 | 0x416, |
59 | 59 | ||
60 | 0x420, | 60 | 0x420, |
61 | 0x430, | 61 | 0x430, |
62 | 0x431, | 62 | 0x431, |
63 | 0x432, | 63 | 0x432, |
64 | 0x433, | 64 | 0x433, |
65 | 0x434, | 65 | 0x434, |
66 | 0x440 | 66 | 0x440 |
67 | }; | 67 | }; |
68 | 68 | ||
69 | static void __iomem *lx_dsp_register(struct lx6464es *chip, int port) | 69 | static void __iomem *lx_dsp_register(struct lx6464es *chip, int port) |
70 | { | 70 | { |
71 | void __iomem *base_address = chip->port_dsp_bar; | 71 | void __iomem *base_address = chip->port_dsp_bar; |
72 | return base_address + dsp_port_offsets[port]*4; | 72 | return base_address + dsp_port_offsets[port]*4; |
73 | } | 73 | } |
74 | 74 | ||
75 | unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port) | 75 | unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port) |
76 | { | 76 | { |
77 | void __iomem *address = lx_dsp_register(chip, port); | 77 | void __iomem *address = lx_dsp_register(chip, port); |
78 | return ioread32(address); | 78 | return ioread32(address); |
79 | } | 79 | } |
80 | 80 | ||
81 | void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len) | 81 | void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len) |
82 | { | 82 | { |
83 | void __iomem *address = lx_dsp_register(chip, port); | 83 | void __iomem *address = lx_dsp_register(chip, port); |
84 | memcpy_fromio(data, address, len*sizeof(u32)); | 84 | memcpy_fromio(data, address, len*sizeof(u32)); |
85 | } | 85 | } |
86 | 86 | ||
87 | 87 | ||
88 | void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data) | 88 | void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data) |
89 | { | 89 | { |
90 | void __iomem *address = lx_dsp_register(chip, port); | 90 | void __iomem *address = lx_dsp_register(chip, port); |
91 | iowrite32(data, address); | 91 | iowrite32(data, address); |
92 | } | 92 | } |
93 | 93 | ||
94 | void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, | 94 | void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, |
95 | u32 len) | 95 | u32 len) |
96 | { | 96 | { |
97 | void __iomem *address = lx_dsp_register(chip, port); | 97 | void __iomem *address = lx_dsp_register(chip, port); |
98 | memcpy_toio(address, data, len*sizeof(u32)); | 98 | memcpy_toio(address, data, len*sizeof(u32)); |
99 | } | 99 | } |
100 | 100 | ||
101 | 101 | ||
102 | static const unsigned long plx_port_offsets[] = { | 102 | static const unsigned long plx_port_offsets[] = { |
103 | 0x04, | 103 | 0x04, |
104 | 0x40, | 104 | 0x40, |
105 | 0x44, | 105 | 0x44, |
106 | 0x48, | 106 | 0x48, |
107 | 0x4c, | 107 | 0x4c, |
108 | 0x50, | 108 | 0x50, |
109 | 0x54, | 109 | 0x54, |
110 | 0x58, | 110 | 0x58, |
111 | 0x5c, | 111 | 0x5c, |
112 | 0x64, | 112 | 0x64, |
113 | 0x68, | 113 | 0x68, |
114 | 0x6C | 114 | 0x6C |
115 | }; | 115 | }; |
116 | 116 | ||
117 | static void __iomem *lx_plx_register(struct lx6464es *chip, int port) | 117 | static void __iomem *lx_plx_register(struct lx6464es *chip, int port) |
118 | { | 118 | { |
119 | void __iomem *base_address = chip->port_plx_remapped; | 119 | void __iomem *base_address = chip->port_plx_remapped; |
120 | return base_address + plx_port_offsets[port]; | 120 | return base_address + plx_port_offsets[port]; |
121 | } | 121 | } |
122 | 122 | ||
123 | unsigned long lx_plx_reg_read(struct lx6464es *chip, int port) | 123 | unsigned long lx_plx_reg_read(struct lx6464es *chip, int port) |
124 | { | 124 | { |
125 | void __iomem *address = lx_plx_register(chip, port); | 125 | void __iomem *address = lx_plx_register(chip, port); |
126 | return ioread32(address); | 126 | return ioread32(address); |
127 | } | 127 | } |
128 | 128 | ||
129 | void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data) | 129 | void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data) |
130 | { | 130 | { |
131 | void __iomem *address = lx_plx_register(chip, port); | 131 | void __iomem *address = lx_plx_register(chip, port); |
132 | iowrite32(data, address); | 132 | iowrite32(data, address); |
133 | } | 133 | } |
134 | 134 | ||
135 | u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr) | 135 | u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr) |
136 | { | 136 | { |
137 | int index; | 137 | int index; |
138 | 138 | ||
139 | switch (mbox_nr) { | 139 | switch (mbox_nr) { |
140 | case 1: | 140 | case 1: |
141 | index = ePLX_MBOX1; break; | 141 | index = ePLX_MBOX1; break; |
142 | case 2: | 142 | case 2: |
143 | index = ePLX_MBOX2; break; | 143 | index = ePLX_MBOX2; break; |
144 | case 3: | 144 | case 3: |
145 | index = ePLX_MBOX3; break; | 145 | index = ePLX_MBOX3; break; |
146 | case 4: | 146 | case 4: |
147 | index = ePLX_MBOX4; break; | 147 | index = ePLX_MBOX4; break; |
148 | case 5: | 148 | case 5: |
149 | index = ePLX_MBOX5; break; | 149 | index = ePLX_MBOX5; break; |
150 | case 6: | 150 | case 6: |
151 | index = ePLX_MBOX6; break; | 151 | index = ePLX_MBOX6; break; |
152 | case 7: | 152 | case 7: |
153 | index = ePLX_MBOX7; break; | 153 | index = ePLX_MBOX7; break; |
154 | case 0: /* reserved for HF flags */ | 154 | case 0: /* reserved for HF flags */ |
155 | snd_BUG(); | 155 | snd_BUG(); |
156 | default: | 156 | default: |
157 | return 0xdeadbeef; | 157 | return 0xdeadbeef; |
158 | } | 158 | } |
159 | 159 | ||
160 | return lx_plx_reg_read(chip, index); | 160 | return lx_plx_reg_read(chip, index); |
161 | } | 161 | } |
162 | 162 | ||
163 | int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value) | 163 | int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value) |
164 | { | 164 | { |
165 | int index = -1; | 165 | int index = -1; |
166 | 166 | ||
167 | switch (mbox_nr) { | 167 | switch (mbox_nr) { |
168 | case 1: | 168 | case 1: |
169 | index = ePLX_MBOX1; break; | 169 | index = ePLX_MBOX1; break; |
170 | case 3: | 170 | case 3: |
171 | index = ePLX_MBOX3; break; | 171 | index = ePLX_MBOX3; break; |
172 | case 4: | 172 | case 4: |
173 | index = ePLX_MBOX4; break; | 173 | index = ePLX_MBOX4; break; |
174 | case 5: | 174 | case 5: |
175 | index = ePLX_MBOX5; break; | 175 | index = ePLX_MBOX5; break; |
176 | case 6: | 176 | case 6: |
177 | index = ePLX_MBOX6; break; | 177 | index = ePLX_MBOX6; break; |
178 | case 7: | 178 | case 7: |
179 | index = ePLX_MBOX7; break; | 179 | index = ePLX_MBOX7; break; |
180 | case 0: /* reserved for HF flags */ | 180 | case 0: /* reserved for HF flags */ |
181 | case 2: /* reserved for Pipe States | 181 | case 2: /* reserved for Pipe States |
182 | * the DSP keeps an image of it */ | 182 | * the DSP keeps an image of it */ |
183 | snd_BUG(); | 183 | snd_BUG(); |
184 | return -EBADRQC; | 184 | return -EBADRQC; |
185 | } | 185 | } |
186 | 186 | ||
187 | lx_plx_reg_write(chip, index, value); | 187 | lx_plx_reg_write(chip, index, value); |
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
190 | 190 | ||
191 | 191 | ||
192 | /* rmh */ | 192 | /* rmh */ |
193 | 193 | ||
194 | #ifdef CONFIG_SND_DEBUG | 194 | #ifdef CONFIG_SND_DEBUG |
195 | #define CMD_NAME(a) a | 195 | #define CMD_NAME(a) a |
196 | #else | 196 | #else |
197 | #define CMD_NAME(a) NULL | 197 | #define CMD_NAME(a) NULL |
198 | #endif | 198 | #endif |
199 | 199 | ||
200 | #define Reg_CSM_MR 0x00000002 | 200 | #define Reg_CSM_MR 0x00000002 |
201 | #define Reg_CSM_MC 0x00000001 | 201 | #define Reg_CSM_MC 0x00000001 |
202 | 202 | ||
203 | struct dsp_cmd_info { | 203 | struct dsp_cmd_info { |
204 | u32 dcCodeOp; /* Op Code of the command (usually 1st 24-bits | 204 | u32 dcCodeOp; /* Op Code of the command (usually 1st 24-bits |
205 | * word).*/ | 205 | * word).*/ |
206 | u16 dcCmdLength; /* Command length in words of 24 bits.*/ | 206 | u16 dcCmdLength; /* Command length in words of 24 bits.*/ |
207 | u16 dcStatusType; /* Status type: 0 for fixed length, 1 for | 207 | u16 dcStatusType; /* Status type: 0 for fixed length, 1 for |
208 | * random. */ | 208 | * random. */ |
209 | u16 dcStatusLength; /* Status length (if fixed).*/ | 209 | u16 dcStatusLength; /* Status length (if fixed).*/ |
210 | char *dcOpName; | 210 | char *dcOpName; |
211 | }; | 211 | }; |
212 | 212 | ||
213 | /* | 213 | /* |
214 | Initialization and control data for the Microblaze interface | 214 | Initialization and control data for the Microblaze interface |
215 | - OpCode: | 215 | - OpCode: |
216 | the opcode field of the command set at the proper offset | 216 | the opcode field of the command set at the proper offset |
217 | - CmdLength | 217 | - CmdLength |
218 | the number of command words | 218 | the number of command words |
219 | - StatusType | 219 | - StatusType |
220 | offset in the status registers: 0 means that the return value may be | 220 | offset in the status registers: 0 means that the return value may be |
221 | different from 0, and must be read | 221 | different from 0, and must be read |
222 | - StatusLength | 222 | - StatusLength |
223 | the number of status words (in addition to the return value) | 223 | the number of status words (in addition to the return value) |
224 | */ | 224 | */ |
225 | 225 | ||
226 | static struct dsp_cmd_info dsp_commands[] = | 226 | static struct dsp_cmd_info dsp_commands[] = |
227 | { | 227 | { |
228 | { (CMD_00_INFO_DEBUG << OPCODE_OFFSET) , 1 /*custom*/ | 228 | { (CMD_00_INFO_DEBUG << OPCODE_OFFSET) , 1 /*custom*/ |
229 | , 1 , 0 /**/ , CMD_NAME("INFO_DEBUG") }, | 229 | , 1 , 0 /**/ , CMD_NAME("INFO_DEBUG") }, |
230 | { (CMD_01_GET_SYS_CFG << OPCODE_OFFSET) , 1 /**/ | 230 | { (CMD_01_GET_SYS_CFG << OPCODE_OFFSET) , 1 /**/ |
231 | , 1 , 2 /**/ , CMD_NAME("GET_SYS_CFG") }, | 231 | , 1 , 2 /**/ , CMD_NAME("GET_SYS_CFG") }, |
232 | { (CMD_02_SET_GRANULARITY << OPCODE_OFFSET) , 1 /**/ | 232 | { (CMD_02_SET_GRANULARITY << OPCODE_OFFSET) , 1 /**/ |
233 | , 1 , 0 /**/ , CMD_NAME("SET_GRANULARITY") }, | 233 | , 1 , 0 /**/ , CMD_NAME("SET_GRANULARITY") }, |
234 | { (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET) , 1 /**/ | 234 | { (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET) , 1 /**/ |
235 | , 1 , 0 /**/ , CMD_NAME("SET_TIMER_IRQ") }, | 235 | , 1 , 0 /**/ , CMD_NAME("SET_TIMER_IRQ") }, |
236 | { (CMD_04_GET_EVENT << OPCODE_OFFSET) , 1 /**/ | 236 | { (CMD_04_GET_EVENT << OPCODE_OFFSET) , 1 /**/ |
237 | , 1 , 0 /*up to 10*/ , CMD_NAME("GET_EVENT") }, | 237 | , 1 , 0 /*up to 10*/ , CMD_NAME("GET_EVENT") }, |
238 | { (CMD_05_GET_PIPES << OPCODE_OFFSET) , 1 /**/ | 238 | { (CMD_05_GET_PIPES << OPCODE_OFFSET) , 1 /**/ |
239 | , 1 , 2 /*up to 4*/ , CMD_NAME("GET_PIPES") }, | 239 | , 1 , 2 /*up to 4*/ , CMD_NAME("GET_PIPES") }, |
240 | { (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET) , 1 /**/ | 240 | { (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET) , 1 /**/ |
241 | , 0 , 0 /**/ , CMD_NAME("ALLOCATE_PIPE") }, | 241 | , 0 , 0 /**/ , CMD_NAME("ALLOCATE_PIPE") }, |
242 | { (CMD_07_RELEASE_PIPE << OPCODE_OFFSET) , 1 /**/ | 242 | { (CMD_07_RELEASE_PIPE << OPCODE_OFFSET) , 1 /**/ |
243 | , 0 , 0 /**/ , CMD_NAME("RELEASE_PIPE") }, | 243 | , 0 , 0 /**/ , CMD_NAME("RELEASE_PIPE") }, |
244 | { (CMD_08_ASK_BUFFERS << OPCODE_OFFSET) , 1 /**/ | 244 | { (CMD_08_ASK_BUFFERS << OPCODE_OFFSET) , 1 /**/ |
245 | , 1 , MAX_STREAM_BUFFER , CMD_NAME("ASK_BUFFERS") }, | 245 | , 1 , MAX_STREAM_BUFFER , CMD_NAME("ASK_BUFFERS") }, |
246 | { (CMD_09_STOP_PIPE << OPCODE_OFFSET) , 1 /**/ | 246 | { (CMD_09_STOP_PIPE << OPCODE_OFFSET) , 1 /**/ |
247 | , 0 , 0 /*up to 2*/ , CMD_NAME("STOP_PIPE") }, | 247 | , 0 , 0 /*up to 2*/ , CMD_NAME("STOP_PIPE") }, |
248 | { (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET) , 1 /**/ | 248 | { (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET) , 1 /**/ |
249 | , 1 , 1 /*up to 2*/ , CMD_NAME("GET_PIPE_SPL_COUNT") }, | 249 | , 1 , 1 /*up to 2*/ , CMD_NAME("GET_PIPE_SPL_COUNT") }, |
250 | { (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET) , 1 /*up to 5*/ | 250 | { (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET) , 1 /*up to 5*/ |
251 | , 1 , 0 /**/ , CMD_NAME("TOGGLE_PIPE_STATE") }, | 251 | , 1 , 0 /**/ , CMD_NAME("TOGGLE_PIPE_STATE") }, |
252 | { (CMD_0C_DEF_STREAM << OPCODE_OFFSET) , 1 /*up to 4*/ | 252 | { (CMD_0C_DEF_STREAM << OPCODE_OFFSET) , 1 /*up to 4*/ |
253 | , 1 , 0 /**/ , CMD_NAME("DEF_STREAM") }, | 253 | , 1 , 0 /**/ , CMD_NAME("DEF_STREAM") }, |
254 | { (CMD_0D_SET_MUTE << OPCODE_OFFSET) , 3 /**/ | 254 | { (CMD_0D_SET_MUTE << OPCODE_OFFSET) , 3 /**/ |
255 | , 1 , 0 /**/ , CMD_NAME("SET_MUTE") }, | 255 | , 1 , 0 /**/ , CMD_NAME("SET_MUTE") }, |
256 | { (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET) , 1/**/ | 256 | { (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET) , 1/**/ |
257 | , 1 , 2 /**/ , CMD_NAME("GET_STREAM_SPL_COUNT") }, | 257 | , 1 , 2 /**/ , CMD_NAME("GET_STREAM_SPL_COUNT") }, |
258 | { (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET) , 3 /*up to 4*/ | 258 | { (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET) , 3 /*up to 4*/ |
259 | , 0 , 1 /**/ , CMD_NAME("UPDATE_BUFFER") }, | 259 | , 0 , 1 /**/ , CMD_NAME("UPDATE_BUFFER") }, |
260 | { (CMD_10_GET_BUFFER << OPCODE_OFFSET) , 1 /**/ | 260 | { (CMD_10_GET_BUFFER << OPCODE_OFFSET) , 1 /**/ |
261 | , 1 , 4 /**/ , CMD_NAME("GET_BUFFER") }, | 261 | , 1 , 4 /**/ , CMD_NAME("GET_BUFFER") }, |
262 | { (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET) , 1 /**/ | 262 | { (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET) , 1 /**/ |
263 | , 1 , 1 /*up to 4*/ , CMD_NAME("CANCEL_BUFFER") }, | 263 | , 1 , 1 /*up to 4*/ , CMD_NAME("CANCEL_BUFFER") }, |
264 | { (CMD_12_GET_PEAK << OPCODE_OFFSET) , 1 /**/ | 264 | { (CMD_12_GET_PEAK << OPCODE_OFFSET) , 1 /**/ |
265 | , 1 , 1 /**/ , CMD_NAME("GET_PEAK") }, | 265 | , 1 , 1 /**/ , CMD_NAME("GET_PEAK") }, |
266 | { (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET) , 1 /**/ | 266 | { (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET) , 1 /**/ |
267 | , 1 , 0 /**/ , CMD_NAME("SET_STREAM_STATE") }, | 267 | , 1 , 0 /**/ , CMD_NAME("SET_STREAM_STATE") }, |
268 | }; | 268 | }; |
269 | 269 | ||
270 | static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd) | 270 | static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd) |
271 | { | 271 | { |
272 | snd_BUG_ON(cmd >= CMD_14_INVALID); | 272 | snd_BUG_ON(cmd >= CMD_14_INVALID); |
273 | 273 | ||
274 | rmh->cmd[0] = dsp_commands[cmd].dcCodeOp; | 274 | rmh->cmd[0] = dsp_commands[cmd].dcCodeOp; |
275 | rmh->cmd_len = dsp_commands[cmd].dcCmdLength; | 275 | rmh->cmd_len = dsp_commands[cmd].dcCmdLength; |
276 | rmh->stat_len = dsp_commands[cmd].dcStatusLength; | 276 | rmh->stat_len = dsp_commands[cmd].dcStatusLength; |
277 | rmh->dsp_stat = dsp_commands[cmd].dcStatusType; | 277 | rmh->dsp_stat = dsp_commands[cmd].dcStatusType; |
278 | rmh->cmd_idx = cmd; | 278 | rmh->cmd_idx = cmd; |
279 | memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32)); | 279 | memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32)); |
280 | 280 | ||
281 | #ifdef CONFIG_SND_DEBUG | 281 | #ifdef CONFIG_SND_DEBUG |
282 | memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32)); | 282 | memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32)); |
283 | #endif | 283 | #endif |
284 | #ifdef RMH_DEBUG | 284 | #ifdef RMH_DEBUG |
285 | rmh->cmd_idx = cmd; | 285 | rmh->cmd_idx = cmd; |
286 | #endif | 286 | #endif |
287 | } | 287 | } |
288 | 288 | ||
289 | #ifdef RMH_DEBUG | 289 | #ifdef RMH_DEBUG |
290 | #define LXRMH "lx6464es rmh: " | 290 | #define LXRMH "lx6464es rmh: " |
291 | static void lx_message_dump(struct lx_rmh *rmh) | 291 | static void lx_message_dump(struct lx_rmh *rmh) |
292 | { | 292 | { |
293 | u8 idx = rmh->cmd_idx; | 293 | u8 idx = rmh->cmd_idx; |
294 | int i; | 294 | int i; |
295 | 295 | ||
296 | snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName); | 296 | snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName); |
297 | 297 | ||
298 | for (i = 0; i != rmh->cmd_len; ++i) | 298 | for (i = 0; i != rmh->cmd_len; ++i) |
299 | snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]); | 299 | snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]); |
300 | 300 | ||
301 | for (i = 0; i != rmh->stat_len; ++i) | 301 | for (i = 0; i != rmh->stat_len; ++i) |
302 | snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]); | 302 | snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]); |
303 | snd_printk("\n"); | 303 | snd_printk("\n"); |
304 | } | 304 | } |
305 | #else | 305 | #else |
306 | static inline void lx_message_dump(struct lx_rmh *rmh) | 306 | static inline void lx_message_dump(struct lx_rmh *rmh) |
307 | {} | 307 | {} |
308 | #endif | 308 | #endif |
309 | 309 | ||
310 | 310 | ||
311 | 311 | ||
312 | /* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */ | 312 | /* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */ |
313 | #define XILINX_TIMEOUT_MS 40 | 313 | #define XILINX_TIMEOUT_MS 40 |
314 | #define XILINX_POLL_NO_SLEEP 100 | 314 | #define XILINX_POLL_NO_SLEEP 100 |
315 | #define XILINX_POLL_ITERATIONS 150 | 315 | #define XILINX_POLL_ITERATIONS 150 |
316 | 316 | ||
317 | 317 | ||
318 | static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) | 318 | static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) |
319 | { | 319 | { |
320 | u32 reg = ED_DSP_TIMED_OUT; | 320 | u32 reg = ED_DSP_TIMED_OUT; |
321 | int dwloop; | 321 | int dwloop; |
322 | 322 | ||
323 | if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { | 323 | if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { |
324 | snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); | 324 | snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); |
325 | return -EBUSY; | 325 | return -EBUSY; |
326 | } | 326 | } |
327 | 327 | ||
328 | /* write command */ | 328 | /* write command */ |
329 | lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); | 329 | lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); |
330 | 330 | ||
331 | /* MicoBlaze gogogo */ | 331 | /* MicoBlaze gogogo */ |
332 | lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); | 332 | lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); |
333 | 333 | ||
334 | /* wait for device to answer */ | 334 | /* wait for device to answer */ |
335 | for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) { | 335 | for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) { |
336 | if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) { | 336 | if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) { |
337 | if (rmh->dsp_stat == 0) | 337 | if (rmh->dsp_stat == 0) |
338 | reg = lx_dsp_reg_read(chip, eReg_CRM1); | 338 | reg = lx_dsp_reg_read(chip, eReg_CRM1); |
339 | else | 339 | else |
340 | reg = 0; | 340 | reg = 0; |
341 | goto polling_successful; | 341 | goto polling_successful; |
342 | } else | 342 | } else |
343 | udelay(1); | 343 | udelay(1); |
344 | } | 344 | } |
345 | snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! " | 345 | snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! " |
346 | "polling failed\n"); | 346 | "polling failed\n"); |
347 | 347 | ||
348 | polling_successful: | 348 | polling_successful: |
349 | if ((reg & ERROR_VALUE) == 0) { | 349 | if ((reg & ERROR_VALUE) == 0) { |
350 | /* read response */ | 350 | /* read response */ |
351 | if (rmh->stat_len) { | 351 | if (rmh->stat_len) { |
352 | snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); | 352 | snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); |
353 | lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, | 353 | lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, |
354 | rmh->stat_len); | 354 | rmh->stat_len); |
355 | } | 355 | } |
356 | } else | 356 | } else |
357 | snd_printk(LXP "rmh error: %08x\n", reg); | 357 | snd_printk(LXP "rmh error: %08x\n", reg); |
358 | 358 | ||
359 | /* clear Reg_CSM_MR */ | 359 | /* clear Reg_CSM_MR */ |
360 | lx_dsp_reg_write(chip, eReg_CSM, 0); | 360 | lx_dsp_reg_write(chip, eReg_CSM, 0); |
361 | 361 | ||
362 | switch (reg) { | 362 | switch (reg) { |
363 | case ED_DSP_TIMED_OUT: | 363 | case ED_DSP_TIMED_OUT: |
364 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); | 364 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); |
365 | return -ETIMEDOUT; | 365 | return -ETIMEDOUT; |
366 | 366 | ||
367 | case ED_DSP_CRASHED: | 367 | case ED_DSP_CRASHED: |
368 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); | 368 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); |
369 | return -EAGAIN; | 369 | return -EAGAIN; |
370 | } | 370 | } |
371 | 371 | ||
372 | lx_message_dump(rmh); | 372 | lx_message_dump(rmh); |
373 | 373 | ||
374 | return reg; | 374 | return reg; |
375 | } | 375 | } |
376 | 376 | ||
377 | 377 | ||
378 | /* low-level dsp access */ | 378 | /* low-level dsp access */ |
379 | int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) | 379 | int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) |
380 | { | 380 | { |
381 | u16 ret; | 381 | u16 ret; |
382 | unsigned long flags; | 382 | unsigned long flags; |
383 | 383 | ||
384 | spin_lock_irqsave(&chip->msg_lock, flags); | 384 | spin_lock_irqsave(&chip->msg_lock, flags); |
385 | 385 | ||
386 | lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); | 386 | lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); |
387 | ret = lx_message_send_atomic(chip, &chip->rmh); | 387 | ret = lx_message_send_atomic(chip, &chip->rmh); |
388 | 388 | ||
389 | *rdsp_version = chip->rmh.stat[1]; | 389 | *rdsp_version = chip->rmh.stat[1]; |
390 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 390 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
391 | return ret; | 391 | return ret; |
392 | } | 392 | } |
393 | 393 | ||
394 | int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) | 394 | int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) |
395 | { | 395 | { |
396 | u16 ret = 0; | 396 | u16 ret = 0; |
397 | unsigned long flags; | 397 | unsigned long flags; |
398 | u32 freq_raw = 0; | 398 | u32 freq_raw = 0; |
399 | u32 freq = 0; | 399 | u32 freq = 0; |
400 | u32 frequency = 0; | 400 | u32 frequency = 0; |
401 | 401 | ||
402 | spin_lock_irqsave(&chip->msg_lock, flags); | 402 | spin_lock_irqsave(&chip->msg_lock, flags); |
403 | 403 | ||
404 | lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); | 404 | lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); |
405 | ret = lx_message_send_atomic(chip, &chip->rmh); | 405 | ret = lx_message_send_atomic(chip, &chip->rmh); |
406 | 406 | ||
407 | if (ret == 0) { | 407 | if (ret == 0) { |
408 | freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET; | 408 | freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET; |
409 | freq = freq_raw & XES_FREQ_COUNT8_MASK; | 409 | freq = freq_raw & XES_FREQ_COUNT8_MASK; |
410 | 410 | ||
411 | if ((freq < XES_FREQ_COUNT8_48_MAX) || | 411 | if ((freq < XES_FREQ_COUNT8_48_MAX) || |
412 | (freq > XES_FREQ_COUNT8_44_MIN)) | 412 | (freq > XES_FREQ_COUNT8_44_MIN)) |
413 | frequency = 0; /* unknown */ | 413 | frequency = 0; /* unknown */ |
414 | else if (freq >= XES_FREQ_COUNT8_44_MAX) | 414 | else if (freq >= XES_FREQ_COUNT8_44_MAX) |
415 | frequency = 44100; | 415 | frequency = 44100; |
416 | else | 416 | else |
417 | frequency = 48000; | 417 | frequency = 48000; |
418 | } | 418 | } |
419 | 419 | ||
420 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 420 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
421 | 421 | ||
422 | *rfreq = frequency * chip->freq_ratio; | 422 | *rfreq = frequency * chip->freq_ratio; |
423 | 423 | ||
424 | return ret; | 424 | return ret; |
425 | } | 425 | } |
426 | 426 | ||
427 | int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address) | 427 | int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address) |
428 | { | 428 | { |
429 | u32 macmsb, maclsb; | 429 | u32 macmsb, maclsb; |
430 | 430 | ||
431 | macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF; | 431 | macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF; |
432 | maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF; | 432 | maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF; |
433 | 433 | ||
434 | /* todo: endianess handling */ | 434 | /* todo: endianess handling */ |
435 | mac_address[5] = ((u8 *)(&maclsb))[0]; | 435 | mac_address[5] = ((u8 *)(&maclsb))[0]; |
436 | mac_address[4] = ((u8 *)(&maclsb))[1]; | 436 | mac_address[4] = ((u8 *)(&maclsb))[1]; |
437 | mac_address[3] = ((u8 *)(&maclsb))[2]; | 437 | mac_address[3] = ((u8 *)(&maclsb))[2]; |
438 | mac_address[2] = ((u8 *)(&macmsb))[0]; | 438 | mac_address[2] = ((u8 *)(&macmsb))[0]; |
439 | mac_address[1] = ((u8 *)(&macmsb))[1]; | 439 | mac_address[1] = ((u8 *)(&macmsb))[1]; |
440 | mac_address[0] = ((u8 *)(&macmsb))[2]; | 440 | mac_address[0] = ((u8 *)(&macmsb))[2]; |
441 | 441 | ||
442 | return 0; | 442 | return 0; |
443 | } | 443 | } |
444 | 444 | ||
445 | 445 | ||
446 | int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran) | 446 | int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran) |
447 | { | 447 | { |
448 | unsigned long flags; | 448 | unsigned long flags; |
449 | int ret; | 449 | int ret; |
450 | 450 | ||
451 | spin_lock_irqsave(&chip->msg_lock, flags); | 451 | spin_lock_irqsave(&chip->msg_lock, flags); |
452 | 452 | ||
453 | lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY); | 453 | lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY); |
454 | chip->rmh.cmd[0] |= gran; | 454 | chip->rmh.cmd[0] |= gran; |
455 | 455 | ||
456 | ret = lx_message_send_atomic(chip, &chip->rmh); | 456 | ret = lx_message_send_atomic(chip, &chip->rmh); |
457 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 457 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
458 | return ret; | 458 | return ret; |
459 | } | 459 | } |
460 | 460 | ||
461 | int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) | 461 | int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) |
462 | { | 462 | { |
463 | unsigned long flags; | 463 | unsigned long flags; |
464 | int ret; | 464 | int ret; |
465 | 465 | ||
466 | spin_lock_irqsave(&chip->msg_lock, flags); | 466 | spin_lock_irqsave(&chip->msg_lock, flags); |
467 | 467 | ||
468 | lx_message_init(&chip->rmh, CMD_04_GET_EVENT); | 468 | lx_message_init(&chip->rmh, CMD_04_GET_EVENT); |
469 | chip->rmh.stat_len = 9; /* we don't necessarily need the full length */ | 469 | chip->rmh.stat_len = 9; /* we don't necessarily need the full length */ |
470 | 470 | ||
471 | ret = lx_message_send_atomic(chip, &chip->rmh); | 471 | ret = lx_message_send_atomic(chip, &chip->rmh); |
472 | 472 | ||
473 | if (!ret) | 473 | if (!ret) |
474 | memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32)); | 474 | memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32)); |
475 | 475 | ||
476 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 476 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
477 | return ret; | 477 | return ret; |
478 | } | 478 | } |
479 | 479 | ||
480 | #define CSES_TIMEOUT 100 /* microseconds */ | 480 | #define CSES_TIMEOUT 100 /* microseconds */ |
481 | #define CSES_CE 0x0001 | 481 | #define CSES_CE 0x0001 |
482 | #define CSES_BROADCAST 0x0002 | 482 | #define CSES_BROADCAST 0x0002 |
483 | #define CSES_UPDATE_LDSV 0x0004 | 483 | #define CSES_UPDATE_LDSV 0x0004 |
484 | 484 | ||
485 | int lx_dsp_es_check_pipeline(struct lx6464es *chip) | 485 | int lx_dsp_es_check_pipeline(struct lx6464es *chip) |
486 | { | 486 | { |
487 | int i; | 487 | int i; |
488 | 488 | ||
489 | for (i = 0; i != CSES_TIMEOUT; ++i) { | 489 | for (i = 0; i != CSES_TIMEOUT; ++i) { |
490 | /* | 490 | /* |
491 | * le bit CSES_UPDATE_LDSV est à 1 dés que le macprog | 491 | * le bit CSES_UPDATE_LDSV est à 1 dés que le macprog |
492 | * est pret. il re-passe à 0 lorsque le premier read a | 492 | * est pret. il re-passe à 0 lorsque le premier read a |
493 | * été fait. pour l'instant on retire le test car ce bit | 493 | * été fait. pour l'instant on retire le test car ce bit |
494 | * passe a 1 environ 200 à 400 ms aprés que le registre | 494 | * passe a 1 environ 200 à 400 ms aprés que le registre |
495 | * confES à été écrit (kick du xilinx ES). | 495 | * confES à été écrit (kick du xilinx ES). |
496 | * | 496 | * |
497 | * On ne teste que le bit CE. | 497 | * On ne teste que le bit CE. |
498 | * */ | 498 | * */ |
499 | 499 | ||
500 | u32 cses = lx_dsp_reg_read(chip, eReg_CSES); | 500 | u32 cses = lx_dsp_reg_read(chip, eReg_CSES); |
501 | 501 | ||
502 | if ((cses & CSES_CE) == 0) | 502 | if ((cses & CSES_CE) == 0) |
503 | return 0; | 503 | return 0; |
504 | 504 | ||
505 | udelay(1); | 505 | udelay(1); |
506 | } | 506 | } |
507 | 507 | ||
508 | return -ETIMEDOUT; | 508 | return -ETIMEDOUT; |
509 | } | 509 | } |
510 | 510 | ||
511 | 511 | ||
512 | #define PIPE_INFO_TO_CMD(capture, pipe) \ | 512 | #define PIPE_INFO_TO_CMD(capture, pipe) \ |
513 | ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) | 513 | ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) |
514 | 514 | ||
515 | 515 | ||
516 | 516 | ||
517 | /* low-level pipe handling */ | 517 | /* low-level pipe handling */ |
518 | int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, | 518 | int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, |
519 | int channels) | 519 | int channels) |
520 | { | 520 | { |
521 | int err; | 521 | int err; |
522 | unsigned long flags; | 522 | unsigned long flags; |
523 | 523 | ||
524 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 524 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
525 | 525 | ||
526 | spin_lock_irqsave(&chip->msg_lock, flags); | 526 | spin_lock_irqsave(&chip->msg_lock, flags); |
527 | lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE); | 527 | lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE); |
528 | 528 | ||
529 | chip->rmh.cmd[0] |= pipe_cmd; | 529 | chip->rmh.cmd[0] |= pipe_cmd; |
530 | chip->rmh.cmd[0] |= channels; | 530 | chip->rmh.cmd[0] |= channels; |
531 | 531 | ||
532 | err = lx_message_send_atomic(chip, &chip->rmh); | 532 | err = lx_message_send_atomic(chip, &chip->rmh); |
533 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 533 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
534 | 534 | ||
535 | if (err != 0) | 535 | if (err != 0) |
536 | snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n"); | 536 | snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n"); |
537 | 537 | ||
538 | return err; | 538 | return err; |
539 | } | 539 | } |
540 | 540 | ||
541 | int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) | 541 | int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) |
542 | { | 542 | { |
543 | int err; | 543 | int err; |
544 | unsigned long flags; | 544 | unsigned long flags; |
545 | 545 | ||
546 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 546 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
547 | 547 | ||
548 | spin_lock_irqsave(&chip->msg_lock, flags); | 548 | spin_lock_irqsave(&chip->msg_lock, flags); |
549 | lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE); | 549 | lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE); |
550 | 550 | ||
551 | chip->rmh.cmd[0] |= pipe_cmd; | 551 | chip->rmh.cmd[0] |= pipe_cmd; |
552 | 552 | ||
553 | err = lx_message_send_atomic(chip, &chip->rmh); | 553 | err = lx_message_send_atomic(chip, &chip->rmh); |
554 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 554 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
555 | 555 | ||
556 | return err; | 556 | return err; |
557 | } | 557 | } |
558 | 558 | ||
559 | int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, | 559 | int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, |
560 | u32 *r_needed, u32 *r_freed, u32 *size_array) | 560 | u32 *r_needed, u32 *r_freed, u32 *size_array) |
561 | { | 561 | { |
562 | int err; | 562 | int err; |
563 | unsigned long flags; | 563 | unsigned long flags; |
564 | 564 | ||
565 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 565 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
566 | 566 | ||
567 | #ifdef CONFIG_SND_DEBUG | 567 | #ifdef CONFIG_SND_DEBUG |
568 | if (size_array) | 568 | if (size_array) |
569 | memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER); | 569 | memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER); |
570 | #endif | 570 | #endif |
571 | 571 | ||
572 | *r_needed = 0; | 572 | *r_needed = 0; |
573 | *r_freed = 0; | 573 | *r_freed = 0; |
574 | 574 | ||
575 | spin_lock_irqsave(&chip->msg_lock, flags); | 575 | spin_lock_irqsave(&chip->msg_lock, flags); |
576 | lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS); | 576 | lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS); |
577 | 577 | ||
578 | chip->rmh.cmd[0] |= pipe_cmd; | 578 | chip->rmh.cmd[0] |= pipe_cmd; |
579 | 579 | ||
580 | err = lx_message_send_atomic(chip, &chip->rmh); | 580 | err = lx_message_send_atomic(chip, &chip->rmh); |
581 | 581 | ||
582 | if (!err) { | 582 | if (!err) { |
583 | int i; | 583 | int i; |
584 | for (i = 0; i < MAX_STREAM_BUFFER; ++i) { | 584 | for (i = 0; i < MAX_STREAM_BUFFER; ++i) { |
585 | u32 stat = chip->rmh.stat[i]; | 585 | u32 stat = chip->rmh.stat[i]; |
586 | if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) { | 586 | if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) { |
587 | /* finished */ | 587 | /* finished */ |
588 | *r_freed += 1; | 588 | *r_freed += 1; |
589 | if (size_array) | 589 | if (size_array) |
590 | size_array[i] = stat & MASK_DATA_SIZE; | 590 | size_array[i] = stat & MASK_DATA_SIZE; |
591 | } else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET)) | 591 | } else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET)) |
592 | == 0) | 592 | == 0) |
593 | /* free */ | 593 | /* free */ |
594 | *r_needed += 1; | 594 | *r_needed += 1; |
595 | } | 595 | } |
596 | 596 | ||
597 | #if 0 | 597 | #if 0 |
598 | snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", | 598 | snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", |
599 | *r_needed, *r_freed); | 599 | *r_needed, *r_freed); |
600 | for (i = 0; i < MAX_STREAM_BUFFER; ++i) { | 600 | for (i = 0; i < MAX_STREAM_BUFFER; ++i) { |
601 | for (i = 0; i != chip->rmh.stat_len; ++i) | 601 | for (i = 0; i != chip->rmh.stat_len; ++i) |
602 | snd_printdd(" stat[%d]: %x, %x\n", i, | 602 | snd_printdd(" stat[%d]: %x, %x\n", i, |
603 | chip->rmh.stat[i], | 603 | chip->rmh.stat[i], |
604 | chip->rmh.stat[i] & MASK_DATA_SIZE); | 604 | chip->rmh.stat[i] & MASK_DATA_SIZE); |
605 | } | 605 | } |
606 | #endif | 606 | #endif |
607 | } | 607 | } |
608 | 608 | ||
609 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 609 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
610 | return err; | 610 | return err; |
611 | } | 611 | } |
612 | 612 | ||
613 | 613 | ||
614 | int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture) | 614 | int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture) |
615 | { | 615 | { |
616 | int err; | 616 | int err; |
617 | unsigned long flags; | 617 | unsigned long flags; |
618 | 618 | ||
619 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 619 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
620 | 620 | ||
621 | spin_lock_irqsave(&chip->msg_lock, flags); | 621 | spin_lock_irqsave(&chip->msg_lock, flags); |
622 | lx_message_init(&chip->rmh, CMD_09_STOP_PIPE); | 622 | lx_message_init(&chip->rmh, CMD_09_STOP_PIPE); |
623 | 623 | ||
624 | chip->rmh.cmd[0] |= pipe_cmd; | 624 | chip->rmh.cmd[0] |= pipe_cmd; |
625 | 625 | ||
626 | err = lx_message_send_atomic(chip, &chip->rmh); | 626 | err = lx_message_send_atomic(chip, &chip->rmh); |
627 | 627 | ||
628 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 628 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
629 | return err; | 629 | return err; |
630 | } | 630 | } |
631 | 631 | ||
632 | static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture) | 632 | static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture) |
633 | { | 633 | { |
634 | int err; | 634 | int err; |
635 | unsigned long flags; | 635 | unsigned long flags; |
636 | 636 | ||
637 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 637 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
638 | 638 | ||
639 | spin_lock_irqsave(&chip->msg_lock, flags); | 639 | spin_lock_irqsave(&chip->msg_lock, flags); |
640 | lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE); | 640 | lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE); |
641 | 641 | ||
642 | chip->rmh.cmd[0] |= pipe_cmd; | 642 | chip->rmh.cmd[0] |= pipe_cmd; |
643 | 643 | ||
644 | err = lx_message_send_atomic(chip, &chip->rmh); | 644 | err = lx_message_send_atomic(chip, &chip->rmh); |
645 | 645 | ||
646 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 646 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
647 | return err; | 647 | return err; |
648 | } | 648 | } |
649 | 649 | ||
650 | 650 | ||
651 | int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture) | 651 | int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture) |
652 | { | 652 | { |
653 | int err; | 653 | int err; |
654 | 654 | ||
655 | err = lx_pipe_wait_for_idle(chip, pipe, is_capture); | 655 | err = lx_pipe_wait_for_idle(chip, pipe, is_capture); |
656 | if (err < 0) | 656 | if (err < 0) |
657 | return err; | 657 | return err; |
658 | 658 | ||
659 | err = lx_pipe_toggle_state(chip, pipe, is_capture); | 659 | err = lx_pipe_toggle_state(chip, pipe, is_capture); |
660 | 660 | ||
661 | return err; | 661 | return err; |
662 | } | 662 | } |
663 | 663 | ||
664 | int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture) | 664 | int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture) |
665 | { | 665 | { |
666 | int err = 0; | 666 | int err = 0; |
667 | 667 | ||
668 | err = lx_pipe_wait_for_start(chip, pipe, is_capture); | 668 | err = lx_pipe_wait_for_start(chip, pipe, is_capture); |
669 | if (err < 0) | 669 | if (err < 0) |
670 | return err; | 670 | return err; |
671 | 671 | ||
672 | err = lx_pipe_toggle_state(chip, pipe, is_capture); | 672 | err = lx_pipe_toggle_state(chip, pipe, is_capture); |
673 | 673 | ||
674 | return err; | 674 | return err; |
675 | } | 675 | } |
676 | 676 | ||
677 | 677 | ||
678 | int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, | 678 | int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, |
679 | u64 *rsample_count) | 679 | u64 *rsample_count) |
680 | { | 680 | { |
681 | int err; | 681 | int err; |
682 | unsigned long flags; | 682 | unsigned long flags; |
683 | 683 | ||
684 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 684 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
685 | 685 | ||
686 | spin_lock_irqsave(&chip->msg_lock, flags); | 686 | spin_lock_irqsave(&chip->msg_lock, flags); |
687 | lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); | 687 | lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); |
688 | 688 | ||
689 | chip->rmh.cmd[0] |= pipe_cmd; | 689 | chip->rmh.cmd[0] |= pipe_cmd; |
690 | chip->rmh.stat_len = 2; /* need all words here! */ | 690 | chip->rmh.stat_len = 2; /* need all words here! */ |
691 | 691 | ||
692 | err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */ | 692 | err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */ |
693 | 693 | ||
694 | if (err != 0) | 694 | if (err != 0) |
695 | snd_printk(KERN_ERR | 695 | snd_printk(KERN_ERR |
696 | "lx6464es: could not query pipe's sample count\n"); | 696 | "lx6464es: could not query pipe's sample count\n"); |
697 | else { | 697 | else { |
698 | *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI) | 698 | *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI) |
699 | << 24) /* hi part */ | 699 | << 24) /* hi part */ |
700 | + chip->rmh.stat[1]; /* lo part */ | 700 | + chip->rmh.stat[1]; /* lo part */ |
701 | } | 701 | } |
702 | 702 | ||
703 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 703 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
704 | return err; | 704 | return err; |
705 | } | 705 | } |
706 | 706 | ||
707 | int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) | 707 | int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) |
708 | { | 708 | { |
709 | int err; | 709 | int err; |
710 | unsigned long flags; | 710 | unsigned long flags; |
711 | 711 | ||
712 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 712 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
713 | 713 | ||
714 | spin_lock_irqsave(&chip->msg_lock, flags); | 714 | spin_lock_irqsave(&chip->msg_lock, flags); |
715 | lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); | 715 | lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); |
716 | 716 | ||
717 | chip->rmh.cmd[0] |= pipe_cmd; | 717 | chip->rmh.cmd[0] |= pipe_cmd; |
718 | 718 | ||
719 | err = lx_message_send_atomic(chip, &chip->rmh); | 719 | err = lx_message_send_atomic(chip, &chip->rmh); |
720 | 720 | ||
721 | if (err != 0) | 721 | if (err != 0) |
722 | snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n"); | 722 | snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n"); |
723 | else | 723 | else |
724 | *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; | 724 | *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; |
725 | 725 | ||
726 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 726 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
727 | return err; | 727 | return err; |
728 | } | 728 | } |
729 | 729 | ||
730 | static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe, | 730 | static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe, |
731 | int is_capture, u16 state) | 731 | int is_capture, u16 state) |
732 | { | 732 | { |
733 | int i; | 733 | int i; |
734 | 734 | ||
735 | /* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms: | 735 | /* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms: |
736 | * timeout 50 ms */ | 736 | * timeout 50 ms */ |
737 | for (i = 0; i != 50; ++i) { | 737 | for (i = 0; i != 50; ++i) { |
738 | u16 current_state; | 738 | u16 current_state; |
739 | int err = lx_pipe_state(chip, pipe, is_capture, ¤t_state); | 739 | int err = lx_pipe_state(chip, pipe, is_capture, ¤t_state); |
740 | 740 | ||
741 | if (err < 0) | 741 | if (err < 0) |
742 | return err; | 742 | return err; |
743 | 743 | ||
744 | if (current_state == state) | 744 | if (current_state == state) |
745 | return 0; | 745 | return 0; |
746 | 746 | ||
747 | mdelay(1); | 747 | mdelay(1); |
748 | } | 748 | } |
749 | 749 | ||
750 | return -ETIMEDOUT; | 750 | return -ETIMEDOUT; |
751 | } | 751 | } |
752 | 752 | ||
753 | int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture) | 753 | int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture) |
754 | { | 754 | { |
755 | return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN); | 755 | return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN); |
756 | } | 756 | } |
757 | 757 | ||
758 | int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture) | 758 | int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture) |
759 | { | 759 | { |
760 | return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE); | 760 | return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE); |
761 | } | 761 | } |
762 | 762 | ||
763 | /* low-level stream handling */ | 763 | /* low-level stream handling */ |
764 | int lx_stream_set_state(struct lx6464es *chip, u32 pipe, | 764 | int lx_stream_set_state(struct lx6464es *chip, u32 pipe, |
765 | int is_capture, enum stream_state_t state) | 765 | int is_capture, enum stream_state_t state) |
766 | { | 766 | { |
767 | int err; | 767 | int err; |
768 | unsigned long flags; | 768 | unsigned long flags; |
769 | 769 | ||
770 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 770 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
771 | 771 | ||
772 | spin_lock_irqsave(&chip->msg_lock, flags); | 772 | spin_lock_irqsave(&chip->msg_lock, flags); |
773 | lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE); | 773 | lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE); |
774 | 774 | ||
775 | chip->rmh.cmd[0] |= pipe_cmd; | 775 | chip->rmh.cmd[0] |= pipe_cmd; |
776 | chip->rmh.cmd[0] |= state; | 776 | chip->rmh.cmd[0] |= state; |
777 | 777 | ||
778 | err = lx_message_send_atomic(chip, &chip->rmh); | 778 | err = lx_message_send_atomic(chip, &chip->rmh); |
779 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 779 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
780 | 780 | ||
781 | return err; | 781 | return err; |
782 | } | 782 | } |
783 | 783 | ||
784 | int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, | 784 | int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, |
785 | u32 pipe, int is_capture) | 785 | u32 pipe, int is_capture) |
786 | { | 786 | { |
787 | int err; | 787 | int err; |
788 | unsigned long flags; | 788 | unsigned long flags; |
789 | 789 | ||
790 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 790 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
791 | 791 | ||
792 | u32 channels = runtime->channels; | 792 | u32 channels = runtime->channels; |
793 | 793 | ||
794 | if (runtime->channels != channels) | 794 | if (runtime->channels != channels) |
795 | snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d", | 795 | snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d", |
796 | runtime->channels, channels); | 796 | runtime->channels, channels); |
797 | 797 | ||
798 | spin_lock_irqsave(&chip->msg_lock, flags); | 798 | spin_lock_irqsave(&chip->msg_lock, flags); |
799 | lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); | 799 | lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); |
800 | 800 | ||
801 | chip->rmh.cmd[0] |= pipe_cmd; | 801 | chip->rmh.cmd[0] |= pipe_cmd; |
802 | 802 | ||
803 | if (runtime->sample_bits == 16) | 803 | if (runtime->sample_bits == 16) |
804 | /* 16 bit format */ | 804 | /* 16 bit format */ |
805 | chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET); | 805 | chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET); |
806 | 806 | ||
807 | if (snd_pcm_format_little_endian(runtime->format)) | 807 | if (snd_pcm_format_little_endian(runtime->format)) |
808 | /* little endian/intel format */ | 808 | /* little endian/intel format */ |
809 | chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET); | 809 | chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET); |
810 | 810 | ||
811 | chip->rmh.cmd[0] |= channels-1; | 811 | chip->rmh.cmd[0] |= channels-1; |
812 | 812 | ||
813 | err = lx_message_send_atomic(chip, &chip->rmh); | 813 | err = lx_message_send_atomic(chip, &chip->rmh); |
814 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 814 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
815 | 815 | ||
816 | return err; | 816 | return err; |
817 | } | 817 | } |
818 | 818 | ||
819 | int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, | 819 | int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, |
820 | int *rstate) | 820 | int *rstate) |
821 | { | 821 | { |
822 | int err; | 822 | int err; |
823 | unsigned long flags; | 823 | unsigned long flags; |
824 | 824 | ||
825 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 825 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
826 | 826 | ||
827 | spin_lock_irqsave(&chip->msg_lock, flags); | 827 | spin_lock_irqsave(&chip->msg_lock, flags); |
828 | lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); | 828 | lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); |
829 | 829 | ||
830 | chip->rmh.cmd[0] |= pipe_cmd; | 830 | chip->rmh.cmd[0] |= pipe_cmd; |
831 | 831 | ||
832 | err = lx_message_send_atomic(chip, &chip->rmh); | 832 | err = lx_message_send_atomic(chip, &chip->rmh); |
833 | 833 | ||
834 | *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE; | 834 | *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE; |
835 | 835 | ||
836 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 836 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
837 | return err; | 837 | return err; |
838 | } | 838 | } |
839 | 839 | ||
840 | int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, | 840 | int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, |
841 | u64 *r_bytepos) | 841 | u64 *r_bytepos) |
842 | { | 842 | { |
843 | int err; | 843 | int err; |
844 | unsigned long flags; | 844 | unsigned long flags; |
845 | 845 | ||
846 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 846 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
847 | 847 | ||
848 | spin_lock_irqsave(&chip->msg_lock, flags); | 848 | spin_lock_irqsave(&chip->msg_lock, flags); |
849 | lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); | 849 | lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); |
850 | 850 | ||
851 | chip->rmh.cmd[0] |= pipe_cmd; | 851 | chip->rmh.cmd[0] |= pipe_cmd; |
852 | 852 | ||
853 | err = lx_message_send_atomic(chip, &chip->rmh); | 853 | err = lx_message_send_atomic(chip, &chip->rmh); |
854 | 854 | ||
855 | *r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI) | 855 | *r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI) |
856 | << 32) /* hi part */ | 856 | << 32) /* hi part */ |
857 | + chip->rmh.stat[1]; /* lo part */ | 857 | + chip->rmh.stat[1]; /* lo part */ |
858 | 858 | ||
859 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 859 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
860 | return err; | 860 | return err; |
861 | } | 861 | } |
862 | 862 | ||
863 | /* low-level buffer handling */ | 863 | /* low-level buffer handling */ |
864 | int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, | 864 | int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, |
865 | u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, | 865 | u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, |
866 | u32 *r_buffer_index) | 866 | u32 *r_buffer_index) |
867 | { | 867 | { |
868 | int err; | 868 | int err; |
869 | unsigned long flags; | 869 | unsigned long flags; |
870 | 870 | ||
871 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 871 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
872 | 872 | ||
873 | spin_lock_irqsave(&chip->msg_lock, flags); | 873 | spin_lock_irqsave(&chip->msg_lock, flags); |
874 | lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER); | 874 | lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER); |
875 | 875 | ||
876 | chip->rmh.cmd[0] |= pipe_cmd; | 876 | chip->rmh.cmd[0] |= pipe_cmd; |
877 | chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */ | 877 | chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */ |
878 | 878 | ||
879 | /* todo: pause request, circular buffer */ | 879 | /* todo: pause request, circular buffer */ |
880 | 880 | ||
881 | chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE; | 881 | chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE; |
882 | chip->rmh.cmd[2] = buf_address_lo; | 882 | chip->rmh.cmd[2] = buf_address_lo; |
883 | 883 | ||
884 | if (buf_address_hi) { | 884 | if (buf_address_hi) { |
885 | chip->rmh.cmd_len = 4; | 885 | chip->rmh.cmd_len = 4; |
886 | chip->rmh.cmd[3] = buf_address_hi; | 886 | chip->rmh.cmd[3] = buf_address_hi; |
887 | chip->rmh.cmd[0] |= BF_64BITS_ADR; | 887 | chip->rmh.cmd[0] |= BF_64BITS_ADR; |
888 | } | 888 | } |
889 | 889 | ||
890 | err = lx_message_send_atomic(chip, &chip->rmh); | 890 | err = lx_message_send_atomic(chip, &chip->rmh); |
891 | 891 | ||
892 | if (err == 0) { | 892 | if (err == 0) { |
893 | *r_buffer_index = chip->rmh.stat[0]; | 893 | *r_buffer_index = chip->rmh.stat[0]; |
894 | goto done; | 894 | goto done; |
895 | } | 895 | } |
896 | 896 | ||
897 | if (err == EB_RBUFFERS_TABLE_OVERFLOW) | 897 | if (err == EB_RBUFFERS_TABLE_OVERFLOW) |
898 | snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n"); | 898 | snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n"); |
899 | 899 | ||
900 | if (err == EB_INVALID_STREAM) | 900 | if (err == EB_INVALID_STREAM) |
901 | snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n"); | 901 | snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n"); |
902 | 902 | ||
903 | if (err == EB_CMD_REFUSED) | 903 | if (err == EB_CMD_REFUSED) |
904 | snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n"); | 904 | snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n"); |
905 | 905 | ||
906 | done: | 906 | done: |
907 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 907 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
908 | return err; | 908 | return err; |
909 | } | 909 | } |
910 | 910 | ||
911 | int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, | 911 | int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, |
912 | u32 *r_buffer_size) | 912 | u32 *r_buffer_size) |
913 | { | 913 | { |
914 | int err; | 914 | int err; |
915 | unsigned long flags; | 915 | unsigned long flags; |
916 | 916 | ||
917 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 917 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
918 | 918 | ||
919 | spin_lock_irqsave(&chip->msg_lock, flags); | 919 | spin_lock_irqsave(&chip->msg_lock, flags); |
920 | lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); | 920 | lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); |
921 | 921 | ||
922 | chip->rmh.cmd[0] |= pipe_cmd; | 922 | chip->rmh.cmd[0] |= pipe_cmd; |
923 | chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the | 923 | chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the |
924 | * microblaze will seek for it */ | 924 | * microblaze will seek for it */ |
925 | 925 | ||
926 | err = lx_message_send_atomic(chip, &chip->rmh); | 926 | err = lx_message_send_atomic(chip, &chip->rmh); |
927 | 927 | ||
928 | if (err == 0) | 928 | if (err == 0) |
929 | *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE; | 929 | *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE; |
930 | 930 | ||
931 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 931 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
932 | return err; | 932 | return err; |
933 | } | 933 | } |
934 | 934 | ||
935 | int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, | 935 | int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, |
936 | u32 buffer_index) | 936 | u32 buffer_index) |
937 | { | 937 | { |
938 | int err; | 938 | int err; |
939 | unsigned long flags; | 939 | unsigned long flags; |
940 | 940 | ||
941 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | 941 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); |
942 | 942 | ||
943 | spin_lock_irqsave(&chip->msg_lock, flags); | 943 | spin_lock_irqsave(&chip->msg_lock, flags); |
944 | lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); | 944 | lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); |
945 | 945 | ||
946 | chip->rmh.cmd[0] |= pipe_cmd; | 946 | chip->rmh.cmd[0] |= pipe_cmd; |
947 | chip->rmh.cmd[0] |= buffer_index; | 947 | chip->rmh.cmd[0] |= buffer_index; |
948 | 948 | ||
949 | err = lx_message_send_atomic(chip, &chip->rmh); | 949 | err = lx_message_send_atomic(chip, &chip->rmh); |
950 | 950 | ||
951 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 951 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
952 | return err; | 952 | return err; |
953 | } | 953 | } |
954 | 954 | ||
955 | 955 | ||
956 | /* low-level gain/peak handling | 956 | /* low-level gain/peak handling |
957 | * | 957 | * |
958 | * \todo: can we unmute capture/playback channels independently? | 958 | * \todo: can we unmute capture/playback channels independently? |
959 | * | 959 | * |
960 | * */ | 960 | * */ |
961 | int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) | 961 | int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) |
962 | { | 962 | { |
963 | int err; | 963 | int err; |
964 | unsigned long flags; | 964 | unsigned long flags; |
965 | 965 | ||
966 | /* bit set to 1: channel muted */ | 966 | /* bit set to 1: channel muted */ |
967 | u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU; | 967 | u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU; |
968 | 968 | ||
969 | spin_lock_irqsave(&chip->msg_lock, flags); | 969 | spin_lock_irqsave(&chip->msg_lock, flags); |
970 | lx_message_init(&chip->rmh, CMD_0D_SET_MUTE); | 970 | lx_message_init(&chip->rmh, CMD_0D_SET_MUTE); |
971 | 971 | ||
972 | chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0); | 972 | chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0); |
973 | 973 | ||
974 | chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */ | 974 | chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */ |
975 | chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */ | 975 | chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */ |
976 | 976 | ||
977 | snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], | 977 | snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], |
978 | chip->rmh.cmd[2]); | 978 | chip->rmh.cmd[2]); |
979 | 979 | ||
980 | err = lx_message_send_atomic(chip, &chip->rmh); | 980 | err = lx_message_send_atomic(chip, &chip->rmh); |
981 | 981 | ||
982 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 982 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
983 | return err; | 983 | return err; |
984 | } | 984 | } |
985 | 985 | ||
986 | static u32 peak_map[] = { | 986 | static u32 peak_map[] = { |
987 | 0x00000109, /* -90.308dB */ | 987 | 0x00000109, /* -90.308dB */ |
988 | 0x0000083B, /* -72.247dB */ | 988 | 0x0000083B, /* -72.247dB */ |
989 | 0x000020C4, /* -60.205dB */ | 989 | 0x000020C4, /* -60.205dB */ |
990 | 0x00008273, /* -48.030dB */ | 990 | 0x00008273, /* -48.030dB */ |
991 | 0x00020756, /* -36.005dB */ | 991 | 0x00020756, /* -36.005dB */ |
992 | 0x00040C37, /* -30.001dB */ | 992 | 0x00040C37, /* -30.001dB */ |
993 | 0x00081385, /* -24.002dB */ | 993 | 0x00081385, /* -24.002dB */ |
994 | 0x00101D3F, /* -18.000dB */ | 994 | 0x00101D3F, /* -18.000dB */ |
995 | 0x0016C310, /* -15.000dB */ | 995 | 0x0016C310, /* -15.000dB */ |
996 | 0x002026F2, /* -12.001dB */ | 996 | 0x002026F2, /* -12.001dB */ |
997 | 0x002D6A86, /* -9.000dB */ | 997 | 0x002D6A86, /* -9.000dB */ |
998 | 0x004026E6, /* -6.004dB */ | 998 | 0x004026E6, /* -6.004dB */ |
999 | 0x005A9DF6, /* -3.000dB */ | 999 | 0x005A9DF6, /* -3.000dB */ |
1000 | 0x0065AC8B, /* -2.000dB */ | 1000 | 0x0065AC8B, /* -2.000dB */ |
1001 | 0x00721481, /* -1.000dB */ | 1001 | 0x00721481, /* -1.000dB */ |
1002 | 0x007FFFFF, /* FS */ | 1002 | 0x007FFFFF, /* FS */ |
1003 | }; | 1003 | }; |
1004 | 1004 | ||
1005 | int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, | 1005 | int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, |
1006 | u32 *r_levels) | 1006 | u32 *r_levels) |
1007 | { | 1007 | { |
1008 | int err = 0; | 1008 | int err = 0; |
1009 | unsigned long flags; | 1009 | unsigned long flags; |
1010 | int i; | 1010 | int i; |
1011 | spin_lock_irqsave(&chip->msg_lock, flags); | 1011 | spin_lock_irqsave(&chip->msg_lock, flags); |
1012 | 1012 | ||
1013 | for (i = 0; i < channels; i += 4) { | 1013 | for (i = 0; i < channels; i += 4) { |
1014 | u32 s0, s1, s2, s3; | 1014 | u32 s0, s1, s2, s3; |
1015 | 1015 | ||
1016 | lx_message_init(&chip->rmh, CMD_12_GET_PEAK); | 1016 | lx_message_init(&chip->rmh, CMD_12_GET_PEAK); |
1017 | chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i); | 1017 | chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i); |
1018 | 1018 | ||
1019 | err = lx_message_send_atomic(chip, &chip->rmh); | 1019 | err = lx_message_send_atomic(chip, &chip->rmh); |
1020 | 1020 | ||
1021 | if (err == 0) { | 1021 | if (err == 0) { |
1022 | s0 = peak_map[chip->rmh.stat[0] & 0x0F]; | 1022 | s0 = peak_map[chip->rmh.stat[0] & 0x0F]; |
1023 | s1 = peak_map[(chip->rmh.stat[0] >> 4) & 0xf]; | 1023 | s1 = peak_map[(chip->rmh.stat[0] >> 4) & 0xf]; |
1024 | s2 = peak_map[(chip->rmh.stat[0] >> 8) & 0xf]; | 1024 | s2 = peak_map[(chip->rmh.stat[0] >> 8) & 0xf]; |
1025 | s3 = peak_map[(chip->rmh.stat[0] >> 12) & 0xf]; | 1025 | s3 = peak_map[(chip->rmh.stat[0] >> 12) & 0xf]; |
1026 | } else | 1026 | } else |
1027 | s0 = s1 = s2 = s3 = 0; | 1027 | s0 = s1 = s2 = s3 = 0; |
1028 | 1028 | ||
1029 | r_levels[0] = s0; | 1029 | r_levels[0] = s0; |
1030 | r_levels[1] = s1; | 1030 | r_levels[1] = s1; |
1031 | r_levels[2] = s2; | 1031 | r_levels[2] = s2; |
1032 | r_levels[3] = s3; | 1032 | r_levels[3] = s3; |
1033 | 1033 | ||
1034 | r_levels += 4; | 1034 | r_levels += 4; |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | spin_unlock_irqrestore(&chip->msg_lock, flags); | 1037 | spin_unlock_irqrestore(&chip->msg_lock, flags); |
1038 | return err; | 1038 | return err; |
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | /* interrupt handling */ | 1041 | /* interrupt handling */ |
1042 | #define PCX_IRQ_NONE 0 | 1042 | #define PCX_IRQ_NONE 0 |
1043 | #define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */ | 1043 | #define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */ |
1044 | #define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */ | 1044 | #define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */ |
1045 | #define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */ | 1045 | #define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */ |
1046 | 1046 | ||
1047 | static u32 lx_interrupt_test_ack(struct lx6464es *chip) | 1047 | static u32 lx_interrupt_test_ack(struct lx6464es *chip) |
1048 | { | 1048 | { |
1049 | u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS); | 1049 | u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS); |
1050 | 1050 | ||
1051 | /* Test if PCI Doorbell interrupt is active */ | 1051 | /* Test if PCI Doorbell interrupt is active */ |
1052 | if (irqcs & IRQCS_ACTIVE_PCIDB) { | 1052 | if (irqcs & IRQCS_ACTIVE_PCIDB) { |
1053 | u32 temp; | 1053 | u32 temp; |
1054 | irqcs = PCX_IRQ_NONE; | 1054 | irqcs = PCX_IRQ_NONE; |
1055 | 1055 | ||
1056 | while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) { | 1056 | while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) { |
1057 | /* RAZ interrupt */ | 1057 | /* RAZ interrupt */ |
1058 | irqcs |= temp; | 1058 | irqcs |= temp; |
1059 | lx_plx_reg_write(chip, ePLX_L2PCIDB, temp); | 1059 | lx_plx_reg_write(chip, ePLX_L2PCIDB, temp); |
1060 | } | 1060 | } |
1061 | 1061 | ||
1062 | return irqcs; | 1062 | return irqcs; |
1063 | } | 1063 | } |
1064 | return PCX_IRQ_NONE; | 1064 | return PCX_IRQ_NONE; |
1065 | } | 1065 | } |
1066 | 1066 | ||
1067 | static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc, | 1067 | static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc, |
1068 | int *r_async_pending, int *r_async_escmd) | 1068 | int *r_async_pending, int *r_async_escmd) |
1069 | { | 1069 | { |
1070 | u32 irq_async; | 1070 | u32 irq_async; |
1071 | u32 irqsrc = lx_interrupt_test_ack(chip); | 1071 | u32 irqsrc = lx_interrupt_test_ack(chip); |
1072 | 1072 | ||
1073 | if (irqsrc == PCX_IRQ_NONE) | 1073 | if (irqsrc == PCX_IRQ_NONE) |
1074 | return 0; | 1074 | return 0; |
1075 | 1075 | ||
1076 | *r_irqsrc = irqsrc; | 1076 | *r_irqsrc = irqsrc; |
1077 | 1077 | ||
1078 | irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response | 1078 | irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response |
1079 | * (set by xilinx) + EOB */ | 1079 | * (set by xilinx) + EOB */ |
1080 | 1080 | ||
1081 | if (irq_async & MASK_SYS_STATUS_ESA) { | 1081 | if (irq_async & MASK_SYS_STATUS_ESA) { |
1082 | irq_async &= ~MASK_SYS_STATUS_ESA; | 1082 | irq_async &= ~MASK_SYS_STATUS_ESA; |
1083 | *r_async_escmd = 1; | 1083 | *r_async_escmd = 1; |
1084 | } | 1084 | } |
1085 | 1085 | ||
1086 | if (irq_async) { | 1086 | if (irq_async) { |
1087 | /* snd_printd("interrupt: async event pending\n"); */ | 1087 | /* snd_printd("interrupt: async event pending\n"); */ |
1088 | *r_async_pending = 1; | 1088 | *r_async_pending = 1; |
1089 | } | 1089 | } |
1090 | 1090 | ||
1091 | return 1; | 1091 | return 1; |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, | 1094 | static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, |
1095 | int *r_freq_changed, | 1095 | int *r_freq_changed, |
1096 | u64 *r_notified_in_pipe_mask, | 1096 | u64 *r_notified_in_pipe_mask, |
1097 | u64 *r_notified_out_pipe_mask) | 1097 | u64 *r_notified_out_pipe_mask) |
1098 | { | 1098 | { |
1099 | int err; | 1099 | int err; |
1100 | u32 stat[9]; /* answer from CMD_04_GET_EVENT */ | 1100 | u32 stat[9]; /* answer from CMD_04_GET_EVENT */ |
1101 | 1101 | ||
1102 | /* On peut optimiser pour ne pas lire les evenements vides | 1102 | /* On peut optimiser pour ne pas lire les evenements vides |
1103 | * les mots de réponse sont dans l'ordre suivant : | 1103 | * les mots de réponse sont dans l'ordre suivant : |
1104 | * Stat[0] mot de status général | 1104 | * Stat[0] mot de status général |
1105 | * Stat[1] fin de buffer OUT pF | 1105 | * Stat[1] fin de buffer OUT pF |
1106 | * Stat[2] fin de buffer OUT pf | 1106 | * Stat[2] fin de buffer OUT pf |
1107 | * Stat[3] fin de buffer IN pF | 1107 | * Stat[3] fin de buffer IN pF |
1108 | * Stat[4] fin de buffer IN pf | 1108 | * Stat[4] fin de buffer IN pf |
1109 | * Stat[5] underrun poid fort | 1109 | * Stat[5] underrun poid fort |
1110 | * Stat[6] underrun poid faible | 1110 | * Stat[6] underrun poid faible |
1111 | * Stat[7] overrun poid fort | 1111 | * Stat[7] overrun poid fort |
1112 | * Stat[8] overrun poid faible | 1112 | * Stat[8] overrun poid faible |
1113 | * */ | 1113 | * */ |
1114 | 1114 | ||
1115 | u64 orun_mask; | 1115 | u64 orun_mask; |
1116 | u64 urun_mask; | 1116 | u64 urun_mask; |
1117 | #if 0 | 1117 | #if 0 |
1118 | int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0; | 1118 | int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0; |
1119 | int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0; | 1119 | int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0; |
1120 | #endif | 1120 | #endif |
1121 | int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0; | 1121 | int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0; |
1122 | int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0; | 1122 | int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0; |
1123 | 1123 | ||
1124 | *r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0; | 1124 | *r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0; |
1125 | 1125 | ||
1126 | err = lx_dsp_read_async_events(chip, stat); | 1126 | err = lx_dsp_read_async_events(chip, stat); |
1127 | if (err < 0) | 1127 | if (err < 0) |
1128 | return err; | 1128 | return err; |
1129 | 1129 | ||
1130 | if (eb_pending_in) { | 1130 | if (eb_pending_in) { |
1131 | *r_notified_in_pipe_mask = ((u64)stat[3] << 32) | 1131 | *r_notified_in_pipe_mask = ((u64)stat[3] << 32) |
1132 | + stat[4]; | 1132 | + stat[4]; |
1133 | snd_printdd(LXP "interrupt: EOBI pending %llx\n", | 1133 | snd_printdd(LXP "interrupt: EOBI pending %llx\n", |
1134 | *r_notified_in_pipe_mask); | 1134 | *r_notified_in_pipe_mask); |
1135 | } | 1135 | } |
1136 | if (eb_pending_out) { | 1136 | if (eb_pending_out) { |
1137 | *r_notified_out_pipe_mask = ((u64)stat[1] << 32) | 1137 | *r_notified_out_pipe_mask = ((u64)stat[1] << 32) |
1138 | + stat[2]; | 1138 | + stat[2]; |
1139 | snd_printdd(LXP "interrupt: EOBO pending %llx\n", | 1139 | snd_printdd(LXP "interrupt: EOBO pending %llx\n", |
1140 | *r_notified_out_pipe_mask); | 1140 | *r_notified_out_pipe_mask); |
1141 | } | 1141 | } |
1142 | 1142 | ||
1143 | orun_mask = ((u64)stat[7] << 32) + stat[8]; | 1143 | orun_mask = ((u64)stat[7] << 32) + stat[8]; |
1144 | urun_mask = ((u64)stat[5] << 32) + stat[6]; | 1144 | urun_mask = ((u64)stat[5] << 32) + stat[6]; |
1145 | 1145 | ||
1146 | /* todo: handle xrun notification */ | 1146 | /* todo: handle xrun notification */ |
1147 | 1147 | ||
1148 | return err; | 1148 | return err; |
1149 | } | 1149 | } |
1150 | 1150 | ||
1151 | static int lx_interrupt_request_new_buffer(struct lx6464es *chip, | 1151 | static int lx_interrupt_request_new_buffer(struct lx6464es *chip, |
1152 | struct lx_stream *lx_stream) | 1152 | struct lx_stream *lx_stream) |
1153 | { | 1153 | { |
1154 | struct snd_pcm_substream *substream = lx_stream->stream; | 1154 | struct snd_pcm_substream *substream = lx_stream->stream; |
1155 | int is_capture = lx_stream->is_capture; | 1155 | const unsigned int is_capture = lx_stream->is_capture; |
1156 | int err; | 1156 | int err; |
1157 | unsigned long flags; | 1157 | unsigned long flags; |
1158 | 1158 | ||
1159 | const u32 channels = substream->runtime->channels; | 1159 | const u32 channels = substream->runtime->channels; |
1160 | const u32 bytes_per_frame = channels * 3; | 1160 | const u32 bytes_per_frame = channels * 3; |
1161 | const u32 period_size = substream->runtime->period_size; | 1161 | const u32 period_size = substream->runtime->period_size; |
1162 | const u32 period_bytes = period_size * bytes_per_frame; | 1162 | const u32 period_bytes = period_size * bytes_per_frame; |
1163 | const u32 pos = lx_stream->frame_pos; | 1163 | const u32 pos = lx_stream->frame_pos; |
1164 | const u32 next_pos = ((pos+1) == substream->runtime->periods) ? | 1164 | const u32 next_pos = ((pos+1) == substream->runtime->periods) ? |
1165 | 0 : pos + 1; | 1165 | 0 : pos + 1; |
1166 | 1166 | ||
1167 | dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes; | 1167 | dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes; |
1168 | u32 buf_hi = 0; | 1168 | u32 buf_hi = 0; |
1169 | u32 buf_lo = 0; | 1169 | u32 buf_lo = 0; |
1170 | u32 buffer_index = 0; | 1170 | u32 buffer_index = 0; |
1171 | 1171 | ||
1172 | u32 needed, freed; | 1172 | u32 needed, freed; |
1173 | u32 size_array[MAX_STREAM_BUFFER]; | 1173 | u32 size_array[MAX_STREAM_BUFFER]; |
1174 | 1174 | ||
1175 | snd_printdd("->lx_interrupt_request_new_buffer\n"); | 1175 | snd_printdd("->lx_interrupt_request_new_buffer\n"); |
1176 | 1176 | ||
1177 | spin_lock_irqsave(&chip->lock, flags); | 1177 | spin_lock_irqsave(&chip->lock, flags); |
1178 | 1178 | ||
1179 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); | 1179 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); |
1180 | snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed); | 1180 | snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed); |
1181 | 1181 | ||
1182 | unpack_pointer(buf, &buf_lo, &buf_hi); | 1182 | unpack_pointer(buf, &buf_lo, &buf_hi); |
1183 | err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi, | 1183 | err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi, |
1184 | &buffer_index); | 1184 | &buffer_index); |
1185 | snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n", | 1185 | snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n", |
1186 | buffer_index, (void *)buf, period_bytes); | 1186 | buffer_index, (void *)buf, period_bytes); |
1187 | 1187 | ||
1188 | lx_stream->frame_pos = next_pos; | 1188 | lx_stream->frame_pos = next_pos; |
1189 | spin_unlock_irqrestore(&chip->lock, flags); | 1189 | spin_unlock_irqrestore(&chip->lock, flags); |
1190 | 1190 | ||
1191 | return err; | 1191 | return err; |
1192 | } | 1192 | } |
1193 | 1193 | ||
1194 | void lx_tasklet_playback(unsigned long data) | 1194 | void lx_tasklet_playback(unsigned long data) |
1195 | { | 1195 | { |
1196 | struct lx6464es *chip = (struct lx6464es *)data; | 1196 | struct lx6464es *chip = (struct lx6464es *)data; |
1197 | struct lx_stream *lx_stream = &chip->playback_stream; | 1197 | struct lx_stream *lx_stream = &chip->playback_stream; |
1198 | int err; | 1198 | int err; |
1199 | 1199 | ||
1200 | snd_printdd("->lx_tasklet_playback\n"); | 1200 | snd_printdd("->lx_tasklet_playback\n"); |
1201 | 1201 | ||
1202 | err = lx_interrupt_request_new_buffer(chip, lx_stream); | 1202 | err = lx_interrupt_request_new_buffer(chip, lx_stream); |
1203 | if (err < 0) | 1203 | if (err < 0) |
1204 | snd_printk(KERN_ERR LXP | 1204 | snd_printk(KERN_ERR LXP |
1205 | "cannot request new buffer for playback\n"); | 1205 | "cannot request new buffer for playback\n"); |
1206 | 1206 | ||
1207 | snd_pcm_period_elapsed(lx_stream->stream); | 1207 | snd_pcm_period_elapsed(lx_stream->stream); |
1208 | } | 1208 | } |
1209 | 1209 | ||
1210 | void lx_tasklet_capture(unsigned long data) | 1210 | void lx_tasklet_capture(unsigned long data) |
1211 | { | 1211 | { |
1212 | struct lx6464es *chip = (struct lx6464es *)data; | 1212 | struct lx6464es *chip = (struct lx6464es *)data; |
1213 | struct lx_stream *lx_stream = &chip->capture_stream; | 1213 | struct lx_stream *lx_stream = &chip->capture_stream; |
1214 | int err; | 1214 | int err; |
1215 | 1215 | ||
1216 | snd_printdd("->lx_tasklet_capture\n"); | 1216 | snd_printdd("->lx_tasklet_capture\n"); |
1217 | err = lx_interrupt_request_new_buffer(chip, lx_stream); | 1217 | err = lx_interrupt_request_new_buffer(chip, lx_stream); |
1218 | if (err < 0) | 1218 | if (err < 0) |
1219 | snd_printk(KERN_ERR LXP | 1219 | snd_printk(KERN_ERR LXP |
1220 | "cannot request new buffer for capture\n"); | 1220 | "cannot request new buffer for capture\n"); |
1221 | 1221 | ||
1222 | snd_pcm_period_elapsed(lx_stream->stream); | 1222 | snd_pcm_period_elapsed(lx_stream->stream); |
1223 | } | 1223 | } |
1224 | 1224 | ||
1225 | 1225 | ||
1226 | 1226 | ||
1227 | static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip, | 1227 | static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip, |
1228 | u64 notified_in_pipe_mask, | 1228 | u64 notified_in_pipe_mask, |
1229 | u64 notified_out_pipe_mask) | 1229 | u64 notified_out_pipe_mask) |
1230 | { | 1230 | { |
1231 | int err = 0; | 1231 | int err = 0; |
1232 | 1232 | ||
1233 | if (notified_in_pipe_mask) { | 1233 | if (notified_in_pipe_mask) { |
1234 | snd_printdd(LXP "requesting audio transfer for capture\n"); | 1234 | snd_printdd(LXP "requesting audio transfer for capture\n"); |
1235 | tasklet_hi_schedule(&chip->tasklet_capture); | 1235 | tasklet_hi_schedule(&chip->tasklet_capture); |
1236 | } | 1236 | } |
1237 | 1237 | ||
1238 | if (notified_out_pipe_mask) { | 1238 | if (notified_out_pipe_mask) { |
1239 | snd_printdd(LXP "requesting audio transfer for playback\n"); | 1239 | snd_printdd(LXP "requesting audio transfer for playback\n"); |
1240 | tasklet_hi_schedule(&chip->tasklet_playback); | 1240 | tasklet_hi_schedule(&chip->tasklet_playback); |
1241 | } | 1241 | } |
1242 | 1242 | ||
1243 | return err; | 1243 | return err; |
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | 1246 | ||
1247 | irqreturn_t lx_interrupt(int irq, void *dev_id) | 1247 | irqreturn_t lx_interrupt(int irq, void *dev_id) |
1248 | { | 1248 | { |
1249 | struct lx6464es *chip = dev_id; | 1249 | struct lx6464es *chip = dev_id; |
1250 | int async_pending, async_escmd; | 1250 | int async_pending, async_escmd; |
1251 | u32 irqsrc; | 1251 | u32 irqsrc; |
1252 | 1252 | ||
1253 | spin_lock(&chip->lock); | 1253 | spin_lock(&chip->lock); |
1254 | 1254 | ||
1255 | snd_printdd("**************************************************\n"); | 1255 | snd_printdd("**************************************************\n"); |
1256 | 1256 | ||
1257 | if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) { | 1257 | if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) { |
1258 | spin_unlock(&chip->lock); | 1258 | spin_unlock(&chip->lock); |
1259 | snd_printdd("IRQ_NONE\n"); | 1259 | snd_printdd("IRQ_NONE\n"); |
1260 | return IRQ_NONE; /* this device did not cause the interrupt */ | 1260 | return IRQ_NONE; /* this device did not cause the interrupt */ |
1261 | } | 1261 | } |
1262 | 1262 | ||
1263 | if (irqsrc & MASK_SYS_STATUS_CMD_DONE) | 1263 | if (irqsrc & MASK_SYS_STATUS_CMD_DONE) |
1264 | goto exit; | 1264 | goto exit; |
1265 | 1265 | ||
1266 | #if 0 | 1266 | #if 0 |
1267 | if (irqsrc & MASK_SYS_STATUS_EOBI) | 1267 | if (irqsrc & MASK_SYS_STATUS_EOBI) |
1268 | snd_printdd(LXP "interrupt: EOBI\n"); | 1268 | snd_printdd(LXP "interrupt: EOBI\n"); |
1269 | 1269 | ||
1270 | if (irqsrc & MASK_SYS_STATUS_EOBO) | 1270 | if (irqsrc & MASK_SYS_STATUS_EOBO) |
1271 | snd_printdd(LXP "interrupt: EOBO\n"); | 1271 | snd_printdd(LXP "interrupt: EOBO\n"); |
1272 | 1272 | ||
1273 | if (irqsrc & MASK_SYS_STATUS_URUN) | 1273 | if (irqsrc & MASK_SYS_STATUS_URUN) |
1274 | snd_printdd(LXP "interrupt: URUN\n"); | 1274 | snd_printdd(LXP "interrupt: URUN\n"); |
1275 | 1275 | ||
1276 | if (irqsrc & MASK_SYS_STATUS_ORUN) | 1276 | if (irqsrc & MASK_SYS_STATUS_ORUN) |
1277 | snd_printdd(LXP "interrupt: ORUN\n"); | 1277 | snd_printdd(LXP "interrupt: ORUN\n"); |
1278 | #endif | 1278 | #endif |
1279 | 1279 | ||
1280 | if (async_pending) { | 1280 | if (async_pending) { |
1281 | u64 notified_in_pipe_mask = 0; | 1281 | u64 notified_in_pipe_mask = 0; |
1282 | u64 notified_out_pipe_mask = 0; | 1282 | u64 notified_out_pipe_mask = 0; |
1283 | int freq_changed; | 1283 | int freq_changed; |
1284 | int err; | 1284 | int err; |
1285 | 1285 | ||
1286 | /* handle async events */ | 1286 | /* handle async events */ |
1287 | err = lx_interrupt_handle_async_events(chip, irqsrc, | 1287 | err = lx_interrupt_handle_async_events(chip, irqsrc, |
1288 | &freq_changed, | 1288 | &freq_changed, |
1289 | ¬ified_in_pipe_mask, | 1289 | ¬ified_in_pipe_mask, |
1290 | ¬ified_out_pipe_mask); | 1290 | ¬ified_out_pipe_mask); |
1291 | if (err) | 1291 | if (err) |
1292 | snd_printk(KERN_ERR LXP | 1292 | snd_printk(KERN_ERR LXP |
1293 | "error handling async events\n"); | 1293 | "error handling async events\n"); |
1294 | 1294 | ||
1295 | err = lx_interrupt_handle_audio_transfer(chip, | 1295 | err = lx_interrupt_handle_audio_transfer(chip, |
1296 | notified_in_pipe_mask, | 1296 | notified_in_pipe_mask, |
1297 | notified_out_pipe_mask | 1297 | notified_out_pipe_mask |
1298 | ); | 1298 | ); |
1299 | if (err) | 1299 | if (err) |
1300 | snd_printk(KERN_ERR LXP | 1300 | snd_printk(KERN_ERR LXP |
1301 | "error during audio transfer\n"); | 1301 | "error during audio transfer\n"); |
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | if (async_escmd) { | 1304 | if (async_escmd) { |
1305 | #if 0 | 1305 | #if 0 |
1306 | /* backdoor for ethersound commands | 1306 | /* backdoor for ethersound commands |
1307 | * | 1307 | * |
1308 | * for now, we do not need this | 1308 | * for now, we do not need this |
1309 | * | 1309 | * |
1310 | * */ | 1310 | * */ |
1311 | 1311 | ||
1312 | snd_printdd("lx6464es: interrupt requests escmd handling\n"); | 1312 | snd_printdd("lx6464es: interrupt requests escmd handling\n"); |
1313 | #endif | 1313 | #endif |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | exit: | 1316 | exit: |
1317 | spin_unlock(&chip->lock); | 1317 | spin_unlock(&chip->lock); |
1318 | return IRQ_HANDLED; /* this device caused the interrupt */ | 1318 | return IRQ_HANDLED; /* this device caused the interrupt */ |
1319 | } | 1319 | } |
1320 | 1320 | ||
1321 | 1321 | ||
1322 | static void lx_irq_set(struct lx6464es *chip, int enable) | 1322 | static void lx_irq_set(struct lx6464es *chip, int enable) |
1323 | { | 1323 | { |
1324 | u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS); | 1324 | u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS); |
1325 | 1325 | ||
1326 | /* enable/disable interrupts | 1326 | /* enable/disable interrupts |
1327 | * | 1327 | * |
1328 | * Set the Doorbell and PCI interrupt enable bits | 1328 | * Set the Doorbell and PCI interrupt enable bits |
1329 | * | 1329 | * |
1330 | * */ | 1330 | * */ |
1331 | if (enable) | 1331 | if (enable) |
1332 | reg |= (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); | 1332 | reg |= (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); |
1333 | else | 1333 | else |
1334 | reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); | 1334 | reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); |
1335 | lx_plx_reg_write(chip, ePLX_IRQCS, reg); | 1335 | lx_plx_reg_write(chip, ePLX_IRQCS, reg); |
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | void lx_irq_enable(struct lx6464es *chip) | 1338 | void lx_irq_enable(struct lx6464es *chip) |
1339 | { | 1339 | { |
1340 | snd_printdd("->lx_irq_enable\n"); | 1340 | snd_printdd("->lx_irq_enable\n"); |
1341 | lx_irq_set(chip, 1); | 1341 | lx_irq_set(chip, 1); |
1342 | } | 1342 | } |
1343 | 1343 | ||
1344 | void lx_irq_disable(struct lx6464es *chip) | 1344 | void lx_irq_disable(struct lx6464es *chip) |
1345 | { | 1345 | { |
1346 | snd_printdd("->lx_irq_disable\n"); | 1346 | snd_printdd("->lx_irq_disable\n"); |
1347 | lx_irq_set(chip, 0); | 1347 | lx_irq_set(chip, 0); |
1348 | } | 1348 | } |
1349 | 1349 |