vserver 2.0 rc7
[linux-2.6.git] / sound / drivers / vx / vx_hwdep.c
1 /*
2  * Driver for Digigram VX soundcards
3  *
4  * DSP firmware management
5  *
6  * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.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 #include <sound/driver.h>
24 #include <linux/device.h>
25 #include <linux/firmware.h>
26 #include <sound/core.h>
27 #include <sound/hwdep.h>
28 #include <sound/vx_core.h>
29
30 #ifdef SND_VX_FW_LOADER
31
32 int snd_vx_setup_firmware(vx_core_t *chip)
33 {
34         static char *fw_files[VX_TYPE_NUMS][4] = {
35                 [VX_TYPE_BOARD] = {
36                         NULL, "x1_1_vx2.xlx", "bd56002.boot", "l_1_vx2.d56",
37                 },
38                 [VX_TYPE_V2] = {
39                         NULL, "x1_2_v22.xlx", "bd563v2.boot", "l_1_v22.d56",
40                 },
41                 [VX_TYPE_MIC] = {
42                         NULL, "x1_2_v22.xlx", "bd563v2.boot", "l_1_v22.d56",
43                 },
44                 [VX_TYPE_VXPOCKET] = {
45                         "bx_1_vxp.b56", "x1_1_vxp.xlx", "bd563s3.boot", "l_1_vxp.d56"
46                 },
47                 [VX_TYPE_VXP440] = {
48                         "bx_1_vp4.b56", "x1_1_vp4.xlx", "bd563s3.boot", "l_1_vp4.d56"
49                 },
50         };
51
52         int i, err;
53
54         for (i = 0; i < 4; i++) {
55                 char path[32];
56                 const struct firmware *fw;
57                 if (! fw_files[chip->type][i])
58                         continue;
59                 sprintf(path, "vx/%s", fw_files[chip->type][i]);
60                 if (request_firmware(&fw, path, chip->dev)) {
61                         snd_printk(KERN_ERR "vx: can't load firmware %s\n", path);
62                         return -ENOENT;
63                 }
64                 err = chip->ops->load_dsp(chip, i, fw);
65                 if (err < 0) {
66                         release_firmware(fw);
67                         return err;
68                 }
69                 if (i == 1)
70                         chip->chip_status |= VX_STAT_XILINX_LOADED;
71 #ifdef CONFIG_PM
72                 chip->firmware[i] = fw;
73 #else
74                 release_firmware(fw);
75 #endif
76         }
77
78         /* ok, we reached to the last one */
79         /* create the devices if not built yet */
80         if ((err = snd_vx_pcm_new(chip)) < 0)
81                 return err;
82
83         if ((err = snd_vx_mixer_new(chip)) < 0)
84                 return err;
85
86         if (chip->ops->add_controls)
87                 if ((err = chip->ops->add_controls(chip)) < 0)
88                         return err;
89
90         chip->chip_status |= VX_STAT_DEVICE_INIT;
91         chip->chip_status |= VX_STAT_CHIP_INIT;
92
93         return snd_card_register(chip->card);
94 }
95
96 /* exported */
97 void snd_vx_free_firmware(vx_core_t *chip)
98 {
99 #ifdef CONFIG_PM
100         int i;
101         for (i = 0; i < 4; i++)
102                 release_firmware(chip->firmware[i]);
103 #endif
104 }
105
106 #else /* old style firmware loading */
107
108 static int vx_hwdep_open(snd_hwdep_t *hw, struct file *file)
109 {
110         return 0;
111 }
112
113 static int vx_hwdep_release(snd_hwdep_t *hw, struct file *file)
114 {
115         return 0;
116 }
117
118 static int vx_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
119 {
120         static char *type_ids[VX_TYPE_NUMS] = {
121                 [VX_TYPE_BOARD] = "vxboard",
122                 [VX_TYPE_V2] = "vx222",
123                 [VX_TYPE_MIC] = "vx222",
124                 [VX_TYPE_VXPOCKET] = "vxpocket",
125                 [VX_TYPE_VXP440] = "vxp440",
126         };
127         vx_core_t *vx = hw->private_data;
128
129         snd_assert(type_ids[vx->type], return -EINVAL);
130         strcpy(info->id, type_ids[vx->type]);
131         if (vx_is_pcmcia(vx))
132                 info->num_dsps = 4;
133         else
134                 info->num_dsps = 3;
135         if (vx->chip_status & VX_STAT_CHIP_INIT)
136                 info->chip_ready = 1;
137         info->version = VX_DRIVER_VERSION;
138         return 0;
139 }
140
141 static void free_fw(const struct firmware *fw)
142 {
143         if (fw) {
144                 vfree(fw->data);
145                 kfree(fw);
146         }
147 }
148
149 static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
150 {
151         vx_core_t *vx = hw->private_data;
152         int index, err;
153         struct firmware *fw;
154
155         snd_assert(vx->ops->load_dsp, return -ENXIO);
156
157         fw = kmalloc(sizeof(*fw), GFP_KERNEL);
158         if (! fw) {
159                 snd_printk(KERN_ERR "cannot allocate firmware\n");
160                 return -ENOMEM;
161         }
162         fw->size = dsp->length;
163         fw->data = vmalloc(fw->size);
164         if (! fw->data) {
165                 snd_printk(KERN_ERR "cannot allocate firmware image (length=%d)\n",
166                            (int)fw->size);
167                 kfree(fw);
168                 return -ENOMEM;
169         }
170         if (copy_from_user(fw->data, dsp->image, dsp->length)) {
171                 free_fw(fw);
172                 return -EFAULT;
173         }
174
175         index = dsp->index;
176         if (! vx_is_pcmcia(vx))
177                 index++;
178         err = vx->ops->load_dsp(vx, index, fw);
179         if (err < 0) {
180                 free_fw(fw);
181                 return err;
182         }
183 #ifdef CONFIG_PM
184         vx->firmware[index] = fw;
185 #else
186         free_fw(fw);
187 #endif
188
189         if (index == 1)
190                 vx->chip_status |= VX_STAT_XILINX_LOADED;
191         if (index < 3)
192                 return 0;
193
194         /* ok, we reached to the last one */
195         /* create the devices if not built yet */
196         if (! (vx->chip_status & VX_STAT_DEVICE_INIT)) {
197                 if ((err = snd_vx_pcm_new(vx)) < 0)
198                         return err;
199
200                 if ((err = snd_vx_mixer_new(vx)) < 0)
201                         return err;
202
203                 if (vx->ops->add_controls)
204                         if ((err = vx->ops->add_controls(vx)) < 0)
205                                 return err;
206
207                 if ((err = snd_card_register(vx->card)) < 0)
208                         return err;
209
210                 vx->chip_status |= VX_STAT_DEVICE_INIT;
211         }
212         vx->chip_status |= VX_STAT_CHIP_INIT;
213         return 0;
214 }
215
216
217 /* exported */
218 int snd_vx_setup_firmware(vx_core_t *chip)
219 {
220         int err;
221         snd_hwdep_t *hw;
222
223         if ((err = snd_hwdep_new(chip->card, SND_VX_HWDEP_ID, 0, &hw)) < 0)
224                 return err;
225
226         hw->iface = SNDRV_HWDEP_IFACE_VX;
227         hw->private_data = chip;
228         hw->ops.open = vx_hwdep_open;
229         hw->ops.release = vx_hwdep_release;
230         hw->ops.dsp_status = vx_hwdep_dsp_status;
231         hw->ops.dsp_load = vx_hwdep_dsp_load;
232         hw->exclusive = 1;
233         sprintf(hw->name, "VX Loader (%s)", chip->card->driver);
234         chip->hwdep = hw;
235
236         return snd_card_register(chip->card);
237 }
238
239 /* exported */
240 void snd_vx_free_firmware(vx_core_t *chip)
241 {
242 #ifdef CONFIG_PM
243         int i;
244         for (i = 0; i < 4; i++)
245                 free_fw(chip->firmware[i]);
246 #endif
247 }
248
249 #endif /* SND_VX_FW_LOADER */