^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 1998-2002 by Paul Davis <pbd@op.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sound/snd_wavefront.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /* Control bits for the Load Control Register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define FX_LSB_TRANSFER 0x01 /* transfer after DSP LSB byte written */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define WAIT_IDLE 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) wavefront_fx_idle (snd_wavefront_t *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) unsigned int x = 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) for (i = 0; i < 1000; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) x = inb (dev->fx_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if ((x & 0x80) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (x & 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) snd_printk ("FX device never idle.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return (1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) wavefront_fx_mute (snd_wavefront_t *dev, int onoff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (!wavefront_fx_idle(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) outb (onoff ? 0x02 : 0x00, dev->fx_op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) wavefront_fx_memset (snd_wavefront_t *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) int cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned short *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (page < 0 || page > 7) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) snd_printk ("FX memset: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) "page must be >= 0 and <= 7\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (addr < 0 || addr > 0x7f) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) snd_printk ("FX memset: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) "addr must be >= 0 and <= 7f\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (cnt == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) outb (FX_LSB_TRANSFER, dev->fx_lcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) outb (page, dev->fx_dsp_page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) outb (addr, dev->fx_dsp_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) outb ((data[0] >> 8), dev->fx_dsp_msb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) outb ((data[0] & 0xff), dev->fx_dsp_lsb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) snd_printk ("FX: addr %d:%x set to 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) page, addr, data[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) outb (page, dev->fx_dsp_page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) outb (addr, dev->fx_dsp_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) for (i = 0; i < cnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) outb ((data[i] >> 8), dev->fx_dsp_msb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) outb ((data[i] & 0xff), dev->fx_dsp_lsb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!wavefront_fx_idle (dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (i != cnt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) snd_printk ("FX memset "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) "(0x%x, 0x%x, 0x%lx, %d) incomplete\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) page, addr, (unsigned long) data, cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) snd_wavefront_fx_detect (snd_wavefront_t *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* This is a crude check, but its the best one I have for now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) Certainly on the Maui and the Tropez, wavefront_fx_idle() will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) report "never idle", which suggests that this test should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) work OK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (inb (dev->fx_status) & 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) snd_printk ("Hmm, probably a Maui or Tropez.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) snd_wavefront_fx_open (struct snd_hwdep *hw, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (!try_module_get(hw->card->module))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) file->private_data = hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) snd_wavefront_fx_release (struct snd_hwdep *hw, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) module_put(hw->card->module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) snd_wavefront_card_t *acard;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) snd_wavefront_t *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) wavefront_fx_info r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) unsigned short *page_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) unsigned short *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) card = sdev->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (snd_BUG_ON(!card))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (snd_BUG_ON(!card->private_data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) acard = card->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) dev = &acard->wavefront;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (copy_from_user (&r, (void __user *)arg, sizeof (wavefront_fx_info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) switch (r.request) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) case WFFX_MUTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) wavefront_fx_mute (dev, r.data[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) case WFFX_MEMSET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (r.data[2] <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) snd_printk ("cannot write "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) "<= 0 bytes to FX\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) } else if (r.data[2] == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) pd = (unsigned short *) &r.data[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (r.data[2] > 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) snd_printk ("cannot write "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) "> 512 bytes to FX\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) page_data = memdup_user((unsigned char __user *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) r.data[3],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) r.data[2] * sizeof(short));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (IS_ERR(page_data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return PTR_ERR(page_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) pd = page_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) err = wavefront_fx_memset (dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) r.data[0], /* page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) r.data[1], /* addr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) r.data[2], /* cnt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) kfree(page_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) snd_printk ("FX: ioctl %d not yet supported\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) r.request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* YSS225 initialization.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) This code was developed using DOSEMU. The Turtle Beach SETUPSND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) of the port I/O done, using the Yamaha faxback document as a guide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) to add more logic to the code. Its really pretty weird.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) This is the approach of just dumping the whole I/O
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) sequence as a series of port/value pairs and a simple loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) that outputs it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) snd_wavefront_fx_start (snd_wavefront_t *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) const struct firmware *firmware = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (dev->fx_initialized)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) err = request_firmware(&firmware, "yamaha/yss225_registers.bin",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) dev->card->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) err = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) for (i = 0; i + 1 < firmware->size; i += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (firmware->data[i] >= 8 && firmware->data[i] < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) outb(firmware->data[i + 1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) dev->base + firmware->data[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) } else if (firmware->data[i] == WAIT_IDLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (!wavefront_fx_idle(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) err = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) snd_printk(KERN_ERR "invalid address"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) " in register data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) err = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) dev->fx_initialized = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) release_firmware(firmware);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) MODULE_FIRMWARE("yamaha/yss225_registers.bin");