Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[ALSA] Xilinx ML403 AC97 Controller Reference device driver

Add ALSA support for the opb_ac97_controller_ref_v1_00_a ip core found
in Xilinx' ML403 reference design.
Known issue: Currently this driver hits a WARN_ON_ONCE(1) statement in
kernel/irq/resend.c (line 70). According to Linus
(http://lkml.org/lkml/2007/8/5/5) this may be ignored, right? I haven't
had a look into this 'problem' yet.

Signed-off-by: Joachim Foerster <JOFT@gmx.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>

authored by

Joachim Foerster and committed by
Jaroslav Kysela
a9f00d8d f1f208d0

+2098
+12
sound/drivers/Kconfig
··· 120 120 To compile this driver as a module, choose M here: the module 121 121 will be called snd-portman2x4. 122 122 123 + config SND_ML403_AC97CR 124 + tristate "Xilinx ML403 AC97 Controller Reference" 125 + depends on SND && XILINX_VIRTEX 126 + select SND_AC97_CODEC 127 + help 128 + Say Y here to include support for the 129 + opb_ac97_controller_ref_v1_00_a ip core found in Xilinx' ML403 130 + reference design. 131 + 132 + To compile this driver as a module, choose M here: the module 133 + will be called snd-ml403_ac97cr. 134 + 123 135 endmenu
+2
sound/drivers/Makefile
··· 9 9 snd-portman2x4-objs := portman2x4.o 10 10 snd-serial-u16550-objs := serial-u16550.o 11 11 snd-virmidi-objs := virmidi.o 12 + snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o 12 13 13 14 # Toplevel Module Dependency 14 15 obj-$(CONFIG_SND_DUMMY) += snd-dummy.o ··· 18 17 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o 19 18 obj-$(CONFIG_SND_MTS64) += snd-mts64.o 20 19 obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o 20 + obj-$(CONFIG_SND_ML403_AC97CR) += snd-ml403-ac97cr.o 21 21 22 22 obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
+1353
sound/drivers/ml403-ac97cr.c
··· 1 + /* 2 + * ALSA driver for Xilinx ML403 AC97 Controller Reference 3 + * IP: opb_ac97_controller_ref_v1_00_a (EDK 8.1i) 4 + * IP: opb_ac97_controller_ref_v1_00_a (EDK 9.1i) 5 + * 6 + * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> 7 + * 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 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 + * 22 + */ 23 + 24 + /* Some notes / status of this driver: 25 + * 26 + * - Don't wonder about some strange implementations of things - especially the 27 + * (heavy) shadowing of codec registers, with which I tried to reduce read 28 + * accesses to a minimum, because after a variable amount of accesses, the AC97 29 + * controller doesn't raise the register access finished bit anymore ... 30 + * 31 + * - Capture support works - basically, but after ~30s (with rates > ~20kHz) 32 + * ALSA stops reading captured samples from the intermediate buffer and 33 + * therefore a overrun happens - ATM I don't know what's wrong. 34 + * 35 + * - Playback support seems to be pretty stable - no issues here. 36 + */ 37 + 38 + #include <sound/driver.h> 39 + #include <linux/init.h> 40 + #include <linux/moduleparam.h> 41 + 42 + #include <linux/platform_device.h> 43 + 44 + #include <linux/ioport.h> 45 + #include <linux/io.h> 46 + #include <linux/interrupt.h> 47 + 48 + /* HZ */ 49 + #include <linux/param.h> 50 + /* jiffies, time_*() */ 51 + #include <linux/jiffies.h> 52 + /* schedule_timeout*() */ 53 + #include <linux/sched.h> 54 + /* spin_lock*() */ 55 + #include <linux/spinlock.h> 56 + /* struct mutex, mutex_init(), mutex_*lock() */ 57 + #include <linux/mutex.h> 58 + 59 + /* snd_printk(), snd_printd() */ 60 + #include <sound/core.h> 61 + #include <sound/pcm.h> 62 + #include <sound/pcm_params.h> 63 + #include <sound/initval.h> 64 + #include <sound/ac97_codec.h> 65 + 66 + #include "pcm-indirect2.h" 67 + 68 + 69 + #define SND_ML403_AC97CR_DRIVER "ml403-ac97cr" 70 + 71 + MODULE_AUTHOR("Joachim Foerster <JOFT@gmx.de>"); 72 + MODULE_DESCRIPTION("Xilinx ML403 AC97 Controller Reference"); 73 + MODULE_LICENSE("GPL"); 74 + MODULE_SUPPORTED_DEVICE("{{Xilinx,ML403 AC97 Controller Reference}}"); 75 + 76 + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 77 + static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 78 + static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; 79 + 80 + module_param_array(index, int, NULL, 0444); 81 + MODULE_PARM_DESC(index, "Index value for ML403 AC97 Controller Reference."); 82 + module_param_array(id, charp, NULL, 0444); 83 + MODULE_PARM_DESC(id, "ID string for ML403 AC97 Controller Reference."); 84 + module_param_array(enable, bool, NULL, 0444); 85 + MODULE_PARM_DESC(enable, "Enable this ML403 AC97 Controller Reference."); 86 + 87 + /* Special feature options */ 88 + /*#define CODEC_WRITE_CHECK_RAF*/ /* don't return after a write to a codec 89 + * register, while RAF bit is not set 90 + */ 91 + /* Debug options for code which may be removed completely in a final version */ 92 + #ifdef CONFIG_SND_DEBUG 93 + /*#define CODEC_STAT*/ /* turn on some minimal "statistics" 94 + * about codec register usage 95 + */ 96 + #define SND_PCM_INDIRECT2_STAT /* turn on some "statistics" about the 97 + * process of copying bytes from the 98 + * intermediate buffer to the hardware 99 + * fifo and the other way round 100 + */ 101 + #endif 102 + 103 + /* Definition of a "level/facility dependent" printk(); may be removed 104 + * completely in a final version 105 + */ 106 + #undef PDEBUG 107 + #ifdef CONFIG_SND_DEBUG 108 + /* "facilities" for PDEBUG */ 109 + #define UNKNOWN (1<<0) 110 + #define CODEC_SUCCESS (1<<1) 111 + #define CODEC_FAKE (1<<2) 112 + #define INIT_INFO (1<<3) 113 + #define INIT_FAILURE (1<<4) 114 + #define WORK_INFO (1<<5) 115 + #define WORK_FAILURE (1<<6) 116 + 117 + #define PDEBUG_FACILITIES (UNKNOWN | INIT_FAILURE | WORK_FAILURE) 118 + 119 + #define PDEBUG(fac, fmt, args...) do { \ 120 + if (fac & PDEBUG_FACILITIES) \ 121 + snd_printd(KERN_DEBUG SND_ML403_AC97CR_DRIVER ": " \ 122 + fmt, ##args); \ 123 + } while (0) 124 + #else 125 + #define PDEBUG(fac, fmt, args...) /* nothing */ 126 + #endif 127 + 128 + 129 + 130 + /* Defines for "waits"/timeouts (portions of HZ=250 on arch/ppc by default) */ 131 + #define CODEC_TIMEOUT_ON_INIT 5 /* timeout for checking for codec 132 + * readiness (after insmod) 133 + */ 134 + #ifndef CODEC_WRITE_CHECK_RAF 135 + #define CODEC_WAIT_AFTER_WRITE 100 /* general, static wait after a write 136 + * access to a codec register, may be 137 + * 0 to completely remove wait 138 + */ 139 + #else 140 + #define CODEC_TIMEOUT_AFTER_WRITE 5 /* timeout after a write access to a 141 + * codec register, if RAF bit is used 142 + */ 143 + #endif 144 + #define CODEC_TIMEOUT_AFTER_READ 5 /* timeout after a read access to a 145 + * codec register (checking RAF bit) 146 + */ 147 + 148 + /* Infrastructure for codec register shadowing */ 149 + #define LM4550_REG_OK (1<<0) /* register exists */ 150 + #define LM4550_REG_DONEREAD (1<<1) /* read register once, value should be 151 + * the same currently in the register 152 + */ 153 + #define LM4550_REG_NOSAVE (1<<2) /* values written to this register will 154 + * not be saved in the register 155 + */ 156 + #define LM4550_REG_NOSHADOW (1<<3) /* don't do register shadowing, use plain 157 + * hardware access 158 + */ 159 + #define LM4550_REG_READONLY (1<<4) /* register is read only */ 160 + #define LM4550_REG_FAKEPROBE (1<<5) /* fake write _and_ read actions during 161 + * probe() correctly 162 + */ 163 + #define LM4550_REG_FAKEREAD (1<<6) /* fake read access, always return 164 + * default value 165 + */ 166 + #define LM4550_REG_ALLFAKE (LM4550_REG_FAKEREAD | LM4550_REG_FAKEPROBE) 167 + 168 + struct lm4550_reg { 169 + u16 value; 170 + u16 flag; 171 + u16 wmask; 172 + u16 def; 173 + }; 174 + 175 + struct lm4550_reg lm4550_regfile[64] = { 176 + [AC97_RESET / 2] = {.flag = LM4550_REG_OK \ 177 + | LM4550_REG_NOSAVE \ 178 + | LM4550_REG_FAKEREAD, 179 + .def = 0x0D50}, 180 + [AC97_MASTER / 2] = {.flag = LM4550_REG_OK 181 + | LM4550_REG_FAKEPROBE, 182 + .wmask = 0x9F1F, 183 + .def = 0x8000}, 184 + [AC97_HEADPHONE / 2] = {.flag = LM4550_REG_OK \ 185 + | LM4550_REG_FAKEPROBE, 186 + .wmask = 0x9F1F, 187 + .def = 0x8000}, 188 + [AC97_MASTER_MONO / 2] = {.flag = LM4550_REG_OK \ 189 + | LM4550_REG_FAKEPROBE, 190 + .wmask = 0x801F, 191 + .def = 0x8000}, 192 + [AC97_PC_BEEP / 2] = {.flag = LM4550_REG_OK \ 193 + | LM4550_REG_FAKEPROBE, 194 + .wmask = 0x801E, 195 + .def = 0x0}, 196 + [AC97_PHONE / 2] = {.flag = LM4550_REG_OK \ 197 + | LM4550_REG_FAKEPROBE, 198 + .wmask = 0x801F, 199 + .def = 0x8008}, 200 + [AC97_MIC / 2] = {.flag = LM4550_REG_OK \ 201 + | LM4550_REG_FAKEPROBE, 202 + .wmask = 0x805F, 203 + .def = 0x8008}, 204 + [AC97_LINE / 2] = {.flag = LM4550_REG_OK \ 205 + | LM4550_REG_FAKEPROBE, 206 + .wmask = 0x9F1F, 207 + .def = 0x8808}, 208 + [AC97_CD / 2] = {.flag = LM4550_REG_OK \ 209 + | LM4550_REG_FAKEPROBE, 210 + .wmask = 0x9F1F, 211 + .def = 0x8808}, 212 + [AC97_VIDEO / 2] = {.flag = LM4550_REG_OK \ 213 + | LM4550_REG_FAKEPROBE, 214 + .wmask = 0x9F1F, 215 + .def = 0x8808}, 216 + [AC97_AUX / 2] = {.flag = LM4550_REG_OK \ 217 + | LM4550_REG_FAKEPROBE, 218 + .wmask = 0x9F1F, 219 + .def = 0x8808}, 220 + [AC97_PCM / 2] = {.flag = LM4550_REG_OK \ 221 + | LM4550_REG_FAKEPROBE, 222 + .wmask = 0x9F1F, 223 + .def = 0x8008}, 224 + [AC97_REC_SEL / 2] = {.flag = LM4550_REG_OK \ 225 + | LM4550_REG_FAKEPROBE, 226 + .wmask = 0x707, 227 + .def = 0x0}, 228 + [AC97_REC_GAIN / 2] = {.flag = LM4550_REG_OK \ 229 + | LM4550_REG_FAKEPROBE, 230 + .wmask = 0x8F0F, 231 + .def = 0x8000}, 232 + [AC97_GENERAL_PURPOSE / 2] = {.flag = LM4550_REG_OK \ 233 + | LM4550_REG_FAKEPROBE, 234 + .def = 0x0, 235 + .wmask = 0xA380}, 236 + [AC97_3D_CONTROL / 2] = {.flag = LM4550_REG_OK \ 237 + | LM4550_REG_FAKEREAD \ 238 + | LM4550_REG_READONLY, 239 + .def = 0x0101}, 240 + [AC97_POWERDOWN / 2] = {.flag = LM4550_REG_OK \ 241 + | LM4550_REG_NOSHADOW \ 242 + | LM4550_REG_NOSAVE, 243 + .wmask = 0xFF00}, 244 + /* may not write ones to 245 + * REF/ANL/DAC/ADC bits 246 + * FIXME: Is this ok? 247 + */ 248 + [AC97_EXTENDED_ID / 2] = {.flag = LM4550_REG_OK \ 249 + | LM4550_REG_FAKEREAD \ 250 + | LM4550_REG_READONLY, 251 + .def = 0x0201}, /* primary codec */ 252 + [AC97_EXTENDED_STATUS / 2] = {.flag = LM4550_REG_OK \ 253 + | LM4550_REG_NOSHADOW \ 254 + | LM4550_REG_NOSAVE, 255 + .wmask = 0x1}, 256 + [AC97_PCM_FRONT_DAC_RATE / 2] = {.flag = LM4550_REG_OK \ 257 + | LM4550_REG_FAKEPROBE, 258 + .def = 0xBB80, 259 + .wmask = 0xFFFF}, 260 + [AC97_PCM_LR_ADC_RATE / 2] = {.flag = LM4550_REG_OK \ 261 + | LM4550_REG_FAKEPROBE, 262 + .def = 0xBB80, 263 + .wmask = 0xFFFF}, 264 + [AC97_VENDOR_ID1 / 2] = {.flag = LM4550_REG_OK \ 265 + | LM4550_REG_READONLY \ 266 + | LM4550_REG_FAKEREAD, 267 + .def = 0x4E53}, 268 + [AC97_VENDOR_ID2 / 2] = {.flag = LM4550_REG_OK \ 269 + | LM4550_REG_READONLY \ 270 + | LM4550_REG_FAKEREAD, 271 + .def = 0x4350} 272 + }; 273 + 274 + #define LM4550_RF_OK(reg) (lm4550_regfile[reg / 2].flag & LM4550_REG_OK) 275 + 276 + static void lm4550_regfile_init(void) 277 + { 278 + int i; 279 + for (i = 0; i < 64; i++) 280 + if (lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) 281 + lm4550_regfile[i].value = lm4550_regfile[i].def; 282 + } 283 + 284 + static void lm4550_regfile_write_values_after_init(struct snd_ac97 *ac97) 285 + { 286 + int i; 287 + for (i = 0; i < 64; i++) 288 + if ((lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) && 289 + (lm4550_regfile[i].value != lm4550_regfile[i].def)) { 290 + PDEBUG(CODEC_FAKE, "lm4550_regfile_write_values_after_" 291 + "init(): reg=0x%x value=0x%x / %d is different " 292 + "from def=0x%x / %d\n", 293 + i, lm4550_regfile[i].value, 294 + lm4550_regfile[i].value, lm4550_regfile[i].def, 295 + lm4550_regfile[i].def); 296 + snd_ac97_write(ac97, i * 2, lm4550_regfile[i].value); 297 + lm4550_regfile[i].flag |= LM4550_REG_DONEREAD; 298 + } 299 + } 300 + 301 + 302 + /* direct registers */ 303 + #define CR_REG(ml403_ac97cr, x) ((ml403_ac97cr)->port + CR_REG_##x) 304 + 305 + #define CR_REG_PLAYFIFO 0x00 306 + #define CR_PLAYDATA(a) ((a) & 0xFFFF) 307 + 308 + #define CR_REG_RECFIFO 0x04 309 + #define CR_RECDATA(a) ((a) & 0xFFFF) 310 + 311 + #define CR_REG_STATUS 0x08 312 + #define CR_RECOVER (1<<7) 313 + #define CR_PLAYUNDER (1<<6) 314 + #define CR_CODECREADY (1<<5) 315 + #define CR_RAF (1<<4) 316 + #define CR_RECEMPTY (1<<3) 317 + #define CR_RECFULL (1<<2) 318 + #define CR_PLAYHALF (1<<1) 319 + #define CR_PLAYFULL (1<<0) 320 + 321 + #define CR_REG_RESETFIFO 0x0C 322 + #define CR_RECRESET (1<<1) 323 + #define CR_PLAYRESET (1<<0) 324 + 325 + #define CR_REG_CODEC_ADDR 0x10 326 + /* UG082 says: 327 + * #define CR_CODEC_ADDR(a) ((a) << 1) 328 + * #define CR_CODEC_READ (1<<0) 329 + * #define CR_CODEC_WRITE (0<<0) 330 + */ 331 + /* RefDesign example says: */ 332 + #define CR_CODEC_ADDR(a) ((a) << 0) 333 + #define CR_CODEC_READ (1<<7) 334 + #define CR_CODEC_WRITE (0<<7) 335 + 336 + #define CR_REG_CODEC_DATAREAD 0x14 337 + #define CR_CODEC_DATAREAD(v) ((v) & 0xFFFF) 338 + 339 + #define CR_REG_CODEC_DATAWRITE 0x18 340 + #define CR_CODEC_DATAWRITE(v) ((v) & 0xFFFF) 341 + 342 + #define CR_FIFO_SIZE 32 343 + 344 + struct snd_ml403_ac97cr { 345 + /* lock for access to (controller) registers */ 346 + spinlock_t reg_lock; 347 + /* mutex for the whole sequence of accesses to (controller) registers 348 + * which affect codec registers 349 + */ 350 + struct mutex cdc_mutex; 351 + 352 + int irq; /* for playback */ 353 + int enable_irq; /* for playback */ 354 + 355 + int capture_irq; 356 + int enable_capture_irq; 357 + 358 + struct resource *res_port; 359 + void *port; 360 + 361 + struct snd_ac97 *ac97; 362 + int ac97_fake; 363 + #ifdef CODEC_STAT 364 + int ac97_read; 365 + int ac97_write; 366 + #endif 367 + 368 + struct platform_device *pfdev; 369 + struct snd_card *card; 370 + struct snd_pcm *pcm; 371 + struct snd_pcm_substream *playback_substream; 372 + struct snd_pcm_substream *capture_substream; 373 + 374 + struct snd_pcm_indirect2 ind_rec; /* for playback */ 375 + struct snd_pcm_indirect2 capture_ind2_rec; 376 + }; 377 + 378 + static struct snd_pcm_hardware snd_ml403_ac97cr_playback = { 379 + .info = (SNDRV_PCM_INFO_MMAP | 380 + SNDRV_PCM_INFO_INTERLEAVED | 381 + SNDRV_PCM_INFO_MMAP_VALID), 382 + .formats = SNDRV_PCM_FMTBIT_S16_BE, 383 + .rates = (SNDRV_PCM_RATE_CONTINUOUS | 384 + SNDRV_PCM_RATE_8000_48000), 385 + .rate_min = 4000, 386 + .rate_max = 48000, 387 + .channels_min = 2, 388 + .channels_max = 2, 389 + .buffer_bytes_max = (128*1024), 390 + .period_bytes_min = CR_FIFO_SIZE/2, 391 + .period_bytes_max = (64*1024), 392 + .periods_min = 2, 393 + .periods_max = (128*1024)/(CR_FIFO_SIZE/2), 394 + .fifo_size = 0, 395 + }; 396 + 397 + static struct snd_pcm_hardware snd_ml403_ac97cr_capture = { 398 + .info = (SNDRV_PCM_INFO_MMAP | 399 + SNDRV_PCM_INFO_INTERLEAVED | 400 + SNDRV_PCM_INFO_MMAP_VALID), 401 + .formats = SNDRV_PCM_FMTBIT_S16_BE, 402 + .rates = (SNDRV_PCM_RATE_CONTINUOUS | 403 + SNDRV_PCM_RATE_8000_48000), 404 + .rate_min = 4000, 405 + .rate_max = 48000, 406 + .channels_min = 2, 407 + .channels_max = 2, 408 + .buffer_bytes_max = (128*1024), 409 + .period_bytes_min = CR_FIFO_SIZE/2, 410 + .period_bytes_max = (64*1024), 411 + .periods_min = 2, 412 + .periods_max = (128*1024)/(CR_FIFO_SIZE/2), 413 + .fifo_size = 0, 414 + }; 415 + 416 + static size_t 417 + snd_ml403_ac97cr_playback_ind2_zero(struct snd_pcm_substream *substream, 418 + struct snd_pcm_indirect2 *rec) 419 + { 420 + struct snd_ml403_ac97cr *ml403_ac97cr; 421 + int copied_words = 0; 422 + u32 full = 0; 423 + 424 + ml403_ac97cr = snd_pcm_substream_chip(substream); 425 + 426 + spin_lock(&ml403_ac97cr->reg_lock); 427 + while ((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & 428 + CR_PLAYFULL)) != CR_PLAYFULL) { 429 + out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), 0); 430 + copied_words++; 431 + } 432 + rec->hw_ready = 0; 433 + spin_unlock(&ml403_ac97cr->reg_lock); 434 + 435 + return (size_t) (copied_words * 2); 436 + } 437 + 438 + static size_t 439 + snd_ml403_ac97cr_playback_ind2_copy(struct snd_pcm_substream *substream, 440 + struct snd_pcm_indirect2 *rec, 441 + size_t bytes) 442 + { 443 + struct snd_ml403_ac97cr *ml403_ac97cr; 444 + u16 *src; 445 + int copied_words = 0; 446 + u32 full = 0; 447 + 448 + ml403_ac97cr = snd_pcm_substream_chip(substream); 449 + src = (u16 *)(substream->runtime->dma_area + rec->sw_data); 450 + 451 + spin_lock(&ml403_ac97cr->reg_lock); 452 + while (((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & 453 + CR_PLAYFULL)) != CR_PLAYFULL) && (bytes > 1)) { 454 + out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), 455 + CR_PLAYDATA(src[copied_words])); 456 + copied_words++; 457 + bytes = bytes - 2; 458 + } 459 + if (full != CR_PLAYFULL) 460 + rec->hw_ready = 1; 461 + else 462 + rec->hw_ready = 0; 463 + spin_unlock(&ml403_ac97cr->reg_lock); 464 + 465 + return (size_t) (copied_words * 2); 466 + } 467 + 468 + static size_t 469 + snd_ml403_ac97cr_capture_ind2_null(struct snd_pcm_substream *substream, 470 + struct snd_pcm_indirect2 *rec) 471 + { 472 + struct snd_ml403_ac97cr *ml403_ac97cr; 473 + int copied_words = 0; 474 + u32 empty = 0; 475 + 476 + ml403_ac97cr = snd_pcm_substream_chip(substream); 477 + 478 + spin_lock(&ml403_ac97cr->reg_lock); 479 + while ((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & 480 + CR_RECEMPTY)) != CR_RECEMPTY) { 481 + volatile u32 trash; 482 + 483 + trash = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, RECFIFO))); 484 + /* Hmmmm, really necessary? Don't want call to in_be32() 485 + * to be optimised away! 486 + */ 487 + trash++; 488 + copied_words++; 489 + } 490 + rec->hw_ready = 0; 491 + spin_unlock(&ml403_ac97cr->reg_lock); 492 + 493 + return (size_t) (copied_words * 2); 494 + } 495 + 496 + static size_t 497 + snd_ml403_ac97cr_capture_ind2_copy(struct snd_pcm_substream *substream, 498 + struct snd_pcm_indirect2 *rec, size_t bytes) 499 + { 500 + struct snd_ml403_ac97cr *ml403_ac97cr; 501 + u16 *dst; 502 + int copied_words = 0; 503 + u32 empty = 0; 504 + 505 + ml403_ac97cr = snd_pcm_substream_chip(substream); 506 + dst = (u16 *)(substream->runtime->dma_area + rec->sw_data); 507 + 508 + spin_lock(&ml403_ac97cr->reg_lock); 509 + while (((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & 510 + CR_RECEMPTY)) != CR_RECEMPTY) && (bytes > 1)) { 511 + dst[copied_words] = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, 512 + RECFIFO))); 513 + copied_words++; 514 + bytes = bytes - 2; 515 + } 516 + if (empty != CR_RECEMPTY) 517 + rec->hw_ready = 1; 518 + else 519 + rec->hw_ready = 0; 520 + spin_unlock(&ml403_ac97cr->reg_lock); 521 + 522 + return (size_t) (copied_words * 2); 523 + } 524 + 525 + static snd_pcm_uframes_t 526 + snd_ml403_ac97cr_pcm_pointer(struct snd_pcm_substream *substream) 527 + { 528 + struct snd_ml403_ac97cr *ml403_ac97cr; 529 + struct snd_pcm_indirect2 *ind2_rec = NULL; 530 + 531 + ml403_ac97cr = snd_pcm_substream_chip(substream); 532 + 533 + if (substream == ml403_ac97cr->playback_substream) 534 + ind2_rec = &ml403_ac97cr->ind_rec; 535 + if (substream == ml403_ac97cr->capture_substream) 536 + ind2_rec = &ml403_ac97cr->capture_ind2_rec; 537 + 538 + if (ind2_rec != NULL) 539 + return snd_pcm_indirect2_pointer(substream, ind2_rec); 540 + return (snd_pcm_uframes_t) 0; 541 + } 542 + 543 + static int 544 + snd_ml403_ac97cr_pcm_playback_trigger(struct snd_pcm_substream *substream, 545 + int cmd) 546 + { 547 + struct snd_ml403_ac97cr *ml403_ac97cr; 548 + int err = 0; 549 + 550 + ml403_ac97cr = snd_pcm_substream_chip(substream); 551 + 552 + switch (cmd) { 553 + case SNDRV_PCM_TRIGGER_START: 554 + PDEBUG(WORK_INFO, "trigger(playback): START\n"); 555 + ml403_ac97cr->ind_rec.hw_ready = 1; 556 + 557 + /* clear play FIFO */ 558 + out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_PLAYRESET); 559 + 560 + /* enable play irq */ 561 + ml403_ac97cr->enable_irq = 1; 562 + enable_irq(ml403_ac97cr->irq); 563 + break; 564 + case SNDRV_PCM_TRIGGER_STOP: 565 + PDEBUG(WORK_INFO, "trigger(playback): STOP\n"); 566 + ml403_ac97cr->ind_rec.hw_ready = 0; 567 + #ifdef SND_PCM_INDIRECT2_STAT 568 + snd_pcm_indirect2_stat(substream, &ml403_ac97cr->ind_rec); 569 + #endif 570 + /* disable play irq */ 571 + disable_irq_nosync(ml403_ac97cr->irq); 572 + ml403_ac97cr->enable_irq = 0; 573 + break; 574 + default: 575 + err = -EINVAL; 576 + break; 577 + } 578 + PDEBUG(WORK_INFO, "trigger(playback): (done)\n"); 579 + return err; 580 + } 581 + 582 + static int 583 + snd_ml403_ac97cr_pcm_capture_trigger(struct snd_pcm_substream *substream, 584 + int cmd) 585 + { 586 + struct snd_ml403_ac97cr *ml403_ac97cr; 587 + int err = 0; 588 + 589 + ml403_ac97cr = snd_pcm_substream_chip(substream); 590 + 591 + switch (cmd) { 592 + case SNDRV_PCM_TRIGGER_START: 593 + PDEBUG(WORK_INFO, "trigger(capture): START\n"); 594 + ml403_ac97cr->capture_ind2_rec.hw_ready = 0; 595 + 596 + /* clear record FIFO */ 597 + out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_RECRESET); 598 + 599 + /* enable record irq */ 600 + ml403_ac97cr->enable_capture_irq = 1; 601 + enable_irq(ml403_ac97cr->capture_irq); 602 + break; 603 + case SNDRV_PCM_TRIGGER_STOP: 604 + PDEBUG(WORK_INFO, "trigger(capture): STOP\n"); 605 + ml403_ac97cr->capture_ind2_rec.hw_ready = 0; 606 + #ifdef SND_PCM_INDIRECT2_STAT 607 + snd_pcm_indirect2_stat(substream, 608 + &ml403_ac97cr->capture_ind2_rec); 609 + #endif 610 + /* disable capture irq */ 611 + disable_irq_nosync(ml403_ac97cr->capture_irq); 612 + ml403_ac97cr->enable_capture_irq = 0; 613 + break; 614 + default: 615 + err = -EINVAL; 616 + break; 617 + } 618 + PDEBUG(WORK_INFO, "trigger(capture): (done)\n"); 619 + return err; 620 + } 621 + 622 + static int 623 + snd_ml403_ac97cr_pcm_playback_prepare(struct snd_pcm_substream *substream) 624 + { 625 + struct snd_ml403_ac97cr *ml403_ac97cr; 626 + struct snd_pcm_runtime *runtime; 627 + 628 + ml403_ac97cr = snd_pcm_substream_chip(substream); 629 + runtime = substream->runtime; 630 + 631 + PDEBUG(WORK_INFO, 632 + "prepare(): period_bytes=%d, minperiod_bytes=%d\n", 633 + snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); 634 + 635 + /* set sampling rate */ 636 + snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_FRONT_DAC_RATE, 637 + runtime->rate); 638 + PDEBUG(WORK_INFO, "prepare(): rate=%d\n", runtime->rate); 639 + 640 + /* init struct for intermediate buffer */ 641 + memset(&ml403_ac97cr->ind_rec, 0, 642 + sizeof(struct snd_pcm_indirect2)); 643 + ml403_ac97cr->ind_rec.hw_buffer_size = CR_FIFO_SIZE; 644 + ml403_ac97cr->ind_rec.sw_buffer_size = 645 + snd_pcm_lib_buffer_bytes(substream); 646 + ml403_ac97cr->ind_rec.min_periods = -1; 647 + ml403_ac97cr->ind_rec.min_multiple = 648 + snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); 649 + PDEBUG(WORK_INFO, "prepare(): hw_buffer_size=%d, " 650 + "sw_buffer_size=%d, min_multiple=%d\n", 651 + CR_FIFO_SIZE, ml403_ac97cr->ind_rec.sw_buffer_size, 652 + ml403_ac97cr->ind_rec.min_multiple); 653 + return 0; 654 + } 655 + 656 + static int 657 + snd_ml403_ac97cr_pcm_capture_prepare(struct snd_pcm_substream *substream) 658 + { 659 + struct snd_ml403_ac97cr *ml403_ac97cr; 660 + struct snd_pcm_runtime *runtime; 661 + 662 + ml403_ac97cr = snd_pcm_substream_chip(substream); 663 + runtime = substream->runtime; 664 + 665 + PDEBUG(WORK_INFO, 666 + "prepare(capture): period_bytes=%d, minperiod_bytes=%d\n", 667 + snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); 668 + 669 + /* set sampling rate */ 670 + snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_LR_ADC_RATE, 671 + runtime->rate); 672 + PDEBUG(WORK_INFO, "prepare(capture): rate=%d\n", runtime->rate); 673 + 674 + /* init struct for intermediate buffer */ 675 + memset(&ml403_ac97cr->capture_ind2_rec, 0, 676 + sizeof(struct snd_pcm_indirect2)); 677 + ml403_ac97cr->capture_ind2_rec.hw_buffer_size = CR_FIFO_SIZE; 678 + ml403_ac97cr->capture_ind2_rec.sw_buffer_size = 679 + snd_pcm_lib_buffer_bytes(substream); 680 + ml403_ac97cr->capture_ind2_rec.min_multiple = 681 + snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); 682 + PDEBUG(WORK_INFO, "prepare(capture): hw_buffer_size=%d, " 683 + "sw_buffer_size=%d, min_multiple=%d\n", CR_FIFO_SIZE, 684 + ml403_ac97cr->capture_ind2_rec.sw_buffer_size, 685 + ml403_ac97cr->capture_ind2_rec.min_multiple); 686 + return 0; 687 + } 688 + 689 + static int snd_ml403_ac97cr_hw_free(struct snd_pcm_substream *substream) 690 + { 691 + PDEBUG(WORK_INFO, "hw_free()\n"); 692 + return snd_pcm_lib_free_pages(substream); 693 + } 694 + 695 + static int 696 + snd_ml403_ac97cr_hw_params(struct snd_pcm_substream *substream, 697 + struct snd_pcm_hw_params *hw_params) 698 + { 699 + PDEBUG(WORK_INFO, "hw_params(): desired buffer bytes=%d, desired " 700 + "period bytes=%d\n", 701 + params_buffer_bytes(hw_params), params_period_bytes(hw_params)); 702 + return snd_pcm_lib_malloc_pages(substream, 703 + params_buffer_bytes(hw_params)); 704 + } 705 + 706 + static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream) 707 + { 708 + struct snd_ml403_ac97cr *ml403_ac97cr; 709 + struct snd_pcm_runtime *runtime; 710 + 711 + ml403_ac97cr = snd_pcm_substream_chip(substream); 712 + runtime = substream->runtime; 713 + 714 + PDEBUG(WORK_INFO, "open(playback)\n"); 715 + ml403_ac97cr->playback_substream = substream; 716 + runtime->hw = snd_ml403_ac97cr_playback; 717 + 718 + snd_pcm_hw_constraint_step(runtime, 0, 719 + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 720 + CR_FIFO_SIZE / 2); 721 + return 0; 722 + } 723 + 724 + static int snd_ml403_ac97cr_capture_open(struct snd_pcm_substream *substream) 725 + { 726 + struct snd_ml403_ac97cr *ml403_ac97cr; 727 + struct snd_pcm_runtime *runtime; 728 + 729 + ml403_ac97cr = snd_pcm_substream_chip(substream); 730 + runtime = substream->runtime; 731 + 732 + PDEBUG(WORK_INFO, "open(capture)\n"); 733 + ml403_ac97cr->capture_substream = substream; 734 + runtime->hw = snd_ml403_ac97cr_capture; 735 + 736 + snd_pcm_hw_constraint_step(runtime, 0, 737 + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 738 + CR_FIFO_SIZE / 2); 739 + return 0; 740 + } 741 + 742 + static int snd_ml403_ac97cr_playback_close(struct snd_pcm_substream *substream) 743 + { 744 + struct snd_ml403_ac97cr *ml403_ac97cr; 745 + 746 + ml403_ac97cr = snd_pcm_substream_chip(substream); 747 + 748 + PDEBUG(WORK_INFO, "close(playback)\n"); 749 + ml403_ac97cr->playback_substream = NULL; 750 + return 0; 751 + } 752 + 753 + static int snd_ml403_ac97cr_capture_close(struct snd_pcm_substream *substream) 754 + { 755 + struct snd_ml403_ac97cr *ml403_ac97cr; 756 + 757 + ml403_ac97cr = snd_pcm_substream_chip(substream); 758 + 759 + PDEBUG(WORK_INFO, "close(capture)\n"); 760 + ml403_ac97cr->capture_substream = NULL; 761 + return 0; 762 + } 763 + 764 + static struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = { 765 + .open = snd_ml403_ac97cr_playback_open, 766 + .close = snd_ml403_ac97cr_playback_close, 767 + .ioctl = snd_pcm_lib_ioctl, 768 + .hw_params = snd_ml403_ac97cr_hw_params, 769 + .hw_free = snd_ml403_ac97cr_hw_free, 770 + .prepare = snd_ml403_ac97cr_pcm_playback_prepare, 771 + .trigger = snd_ml403_ac97cr_pcm_playback_trigger, 772 + .pointer = snd_ml403_ac97cr_pcm_pointer, 773 + }; 774 + 775 + static struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = { 776 + .open = snd_ml403_ac97cr_capture_open, 777 + .close = snd_ml403_ac97cr_capture_close, 778 + .ioctl = snd_pcm_lib_ioctl, 779 + .hw_params = snd_ml403_ac97cr_hw_params, 780 + .hw_free = snd_ml403_ac97cr_hw_free, 781 + .prepare = snd_ml403_ac97cr_pcm_capture_prepare, 782 + .trigger = snd_ml403_ac97cr_pcm_capture_trigger, 783 + .pointer = snd_ml403_ac97cr_pcm_pointer, 784 + }; 785 + 786 + static irqreturn_t snd_ml403_ac97cr_irq(int irq, void *dev_id) 787 + { 788 + struct snd_ml403_ac97cr *ml403_ac97cr; 789 + struct platform_device *pfdev; 790 + int cmp_irq; 791 + 792 + ml403_ac97cr = (struct snd_ml403_ac97cr *)dev_id; 793 + if (ml403_ac97cr == NULL) 794 + return IRQ_NONE; 795 + 796 + pfdev = ml403_ac97cr->pfdev; 797 + 798 + /* playback interrupt */ 799 + cmp_irq = platform_get_irq(pfdev, 0); 800 + if (irq == cmp_irq) { 801 + if (ml403_ac97cr->enable_irq) 802 + snd_pcm_indirect2_playback_interrupt( 803 + ml403_ac97cr->playback_substream, 804 + &ml403_ac97cr->ind_rec, 805 + snd_ml403_ac97cr_playback_ind2_copy, 806 + snd_ml403_ac97cr_playback_ind2_zero); 807 + else 808 + goto __disable_irq; 809 + } else { 810 + /* record interrupt */ 811 + cmp_irq = platform_get_irq(pfdev, 1); 812 + if (irq == cmp_irq) { 813 + if (ml403_ac97cr->enable_capture_irq) 814 + snd_pcm_indirect2_capture_interrupt( 815 + ml403_ac97cr->capture_substream, 816 + &ml403_ac97cr->capture_ind2_rec, 817 + snd_ml403_ac97cr_capture_ind2_copy, 818 + snd_ml403_ac97cr_capture_ind2_null); 819 + else 820 + goto __disable_irq; 821 + } else 822 + return IRQ_NONE; 823 + } 824 + return IRQ_HANDLED; 825 + 826 + __disable_irq: 827 + PDEBUG(INIT_INFO, "irq(): irq %d is meant to be disabled! So, now try " 828 + "to disable it _really_!\n", irq); 829 + disable_irq_nosync(irq); 830 + return IRQ_HANDLED; 831 + } 832 + 833 + static unsigned short 834 + snd_ml403_ac97cr_codec_read(struct snd_ac97 *ac97, unsigned short reg) 835 + { 836 + struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; 837 + #ifdef CODEC_STAT 838 + u32 stat; 839 + u32 rafaccess = 0; 840 + #endif 841 + unsigned long end_time; 842 + u16 value = 0; 843 + 844 + if (!LM4550_RF_OK(reg)) { 845 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 846 + "access to unknown/unused codec register 0x%x " 847 + "ignored!\n", reg); 848 + return 0; 849 + } 850 + /* check if we can fake/answer this access from our shadow register */ 851 + if ((lm4550_regfile[reg / 2].flag & 852 + (LM4550_REG_DONEREAD | LM4550_REG_ALLFAKE)) && 853 + !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { 854 + if (lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEREAD) { 855 + PDEBUG(CODEC_FAKE, "codec_read(): faking read from " 856 + "reg=0x%x, val=0x%x / %d\n", 857 + reg, lm4550_regfile[reg / 2].def, 858 + lm4550_regfile[reg / 2].def); 859 + return lm4550_regfile[reg / 2].def; 860 + } else if ((lm4550_regfile[reg / 2].flag & 861 + LM4550_REG_FAKEPROBE) && 862 + ml403_ac97cr->ac97_fake) { 863 + PDEBUG(CODEC_FAKE, "codec_read(): faking read from " 864 + "reg=0x%x, val=0x%x / %d (probe)\n", 865 + reg, lm4550_regfile[reg / 2].value, 866 + lm4550_regfile[reg / 2].value); 867 + return lm4550_regfile[reg / 2].value; 868 + } else { 869 + #ifdef CODEC_STAT 870 + PDEBUG(CODEC_FAKE, "codec_read(): read access " 871 + "answered by shadow register 0x%x (value=0x%x " 872 + "/ %d) (cw=%d cr=%d)\n", 873 + reg, lm4550_regfile[reg / 2].value, 874 + lm4550_regfile[reg / 2].value, 875 + ml403_ac97cr->ac97_write, 876 + ml403_ac97cr->ac97_read); 877 + #else 878 + PDEBUG(CODEC_FAKE, "codec_read(): read access " 879 + "answered by shadow register 0x%x (value=0x%x " 880 + "/ %d)\n", 881 + reg, lm4550_regfile[reg / 2].value, 882 + lm4550_regfile[reg / 2].value); 883 + #endif 884 + return lm4550_regfile[reg / 2].value; 885 + } 886 + } 887 + /* if we are here, we _have_ to access the codec really, no faking */ 888 + if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) 889 + return 0; 890 + #ifdef CODEC_STAT 891 + ml403_ac97cr->ac97_read++; 892 + #endif 893 + spin_lock(&ml403_ac97cr->reg_lock); 894 + out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), 895 + CR_CODEC_ADDR(reg) | CR_CODEC_READ); 896 + spin_unlock(&ml403_ac97cr->reg_lock); 897 + end_time = jiffies + (HZ / CODEC_TIMEOUT_AFTER_READ); 898 + do { 899 + spin_lock(&ml403_ac97cr->reg_lock); 900 + #ifdef CODEC_STAT 901 + rafaccess++; 902 + stat = in_be32(CR_REG(ml403_ac97cr, STATUS)); 903 + if ((stat & CR_RAF) == CR_RAF) { 904 + value = CR_CODEC_DATAREAD( 905 + in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); 906 + PDEBUG(CODEC_SUCCESS, "codec_read(): (done) reg=0x%x, " 907 + "value=0x%x / %d (STATUS=0x%x)\n", 908 + reg, value, value, stat); 909 + #else 910 + if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & 911 + CR_RAF) == CR_RAF) { 912 + value = CR_CODEC_DATAREAD( 913 + in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); 914 + PDEBUG(CODEC_SUCCESS, "codec_read(): (done) " 915 + "reg=0x%x, value=0x%x / %d\n", 916 + reg, value, value); 917 + #endif 918 + lm4550_regfile[reg / 2].value = value; 919 + lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; 920 + spin_unlock(&ml403_ac97cr->reg_lock); 921 + mutex_unlock(&ml403_ac97cr->cdc_mutex); 922 + return value; 923 + } 924 + spin_unlock(&ml403_ac97cr->reg_lock); 925 + schedule_timeout_uninterruptible(1); 926 + } while (time_after(end_time, jiffies)); 927 + /* read the DATAREAD register anyway, see comment below */ 928 + spin_lock(&ml403_ac97cr->reg_lock); 929 + value = 930 + CR_CODEC_DATAREAD(in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); 931 + spin_unlock(&ml403_ac97cr->reg_lock); 932 + #ifdef CODEC_STAT 933 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 934 + "timeout while codec read! " 935 + "(reg=0x%x, last STATUS=0x%x, DATAREAD=0x%x / %d, %d) " 936 + "(cw=%d, cr=%d)\n", 937 + reg, stat, value, value, rafaccess, 938 + ml403_ac97cr->ac97_write, ml403_ac97cr->ac97_read); 939 + #else 940 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 941 + "timeout while codec read! " 942 + "(reg=0x%x, DATAREAD=0x%x / %d)\n", 943 + reg, value, value); 944 + #endif 945 + /* BUG: This is PURE speculation! But after _most_ read timeouts the 946 + * value in the register is ok! 947 + */ 948 + lm4550_regfile[reg / 2].value = value; 949 + lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; 950 + mutex_unlock(&ml403_ac97cr->cdc_mutex); 951 + return value; 952 + } 953 + 954 + static void 955 + snd_ml403_ac97cr_codec_write(struct snd_ac97 *ac97, unsigned short reg, 956 + unsigned short val) 957 + { 958 + struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; 959 + 960 + #ifdef CODEC_STAT 961 + u32 stat; 962 + u32 rafaccess = 0; 963 + #endif 964 + #ifdef CODEC_WRITE_CHECK_RAF 965 + unsigned long end_time; 966 + #endif 967 + 968 + if (!LM4550_RF_OK(reg)) { 969 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 970 + "access to unknown/unused codec register 0x%x " 971 + "ignored!\n", reg); 972 + return; 973 + } 974 + if (lm4550_regfile[reg / 2].flag & LM4550_REG_READONLY) { 975 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 976 + "write access to read only codec register 0x%x " 977 + "ignored!\n", reg); 978 + return; 979 + } 980 + if ((val & lm4550_regfile[reg / 2].wmask) != val) { 981 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 982 + "write access to codec register 0x%x " 983 + "with bad value 0x%x / %d!\n", 984 + reg, val, val); 985 + val = val & lm4550_regfile[reg / 2].wmask; 986 + } 987 + if (((lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEPROBE) && 988 + ml403_ac97cr->ac97_fake) && 989 + !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { 990 + PDEBUG(CODEC_FAKE, "codec_write(): faking write to reg=0x%x, " 991 + "val=0x%x / %d\n", reg, val, val); 992 + lm4550_regfile[reg / 2].value = (val & 993 + lm4550_regfile[reg / 2].wmask); 994 + return; 995 + } 996 + if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) 997 + return; 998 + #ifdef CODEC_STAT 999 + ml403_ac97cr->ac97_write++; 1000 + #endif 1001 + spin_lock(&ml403_ac97cr->reg_lock); 1002 + out_be32(CR_REG(ml403_ac97cr, CODEC_DATAWRITE), 1003 + CR_CODEC_DATAWRITE(val)); 1004 + out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), 1005 + CR_CODEC_ADDR(reg) | CR_CODEC_WRITE); 1006 + spin_unlock(&ml403_ac97cr->reg_lock); 1007 + #ifdef CODEC_WRITE_CHECK_RAF 1008 + /* check CR_CODEC_RAF bit to see if write access to register is done; 1009 + * loop until bit is set or timeout happens 1010 + */ 1011 + end_time = jiffies + HZ / CODEC_TIMEOUT_AFTER_WRITE; 1012 + do { 1013 + spin_lock(&ml403_ac97cr->reg_lock); 1014 + #ifdef CODEC_STAT 1015 + rafaccess++; 1016 + stat = in_be32(CR_REG(ml403_ac97cr, STATUS)) 1017 + if ((stat & CR_RAF) == CR_RAF) { 1018 + #else 1019 + if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & 1020 + CR_RAF) == CR_RAF) { 1021 + #endif 1022 + PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " 1023 + "reg=0x%x, value=%d / 0x%x\n", 1024 + reg, val, val); 1025 + if (!(lm4550_regfile[reg / 2].flag & 1026 + LM4550_REG_NOSHADOW) && 1027 + !(lm4550_regfile[reg / 2].flag & 1028 + LM4550_REG_NOSAVE)) 1029 + lm4550_regfile[reg / 2].value = val; 1030 + lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; 1031 + spin_unlock(&ml403_ac97cr->reg_lock); 1032 + mutex_unlock(&ml403_ac97cr->cdc_mutex); 1033 + return; 1034 + } 1035 + spin_unlock(&ml403_ac97cr->reg_lock); 1036 + schedule_timeout_uninterruptible(1); 1037 + } while (time_after(end_time, jiffies)); 1038 + #ifdef CODEC_STAT 1039 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 1040 + "timeout while codec write " 1041 + "(reg=0x%x, val=0x%x / %d, last STATUS=0x%x, %d) " 1042 + "(cw=%d, cr=%d)\n", 1043 + reg, val, val, stat, rafaccess, ml403_ac97cr->ac97_write, 1044 + ml403_ac97cr->ac97_read); 1045 + #else 1046 + snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " 1047 + "timeout while codec write (reg=0x%x, val=0x%x / %d)\n", 1048 + reg, val, val); 1049 + #endif 1050 + #else /* CODEC_WRITE_CHECK_RAF */ 1051 + #if CODEC_WAIT_AFTER_WRITE > 0 1052 + /* officially, in AC97 spec there is no possibility for a AC97 1053 + * controller to determine, if write access is done or not - so: How 1054 + * is Xilinx able to provide a RAF bit for write access? 1055 + * => very strange, thus just don't check RAF bit (compare with 1056 + * Xilinx's example app in EDK 8.1i) and wait 1057 + */ 1058 + schedule_timeout_uninterruptible(HZ / CODEC_WAIT_AFTER_WRITE); 1059 + #endif 1060 + PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " 1061 + "reg=0x%x, value=%d / 0x%x (no RAF check)\n", 1062 + reg, val, val); 1063 + #endif 1064 + mutex_unlock(&ml403_ac97cr->cdc_mutex); 1065 + return; 1066 + } 1067 + 1068 + static int __devinit 1069 + snd_ml403_ac97cr_chip_init(struct snd_ml403_ac97cr *ml403_ac97cr) 1070 + { 1071 + unsigned long end_time; 1072 + PDEBUG(INIT_INFO, "chip_init():\n"); 1073 + end_time = jiffies + HZ / CODEC_TIMEOUT_ON_INIT; 1074 + do { 1075 + if (in_be32(CR_REG(ml403_ac97cr, STATUS)) & CR_CODECREADY) { 1076 + /* clear both hardware FIFOs */ 1077 + out_be32(CR_REG(ml403_ac97cr, RESETFIFO), 1078 + CR_RECRESET | CR_PLAYRESET); 1079 + PDEBUG(INIT_INFO, "chip_init(): (done)\n"); 1080 + return 0; 1081 + } 1082 + schedule_timeout_uninterruptible(1); 1083 + } while (time_after(end_time, jiffies)); 1084 + snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " 1085 + "timeout while waiting for codec, " 1086 + "not ready!\n"); 1087 + return -EBUSY; 1088 + } 1089 + 1090 + static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr) 1091 + { 1092 + PDEBUG(INIT_INFO, "free():\n"); 1093 + /* irq release */ 1094 + if (ml403_ac97cr->irq >= 0) 1095 + free_irq(ml403_ac97cr->irq, ml403_ac97cr); 1096 + if (ml403_ac97cr->capture_irq >= 0) 1097 + free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr); 1098 + /* give back "port" */ 1099 + if (ml403_ac97cr->port != NULL) 1100 + iounmap(ml403_ac97cr->port); 1101 + kfree(ml403_ac97cr); 1102 + PDEBUG(INIT_INFO, "free(): (done)\n"); 1103 + return 0; 1104 + } 1105 + 1106 + static int snd_ml403_ac97cr_dev_free(struct snd_device *snddev) 1107 + { 1108 + struct snd_ml403_ac97cr *ml403_ac97cr = snddev->device_data; 1109 + PDEBUG(INIT_INFO, "dev_free():\n"); 1110 + return snd_ml403_ac97cr_free(ml403_ac97cr); 1111 + } 1112 + 1113 + static int __devinit 1114 + snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, 1115 + struct snd_ml403_ac97cr **rml403_ac97cr) 1116 + { 1117 + struct snd_ml403_ac97cr *ml403_ac97cr; 1118 + int err; 1119 + static struct snd_device_ops ops = { 1120 + .dev_free = snd_ml403_ac97cr_dev_free, 1121 + }; 1122 + struct resource *resource; 1123 + int irq; 1124 + 1125 + *rml403_ac97cr = NULL; 1126 + ml403_ac97cr = kzalloc(sizeof(*ml403_ac97cr), GFP_KERNEL); 1127 + if (ml403_ac97cr == NULL) 1128 + return -ENOMEM; 1129 + spin_lock_init(&ml403_ac97cr->reg_lock); 1130 + mutex_init(&ml403_ac97cr->cdc_mutex); 1131 + ml403_ac97cr->card = card; 1132 + ml403_ac97cr->pfdev = pfdev; 1133 + ml403_ac97cr->irq = -1; 1134 + ml403_ac97cr->enable_irq = 0; 1135 + ml403_ac97cr->capture_irq = -1; 1136 + ml403_ac97cr->enable_capture_irq = 0; 1137 + ml403_ac97cr->port = NULL; 1138 + ml403_ac97cr->res_port = NULL; 1139 + 1140 + PDEBUG(INIT_INFO, "Trying to reserve resources now ...\n"); 1141 + resource = platform_get_resource(pfdev, IORESOURCE_MEM, 0); 1142 + /* get "port" */ 1143 + ml403_ac97cr->port = ioremap_nocache(resource->start, 1144 + (resource->end) - 1145 + (resource->start) + 1); 1146 + if (ml403_ac97cr->port == NULL) { 1147 + snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " 1148 + "unable to remap memory region (%x to %x)\n", 1149 + resource->start, resource->end); 1150 + snd_ml403_ac97cr_free(ml403_ac97cr); 1151 + return -EBUSY; 1152 + } 1153 + snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " 1154 + "remap controller memory region to " 1155 + "0x%x done\n", (unsigned int)ml403_ac97cr->port); 1156 + /* get irq */ 1157 + irq = platform_get_irq(pfdev, 0); 1158 + if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, 1159 + pfdev->dev.bus_id, (void *)ml403_ac97cr)) { 1160 + snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " 1161 + "unable to grab IRQ %d\n", 1162 + irq); 1163 + snd_ml403_ac97cr_free(ml403_ac97cr); 1164 + return -EBUSY; 1165 + } 1166 + ml403_ac97cr->irq = irq; 1167 + snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " 1168 + "request (playback) irq %d done\n", 1169 + ml403_ac97cr->irq); 1170 + irq = platform_get_irq(pfdev, 1); 1171 + if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, 1172 + pfdev->dev.bus_id, (void *)ml403_ac97cr)) { 1173 + snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " 1174 + "unable to grab IRQ %d\n", 1175 + irq); 1176 + snd_ml403_ac97cr_free(ml403_ac97cr); 1177 + return -EBUSY; 1178 + } 1179 + ml403_ac97cr->capture_irq = irq; 1180 + snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " 1181 + "request (capture) irq %d done\n", 1182 + ml403_ac97cr->capture_irq); 1183 + 1184 + err = snd_ml403_ac97cr_chip_init(ml403_ac97cr); 1185 + if (err < 0) { 1186 + snd_ml403_ac97cr_free(ml403_ac97cr); 1187 + return err; 1188 + } 1189 + 1190 + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ml403_ac97cr, &ops); 1191 + if (err < 0) { 1192 + PDEBUG(INIT_FAILURE, "probe(): snd_device_new() failed!\n"); 1193 + snd_ml403_ac97cr_free(ml403_ac97cr); 1194 + return err; 1195 + } 1196 + 1197 + snd_card_set_dev(card, &pfdev->dev); 1198 + 1199 + *rml403_ac97cr = ml403_ac97cr; 1200 + return 0; 1201 + } 1202 + 1203 + static void snd_ml403_ac97cr_mixer_free(struct snd_ac97 *ac97) 1204 + { 1205 + struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; 1206 + PDEBUG(INIT_INFO, "mixer_free():\n"); 1207 + ml403_ac97cr->ac97 = NULL; 1208 + PDEBUG(INIT_INFO, "mixer_free(): (done)\n"); 1209 + } 1210 + 1211 + static int __devinit 1212 + snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) 1213 + { 1214 + struct snd_ac97_bus *bus; 1215 + struct snd_ac97_template ac97; 1216 + int err; 1217 + static struct snd_ac97_bus_ops ops = { 1218 + .write = snd_ml403_ac97cr_codec_write, 1219 + .read = snd_ml403_ac97cr_codec_read, 1220 + }; 1221 + PDEBUG(INIT_INFO, "mixer():\n"); 1222 + err = snd_ac97_bus(ml403_ac97cr->card, 0, &ops, NULL, &bus); 1223 + if (err < 0) 1224 + return err; 1225 + 1226 + memset(&ac97, 0, sizeof(ac97)); 1227 + ml403_ac97cr->ac97_fake = 1; 1228 + lm4550_regfile_init(); 1229 + #ifdef CODEC_STAT 1230 + ml403_ac97cr->ac97_read = 0; 1231 + ml403_ac97cr->ac97_write = 0; 1232 + #endif 1233 + ac97.private_data = ml403_ac97cr; 1234 + ac97.private_free = snd_ml403_ac97cr_mixer_free; 1235 + ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM | 1236 + AC97_SCAP_NO_SPDIF; 1237 + err = snd_ac97_mixer(bus, &ac97, &ml403_ac97cr->ac97); 1238 + ml403_ac97cr->ac97_fake = 0; 1239 + lm4550_regfile_write_values_after_init(ml403_ac97cr->ac97); 1240 + PDEBUG(INIT_INFO, "mixer(): (done) snd_ac97_mixer()=%d\n", err); 1241 + return err; 1242 + } 1243 + 1244 + static int __devinit 1245 + snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, 1246 + struct snd_pcm **rpcm) 1247 + { 1248 + struct snd_pcm *pcm; 1249 + int err; 1250 + 1251 + if (rpcm) 1252 + *rpcm = NULL; 1253 + err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1, 1254 + &pcm); 1255 + if (err < 0) 1256 + return err; 1257 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1258 + &snd_ml403_ac97cr_playback_ops); 1259 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 1260 + &snd_ml403_ac97cr_capture_ops); 1261 + pcm->private_data = ml403_ac97cr; 1262 + pcm->info_flags = 0; 1263 + strcpy(pcm->name, "ML403AC97CR DAC/ADC"); 1264 + ml403_ac97cr->pcm = pcm; 1265 + 1266 + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, 1267 + snd_dma_continuous_data(GFP_KERNEL), 1268 + 64 * 1024, 1269 + 128 * 1024); 1270 + if (rpcm) 1271 + *rpcm = pcm; 1272 + return 0; 1273 + } 1274 + 1275 + static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev) 1276 + { 1277 + struct snd_card *card; 1278 + struct snd_ml403_ac97cr *ml403_ac97cr = NULL; 1279 + int err; 1280 + int dev = pfdev->id; 1281 + 1282 + if (dev >= SNDRV_CARDS) 1283 + return -ENODEV; 1284 + if (!enable[dev]) 1285 + return -ENOENT; 1286 + 1287 + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); 1288 + if (card == NULL) 1289 + return -ENOMEM; 1290 + err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr); 1291 + if (err < 0) { 1292 + PDEBUG(INIT_FAILURE, "probe(): create failed!\n"); 1293 + snd_card_free(card); 1294 + return err; 1295 + } 1296 + PDEBUG(INIT_INFO, "probe(): create done\n"); 1297 + card->private_data = ml403_ac97cr; 1298 + err = snd_ml403_ac97cr_mixer(ml403_ac97cr); 1299 + if (err < 0) { 1300 + snd_card_free(card); 1301 + return err; 1302 + } 1303 + PDEBUG(INIT_INFO, "probe(): mixer done\n"); 1304 + err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL); 1305 + if (err < 0) { 1306 + snd_card_free(card); 1307 + return err; 1308 + } 1309 + PDEBUG(INIT_INFO, "probe(): PCM done\n"); 1310 + strcpy(card->driver, SND_ML403_AC97CR_DRIVER); 1311 + strcpy(card->shortname, "ML403 AC97 Controller Reference"); 1312 + sprintf(card->longname, "%s %s at 0x%lx, irq %i & %i, device %i", 1313 + card->shortname, card->driver, 1314 + (unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq, 1315 + ml403_ac97cr->capture_irq, dev + 1); 1316 + 1317 + err = snd_card_register(card); 1318 + if (err < 0) { 1319 + snd_card_free(card); 1320 + return err; 1321 + } 1322 + platform_set_drvdata(pfdev, card); 1323 + PDEBUG(INIT_INFO, "probe(): (done)\n"); 1324 + return 0; 1325 + } 1326 + 1327 + static int snd_ml403_ac97cr_remove(struct platform_device *pfdev) 1328 + { 1329 + snd_card_free(platform_get_drvdata(pfdev)); 1330 + platform_set_drvdata(pfdev, NULL); 1331 + return 0; 1332 + } 1333 + 1334 + static struct platform_driver snd_ml403_ac97cr_driver = { 1335 + .probe = snd_ml403_ac97cr_probe, 1336 + .remove = snd_ml403_ac97cr_remove, 1337 + .driver = { 1338 + .name = SND_ML403_AC97CR_DRIVER, 1339 + }, 1340 + }; 1341 + 1342 + static int __init alsa_card_ml403_ac97cr_init(void) 1343 + { 1344 + return platform_driver_register(&snd_ml403_ac97cr_driver); 1345 + } 1346 + 1347 + static void __exit alsa_card_ml403_ac97cr_exit(void) 1348 + { 1349 + platform_driver_unregister(&snd_ml403_ac97cr_driver); 1350 + } 1351 + 1352 + module_init(alsa_card_ml403_ac97cr_init) 1353 + module_exit(alsa_card_ml403_ac97cr_exit)
+591
sound/drivers/pcm-indirect2.c
··· 1 + /* 2 + * Helper functions for indirect PCM data transfer to a simple FIFO in 3 + * hardware (small, no possibility to read "hardware io position", 4 + * updating position done by interrupt, ...) 5 + * 6 + * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> 7 + * 8 + * Based on "pcm-indirect.h" (alsa-driver-1.0.13) by 9 + * 10 + * Copyright (c) by Takashi Iwai <tiwai@suse.de> 11 + * Jaroslav Kysela <perex@suse.cz> 12 + * 13 + * This program is free software; you can redistribute it and/or modify 14 + * it under the terms of the GNU General Public License as published by 15 + * the Free Software Foundation; either version 2 of the License, or 16 + * (at your option) any later version. 17 + * 18 + * This program is distributed in the hope that it will be useful, 19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 + * GNU General Public License for more details. 22 + * 23 + * You should have received a copy of the GNU General Public License 24 + * along with this program; if not, write to the Free Software 25 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 26 + */ 27 + 28 + /* #dependency of sound/core.h# */ 29 + #include <sound/driver.h> 30 + /* snd_printk/d() */ 31 + #include <sound/core.h> 32 + /* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t 33 + * snd_pcm_period_elapsed() */ 34 + #include <sound/pcm.h> 35 + 36 + #include "pcm-indirect2.h" 37 + 38 + #ifdef SND_PCM_INDIRECT2_STAT 39 + /* jiffies */ 40 + #include <linux/jiffies.h> 41 + 42 + void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream, 43 + struct snd_pcm_indirect2 *rec) 44 + { 45 + struct snd_pcm_runtime *runtime = substream->runtime; 46 + int i; 47 + int j; 48 + int k; 49 + int seconds = (rec->lastbytetime - rec->firstbytetime) / HZ; 50 + 51 + snd_printk(KERN_DEBUG "STAT: mul_elapsed: %u, mul_elapsed_real: %d, " 52 + "irq_occured: %d\n", 53 + rec->mul_elapsed, rec->mul_elapsed_real, rec->irq_occured); 54 + snd_printk(KERN_DEBUG "STAT: min_multiple: %d (irqs/period)\n", 55 + rec->min_multiple); 56 + snd_printk(KERN_DEBUG "STAT: firstbytetime: %lu, lastbytetime: %lu, " 57 + "firstzerotime: %lu\n", 58 + rec->firstbytetime, rec->lastbytetime, rec->firstzerotime); 59 + snd_printk(KERN_DEBUG "STAT: bytes2hw: %u Bytes => (by runtime->rate) " 60 + "length: %d s\n", 61 + rec->bytes2hw, rec->bytes2hw / 2 / 2 / runtime->rate); 62 + snd_printk(KERN_DEBUG "STAT: (by measurement) length: %d => " 63 + "rate: %d Bytes/s = %d Frames/s|Hz\n", 64 + seconds, rec->bytes2hw / seconds, 65 + rec->bytes2hw / 2 / 2 / seconds); 66 + snd_printk(KERN_DEBUG 67 + "STAT: zeros2hw: %u = %d ms ~ %d * %d zero copies\n", 68 + rec->zeros2hw, ((rec->zeros2hw / 2 / 2) * 1000) / 69 + runtime->rate, 70 + rec->zeros2hw / (rec->hw_buffer_size / 2), 71 + (rec->hw_buffer_size / 2)); 72 + snd_printk(KERN_DEBUG "STAT: pointer_calls: %u, lastdifftime: %u\n", 73 + rec->pointer_calls, rec->lastdifftime); 74 + snd_printk(KERN_DEBUG "STAT: sw_io: %d, sw_data: %d\n", rec->sw_io, 75 + rec->sw_data); 76 + snd_printk(KERN_DEBUG "STAT: byte_sizes[]:\n"); 77 + k = 0; 78 + for (j = 0; j < 8; j++) { 79 + for (i = j * 8; i < (j + 1) * 8; i++) 80 + if (rec->byte_sizes[i] != 0) { 81 + snd_printk(KERN_DEBUG "%u: %u", 82 + i, rec->byte_sizes[i]); 83 + k++; 84 + } 85 + if (((k % 8) == 0) && (k != 0)) { 86 + snd_printk(KERN_DEBUG "\n"); 87 + k = 0; 88 + } 89 + } 90 + snd_printk(KERN_DEBUG "\n"); 91 + snd_printk(KERN_DEBUG "STAT: zero_sizes[]:\n"); 92 + for (j = 0; j < 8; j++) { 93 + k = 0; 94 + for (i = j * 8; i < (j + 1) * 8; i++) 95 + if (rec->zero_sizes[i] != 0) 96 + snd_printk(KERN_DEBUG "%u: %u", 97 + i, rec->zero_sizes[i]); 98 + else 99 + k++; 100 + if (!k) 101 + snd_printk(KERN_DEBUG "\n"); 102 + } 103 + snd_printk(KERN_DEBUG "\n"); 104 + snd_printk(KERN_DEBUG "STAT: min_adds[]:\n"); 105 + for (j = 0; j < 8; j++) { 106 + if (rec->min_adds[j] != 0) 107 + snd_printk(KERN_DEBUG "%u: %u", j, rec->min_adds[j]); 108 + } 109 + snd_printk(KERN_DEBUG "\n"); 110 + snd_printk(KERN_DEBUG "STAT: mul_adds[]:\n"); 111 + for (j = 0; j < 8; j++) { 112 + if (rec->mul_adds[j] != 0) 113 + snd_printk(KERN_DEBUG "%u: %u", j, rec->mul_adds[j]); 114 + } 115 + snd_printk(KERN_DEBUG "\n"); 116 + snd_printk(KERN_DEBUG 117 + "STAT: zero_times_saved: %d, zero_times_notsaved: %d\n", 118 + rec->zero_times_saved, rec->zero_times_notsaved); 119 + /* snd_printk(KERN_DEBUG "STAT: zero_times[]\n"); 120 + i = 0; 121 + for (j = 0; j < 3750; j++) { 122 + if (rec->zero_times[j] != 0) { 123 + snd_printk(KERN_DEBUG "%u: %u", j, rec->zero_times[j]); 124 + i++; 125 + } 126 + if (((i % 8) == 0) && (i != 0)) 127 + snd_printk(KERN_DEBUG "\n"); 128 + } 129 + snd_printk(KERN_DEBUG "\n"); */ 130 + return; 131 + } 132 + #endif 133 + 134 + /* 135 + * _internal_ helper function for playback/capture transfer function 136 + */ 137 + static void 138 + snd_pcm_indirect2_increase_min_periods(struct snd_pcm_substream *substream, 139 + struct snd_pcm_indirect2 *rec, 140 + int isplay, int iscopy, 141 + unsigned int bytes) 142 + { 143 + if (rec->min_periods >= 0) { 144 + if (iscopy) { 145 + rec->sw_io += bytes; 146 + if (rec->sw_io >= rec->sw_buffer_size) 147 + rec->sw_io -= rec->sw_buffer_size; 148 + } else if (isplay) { 149 + /* If application does not write data in multiples of 150 + * a period, move sw_data to the next correctly aligned 151 + * position, so that sw_io can converge to it (in the 152 + * next step). 153 + */ 154 + if (!rec->check_alignment) { 155 + if (rec->bytes2hw % 156 + snd_pcm_lib_period_bytes(substream)) { 157 + unsigned bytes2hw_aligned = 158 + (1 + 159 + (rec->bytes2hw / 160 + snd_pcm_lib_period_bytes 161 + (substream))) * 162 + snd_pcm_lib_period_bytes 163 + (substream); 164 + rec->sw_data = 165 + bytes2hw_aligned % 166 + rec->sw_buffer_size; 167 + #ifdef SND_PCM_INDIRECT2_STAT 168 + snd_printk(KERN_DEBUG 169 + "STAT: @re-align: aligned " 170 + "bytes2hw to next period " 171 + "size boundary: %d " 172 + "(instead of %d)\n", 173 + bytes2hw_aligned, 174 + rec->bytes2hw); 175 + snd_printk(KERN_DEBUG 176 + "STAT: @re-align: sw_data " 177 + "moves to: %d\n", 178 + rec->sw_data); 179 + #endif 180 + } 181 + rec->check_alignment = 1; 182 + } 183 + /* We are at the end and are copying zeros into the 184 + * fifo. 185 + * Now, we have to make sure that sw_io is increased 186 + * until the position of sw_data: Filling the fifo with 187 + * the first zeros means, the last bytes were played. 188 + */ 189 + if (rec->sw_io != rec->sw_data) { 190 + unsigned int diff; 191 + if (rec->sw_data > rec->sw_io) 192 + diff = rec->sw_data - rec->sw_io; 193 + else 194 + diff = (rec->sw_buffer_size - 195 + rec->sw_io) + 196 + rec->sw_data; 197 + if (bytes >= diff) 198 + rec->sw_io = rec->sw_data; 199 + else { 200 + rec->sw_io += bytes; 201 + if (rec->sw_io >= rec->sw_buffer_size) 202 + rec->sw_io -= 203 + rec->sw_buffer_size; 204 + } 205 + } 206 + } 207 + rec->min_period_count += bytes; 208 + if (rec->min_period_count >= (rec->hw_buffer_size / 2)) { 209 + rec->min_periods += (rec->min_period_count / 210 + (rec->hw_buffer_size / 2)); 211 + #ifdef SND_PCM_INDIRECT2_STAT 212 + if ((rec->min_period_count / 213 + (rec->hw_buffer_size / 2)) > 7) 214 + snd_printk(KERN_DEBUG 215 + "STAT: more than 7 (%d) min_adds " 216 + "at once - too big to save!\n", 217 + (rec->min_period_count / 218 + (rec->hw_buffer_size / 2))); 219 + else 220 + rec->min_adds[(rec->min_period_count / 221 + (rec->hw_buffer_size / 2))]++; 222 + #endif 223 + rec->min_period_count = (rec->min_period_count % 224 + (rec->hw_buffer_size / 2)); 225 + } 226 + } else if (isplay && iscopy) 227 + rec->min_periods = 0; 228 + } 229 + 230 + /* 231 + * helper function for playback/capture pointer callback 232 + */ 233 + snd_pcm_uframes_t 234 + snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream, 235 + struct snd_pcm_indirect2 *rec) 236 + { 237 + #ifdef SND_PCM_INDIRECT2_STAT 238 + rec->pointer_calls++; 239 + #endif 240 + return bytes_to_frames(substream->runtime, rec->sw_io); 241 + } 242 + 243 + /* 244 + * _internal_ helper function for playback interrupt callback 245 + */ 246 + static void 247 + snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream, 248 + struct snd_pcm_indirect2 *rec, 249 + snd_pcm_indirect2_copy_t copy, 250 + snd_pcm_indirect2_zero_t zero) 251 + { 252 + struct snd_pcm_runtime *runtime = substream->runtime; 253 + snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; 254 + 255 + /* runtime->control->appl_ptr: position where ALSA will write next time 256 + * rec->appl_ptr: position where ALSA was last time 257 + * diff: obviously ALSA wrote that much bytes into the intermediate 258 + * buffer since we checked last time 259 + */ 260 + snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; 261 + 262 + if (diff) { 263 + #ifdef SND_PCM_INDIRECT2_STAT 264 + rec->lastdifftime = jiffies; 265 + #endif 266 + if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) 267 + diff += runtime->boundary; 268 + /* number of bytes "added" by ALSA increases the number of 269 + * bytes which are ready to "be transfered to HW"/"played" 270 + * Then, set rec->appl_ptr to not count bytes twice next time. 271 + */ 272 + rec->sw_ready += (int)frames_to_bytes(runtime, diff); 273 + rec->appl_ptr = appl_ptr; 274 + } 275 + if (rec->hw_ready && (rec->sw_ready <= 0)) { 276 + unsigned int bytes; 277 + 278 + #ifdef SND_PCM_INDIRECT2_STAT 279 + if (rec->firstzerotime == 0) { 280 + rec->firstzerotime = jiffies; 281 + snd_printk(KERN_DEBUG 282 + "STAT: @firstzerotime: mul_elapsed: %d, " 283 + "min_period_count: %d\n", 284 + rec->mul_elapsed, rec->min_period_count); 285 + snd_printk(KERN_DEBUG 286 + "STAT: @firstzerotime: sw_io: %d, " 287 + "sw_data: %d, appl_ptr: %u\n", 288 + rec->sw_io, rec->sw_data, 289 + (unsigned int)appl_ptr); 290 + } 291 + if ((jiffies - rec->firstzerotime) < 3750) { 292 + rec->zero_times[(jiffies - rec->firstzerotime)]++; 293 + rec->zero_times_saved++; 294 + } else 295 + rec->zero_times_notsaved++; 296 + #endif 297 + bytes = zero(substream, rec); 298 + 299 + #ifdef SND_PCM_INDIRECT2_STAT 300 + rec->zeros2hw += bytes; 301 + if (bytes < 64) 302 + rec->zero_sizes[bytes]++; 303 + else 304 + snd_printk(KERN_DEBUG 305 + "STAT: %d zero Bytes copied to hardware at " 306 + "once - too big to save!\n", 307 + bytes); 308 + #endif 309 + snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 0, 310 + bytes); 311 + return; 312 + } 313 + while (rec->hw_ready && (rec->sw_ready > 0)) { 314 + /* sw_to_end: max. number of bytes that can be read/take from 315 + * the current position (sw_data) in _one_ step 316 + */ 317 + unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data; 318 + 319 + /* bytes: number of bytes we have available (for reading) */ 320 + unsigned int bytes = rec->sw_ready; 321 + 322 + if (sw_to_end < bytes) 323 + bytes = sw_to_end; 324 + if (!bytes) 325 + break; 326 + 327 + #ifdef SND_PCM_INDIRECT2_STAT 328 + if (rec->firstbytetime == 0) 329 + rec->firstbytetime = jiffies; 330 + rec->lastbytetime = jiffies; 331 + #endif 332 + /* copy bytes from intermediate buffer position sw_data to the 333 + * HW and return number of bytes actually written 334 + * Furthermore, set hw_ready to 0, if the fifo isn't empty 335 + * now => more could be transfered to fifo 336 + */ 337 + bytes = copy(substream, rec, bytes); 338 + rec->bytes2hw += bytes; 339 + 340 + #ifdef SND_PCM_INDIRECT2_STAT 341 + if (bytes < 64) 342 + rec->byte_sizes[bytes]++; 343 + else 344 + snd_printk(KERN_DEBUG 345 + "STAT: %d Bytes copied to hardware at once " 346 + "- too big to save!\n", 347 + bytes); 348 + #endif 349 + /* increase sw_data by the number of actually written bytes 350 + * (= number of taken bytes from intermediate buffer) 351 + */ 352 + rec->sw_data += bytes; 353 + if (rec->sw_data == rec->sw_buffer_size) 354 + rec->sw_data = 0; 355 + /* now sw_data is the position where ALSA is going to write 356 + * in the intermediate buffer next time = position we are going 357 + * to read from next time 358 + */ 359 + 360 + snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 1, 361 + bytes); 362 + 363 + /* we read bytes from intermediate buffer, so we need to say 364 + * that the number of bytes ready for transfer are decreased 365 + * now 366 + */ 367 + rec->sw_ready -= bytes; 368 + } 369 + return; 370 + } 371 + 372 + /* 373 + * helper function for playback interrupt routine 374 + */ 375 + void 376 + snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream, 377 + struct snd_pcm_indirect2 *rec, 378 + snd_pcm_indirect2_copy_t copy, 379 + snd_pcm_indirect2_zero_t zero) 380 + { 381 + #ifdef SND_PCM_INDIRECT2_STAT 382 + rec->irq_occured++; 383 + #endif 384 + /* hardware played some bytes, so there is room again (in fifo) */ 385 + rec->hw_ready = 1; 386 + 387 + /* don't call ack() now, instead call transfer() function directly 388 + * (normally called by ack() ) 389 + */ 390 + snd_pcm_indirect2_playback_transfer(substream, rec, copy, zero); 391 + 392 + if (rec->min_periods >= rec->min_multiple) { 393 + #ifdef SND_PCM_INDIRECT2_STAT 394 + if ((rec->min_periods / rec->min_multiple) > 7) 395 + snd_printk(KERN_DEBUG 396 + "STAT: more than 7 (%d) mul_adds - too big " 397 + "to save!\n", 398 + (rec->min_periods / rec->min_multiple)); 399 + else 400 + rec->mul_adds[(rec->min_periods / 401 + rec->min_multiple)]++; 402 + rec->mul_elapsed_real += (rec->min_periods / 403 + rec->min_multiple); 404 + rec->mul_elapsed++; 405 + #endif 406 + rec->min_periods = 0; 407 + snd_pcm_period_elapsed(substream); 408 + } 409 + } 410 + 411 + /* 412 + * _internal_ helper function for capture interrupt callback 413 + */ 414 + static void 415 + snd_pcm_indirect2_capture_transfer(struct snd_pcm_substream *substream, 416 + struct snd_pcm_indirect2 *rec, 417 + snd_pcm_indirect2_copy_t copy, 418 + snd_pcm_indirect2_zero_t null) 419 + { 420 + struct snd_pcm_runtime *runtime = substream->runtime; 421 + snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; 422 + snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; 423 + 424 + if (diff) { 425 + #ifdef SND_PCM_INDIRECT2_STAT 426 + rec->lastdifftime = jiffies; 427 + #endif 428 + if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) 429 + diff += runtime->boundary; 430 + rec->sw_ready -= frames_to_bytes(runtime, diff); 431 + rec->appl_ptr = appl_ptr; 432 + } 433 + /* if hardware has something, but the intermediate buffer is full 434 + * => skip contents of buffer 435 + */ 436 + if (rec->hw_ready && (rec->sw_ready >= (int)rec->sw_buffer_size)) { 437 + unsigned int bytes; 438 + 439 + #ifdef SND_PCM_INDIRECT2_STAT 440 + if (rec->firstzerotime == 0) { 441 + rec->firstzerotime = jiffies; 442 + snd_printk(KERN_DEBUG "STAT: (capture) " 443 + "@firstzerotime: mul_elapsed: %d, " 444 + "min_period_count: %d\n", 445 + rec->mul_elapsed, rec->min_period_count); 446 + snd_printk(KERN_DEBUG "STAT: (capture) " 447 + "@firstzerotime: sw_io: %d, sw_data: %d, " 448 + "appl_ptr: %u\n", 449 + rec->sw_io, rec->sw_data, 450 + (unsigned int)appl_ptr); 451 + } 452 + if ((jiffies - rec->firstzerotime) < 3750) { 453 + rec->zero_times[(jiffies - rec->firstzerotime)]++; 454 + rec->zero_times_saved++; 455 + } else 456 + rec->zero_times_notsaved++; 457 + #endif 458 + bytes = null(substream, rec); 459 + 460 + #ifdef SND_PCM_INDIRECT2_STAT 461 + rec->zeros2hw += bytes; 462 + if (bytes < 64) 463 + rec->zero_sizes[bytes]++; 464 + else 465 + snd_printk(KERN_DEBUG 466 + "STAT: (capture) %d zero Bytes copied to " 467 + "hardware at once - too big to save!\n", 468 + bytes); 469 + #endif 470 + snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 0, 471 + bytes); 472 + /* report an overrun */ 473 + rec->sw_io = SNDRV_PCM_POS_XRUN; 474 + return; 475 + } 476 + while (rec->hw_ready && (rec->sw_ready < (int)rec->sw_buffer_size)) { 477 + /* sw_to_end: max. number of bytes that we can write to the 478 + * intermediate buffer (until it's end) 479 + */ 480 + size_t sw_to_end = rec->sw_buffer_size - rec->sw_data; 481 + 482 + /* bytes: max. number of bytes, which may be copied to the 483 + * intermediate buffer without overflow (in _one_ step) 484 + */ 485 + size_t bytes = rec->sw_buffer_size - rec->sw_ready; 486 + 487 + /* limit number of bytes (for transfer) by available room in 488 + * the intermediate buffer 489 + */ 490 + if (sw_to_end < bytes) 491 + bytes = sw_to_end; 492 + if (!bytes) 493 + break; 494 + 495 + #ifdef SND_PCM_INDIRECT2_STAT 496 + if (rec->firstbytetime == 0) 497 + rec->firstbytetime = jiffies; 498 + rec->lastbytetime = jiffies; 499 + #endif 500 + /* copy bytes from the intermediate buffer (position sw_data) 501 + * to the HW at most and return number of bytes actually copied 502 + * from HW 503 + * Furthermore, set hw_ready to 0, if the fifo is empty now. 504 + */ 505 + bytes = copy(substream, rec, bytes); 506 + rec->bytes2hw += bytes; 507 + 508 + #ifdef SND_PCM_INDIRECT2_STAT 509 + if (bytes < 64) 510 + rec->byte_sizes[bytes]++; 511 + else 512 + snd_printk(KERN_DEBUG 513 + "STAT: (capture) %d Bytes copied to " 514 + "hardware at once - too big to save!\n", 515 + bytes); 516 + #endif 517 + /* increase sw_data by the number of actually copied bytes from 518 + * HW 519 + */ 520 + rec->sw_data += bytes; 521 + if (rec->sw_data == rec->sw_buffer_size) 522 + rec->sw_data = 0; 523 + 524 + snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 1, 525 + bytes); 526 + 527 + /* number of bytes in the intermediate buffer, which haven't 528 + * been fetched by ALSA yet. 529 + */ 530 + rec->sw_ready += bytes; 531 + } 532 + return; 533 + } 534 + 535 + /* 536 + * helper function for capture interrupt routine 537 + */ 538 + void 539 + snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream, 540 + struct snd_pcm_indirect2 *rec, 541 + snd_pcm_indirect2_copy_t copy, 542 + snd_pcm_indirect2_zero_t null) 543 + { 544 + #ifdef SND_PCM_INDIRECT2_STAT 545 + rec->irq_occured++; 546 + #endif 547 + /* hardware recorded some bytes, so there is something to read from the 548 + * record fifo: 549 + */ 550 + rec->hw_ready = 1; 551 + 552 + /* don't call ack() now, instead call transfer() function directly 553 + * (normally called by ack() ) 554 + */ 555 + snd_pcm_indirect2_capture_transfer(substream, rec, copy, null); 556 + 557 + if (rec->min_periods >= rec->min_multiple) { 558 + 559 + #ifdef SND_PCM_INDIRECT2_STAT 560 + if ((rec->min_periods / rec->min_multiple) > 7) 561 + snd_printk(KERN_DEBUG 562 + "STAT: more than 7 (%d) mul_adds - " 563 + "too big to save!\n", 564 + (rec->min_periods / rec->min_multiple)); 565 + else 566 + rec->mul_adds[(rec->min_periods / 567 + rec->min_multiple)]++; 568 + rec->mul_elapsed_real += (rec->min_periods / 569 + rec->min_multiple); 570 + rec->mul_elapsed++; 571 + 572 + if (!(rec->mul_elapsed % 4)) { 573 + struct snd_pcm_runtime *runtime = substream->runtime; 574 + unsigned int appl_ptr = 575 + frames_to_bytes(runtime, 576 + (unsigned int)runtime->control-> 577 + appl_ptr) % rec->sw_buffer_size; 578 + int diff = rec->sw_data - appl_ptr; 579 + if (diff < 0) 580 + diff += rec->sw_buffer_size; 581 + snd_printk(KERN_DEBUG 582 + "STAT: mul_elapsed: %d, sw_data: %u, " 583 + "appl_ptr (bytes): %u, diff: %d\n", 584 + rec->mul_elapsed, rec->sw_data, appl_ptr, 585 + diff); 586 + } 587 + #endif 588 + rec->min_periods = 0; 589 + snd_pcm_period_elapsed(substream); 590 + } 591 + }
+140
sound/drivers/pcm-indirect2.h
··· 1 + /* 2 + * Helper functions for indirect PCM data transfer to a simple FIFO in 3 + * hardware (small, no possibility to read "hardware io position", 4 + * updating position done by interrupt, ...) 5 + * 6 + * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> 7 + * 8 + * Based on "pcm-indirect.h" (alsa-driver-1.0.13) by 9 + * 10 + * Copyright (c) by Takashi Iwai <tiwai@suse.de> 11 + * Jaroslav Kysela <perex@suse.cz> 12 + * 13 + * This program is free software; you can redistribute it and/or modify 14 + * it under the terms of the GNU General Public License as published by 15 + * the Free Software Foundation; either version 2 of the License, or 16 + * (at your option) any later version. 17 + * 18 + * This program is distributed in the hope that it will be useful, 19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 + * GNU General Public License for more details. 22 + * 23 + * You should have received a copy of the GNU General Public License 24 + * along with this program; if not, write to the Free Software 25 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 26 + */ 27 + 28 + #ifndef __SOUND_PCM_INDIRECT2_H 29 + #define __SOUND_PCM_INDIRECT2_H 30 + 31 + /* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t */ 32 + #include <sound/pcm.h> 33 + 34 + /* Debug options for code which may be removed completely in a final version */ 35 + #ifdef CONFIG_SND_DEBUG 36 + #define SND_PCM_INDIRECT2_STAT /* turn on some "statistics" about the 37 + * process of copying bytes from the 38 + * intermediate buffer to the hardware 39 + * fifo and the other way round 40 + */ 41 + #endif 42 + 43 + struct snd_pcm_indirect2 { 44 + unsigned int hw_buffer_size; /* Byte size of hardware buffer */ 45 + int hw_ready; /* playback: 1 = hw fifo has room left, 46 + * 0 = hw fifo is full 47 + */ 48 + unsigned int min_multiple; 49 + int min_periods; /* counts number of min. periods until 50 + * min_multiple is reached 51 + */ 52 + int min_period_count; /* counts bytes to count number of 53 + * min. periods 54 + */ 55 + 56 + unsigned int sw_buffer_size; /* Byte size of software buffer */ 57 + 58 + /* sw_data: position in intermediate buffer, where we will read (or 59 + * write) from/to next time (to transfer data to/from HW) 60 + */ 61 + unsigned int sw_data; /* Offset to next dst (or src) in sw 62 + * ring buffer 63 + */ 64 + /* easiest case (playback): 65 + * sw_data is nearly the same as ~ runtime->control->appl_ptr, with the 66 + * exception that sw_data is "behind" by the number if bytes ALSA wrote 67 + * to the intermediate buffer last time. 68 + * A call to ack() callback synchronizes both indirectly. 69 + */ 70 + 71 + /* We have no real sw_io pointer here. Usually sw_io is pointing to the 72 + * current playback/capture position _inside_ the hardware. Devices 73 + * with plain FIFOs often have no possibility to publish this position. 74 + * So we say: if sw_data is updated, that means bytes were copied to 75 + * the hardware, we increase sw_io by that amount, because there have 76 + * to be as much bytes which were played. So sw_io will stay behind 77 + * sw_data all the time and has to converge to sw_data at the end of 78 + * playback. 79 + */ 80 + unsigned int sw_io; /* Current software pointer in bytes */ 81 + 82 + /* sw_ready: number of bytes ALSA copied to the intermediate buffer, so 83 + * it represents the number of bytes which wait for transfer to the HW 84 + */ 85 + int sw_ready; /* Bytes ready to be transferred to/from hw */ 86 + 87 + /* appl_ptr: last known position of ALSA (where ALSA is going to write 88 + * next time into the intermediate buffer 89 + */ 90 + snd_pcm_uframes_t appl_ptr; /* Last seen appl_ptr */ 91 + 92 + unsigned int bytes2hw; 93 + int check_alignment; 94 + 95 + #ifdef SND_PCM_INDIRECT2_STAT 96 + unsigned int zeros2hw; 97 + unsigned int mul_elapsed; 98 + unsigned int mul_elapsed_real; 99 + unsigned long firstbytetime; 100 + unsigned long lastbytetime; 101 + unsigned long firstzerotime; 102 + unsigned int byte_sizes[64]; 103 + unsigned int zero_sizes[64]; 104 + unsigned int min_adds[8]; 105 + unsigned int mul_adds[8]; 106 + unsigned int zero_times[3750]; /* = 15s */ 107 + unsigned int zero_times_saved; 108 + unsigned int zero_times_notsaved; 109 + unsigned int irq_occured; 110 + unsigned int pointer_calls; 111 + unsigned int lastdifftime; 112 + #endif 113 + }; 114 + 115 + typedef size_t (*snd_pcm_indirect2_copy_t) (struct snd_pcm_substream *substream, 116 + struct snd_pcm_indirect2 *rec, 117 + size_t bytes); 118 + typedef size_t (*snd_pcm_indirect2_zero_t) (struct snd_pcm_substream *substream, 119 + struct snd_pcm_indirect2 *rec); 120 + 121 + #ifdef SND_PCM_INDIRECT2_STAT 122 + void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream, 123 + struct snd_pcm_indirect2 *rec); 124 + #endif 125 + 126 + snd_pcm_uframes_t 127 + snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream, 128 + struct snd_pcm_indirect2 *rec); 129 + void 130 + snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream, 131 + struct snd_pcm_indirect2 *rec, 132 + snd_pcm_indirect2_copy_t copy, 133 + snd_pcm_indirect2_zero_t zero); 134 + void 135 + snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream, 136 + struct snd_pcm_indirect2 *rec, 137 + snd_pcm_indirect2_copy_t copy, 138 + snd_pcm_indirect2_zero_t null); 139 + 140 + #endif /* __SOUND_PCM_INDIRECT2_H */