2 * 32bit -> 64bit ioctl wrapper for PCM API
3 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <sound/driver.h>
22 #include <linux/time.h>
23 #include <linux/slab.h>
24 #include <linux/compat.h>
25 #include <sound/core.h>
26 #include <sound/pcm.h>
30 /* wrapper for sndrv_pcm_[us]frames */
31 struct sndrv_pcm_sframes_str {
32 sndrv_pcm_sframes_t val;
34 struct sndrv_pcm_sframes_str32 {
37 struct sndrv_pcm_uframes_str {
38 sndrv_pcm_uframes_t val;
40 struct sndrv_pcm_uframes_str32 {
44 #define CVT_sndrv_pcm_sframes_str() { COPY(val); }
45 #define CVT_sndrv_pcm_uframes_str() { COPY(val); }
48 struct sndrv_interval32 {
50 unsigned int openmin:1,
56 struct sndrv_pcm_hw_params32 {
58 struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
59 struct sndrv_mask mres[5]; /* reserved masks */
60 struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
61 struct sndrv_interval ires[9]; /* reserved intervals */
69 unsigned char reserved[64];
70 } __attribute__((packed));
72 #define numberof(array) (sizeof(array)/sizeof(array[0]))
74 #define CVT_sndrv_pcm_hw_params()\
78 for (i = 0; i < numberof(dst->masks); i++)\
80 for (i = 0; i < numberof(dst->intervals); i++) {\
81 COPY(intervals[i].min);\
82 COPY(intervals[i].max);\
83 COPY(intervals[i].openmin);\
84 COPY(intervals[i].openmax);\
85 COPY(intervals[i].integer);\
86 COPY(intervals[i].empty);\
97 struct sndrv_pcm_sw_params32 {
105 u32 silence_threshold;
108 unsigned char reserved[64];
109 } __attribute__((packed));
111 #define CVT_sndrv_pcm_sw_params()\
118 COPY(start_threshold);\
119 COPY(stop_threshold);\
120 COPY(silence_threshold);\
125 struct sndrv_pcm_channel_info32 {
130 } __attribute__((packed));
132 #define CVT_sndrv_pcm_channel_info()\
140 struct sndrv_pcm_status32 {
142 struct compat_timespec trigger_tstamp;
143 struct compat_timespec tstamp;
151 unsigned char reserved[60];
152 } __attribute__((packed));
154 #define CVT_sndrv_pcm_status()\
157 COPY(trigger_tstamp.tv_sec);\
158 COPY(trigger_tstamp.tv_nsec);\
159 COPY(tstamp.tv_sec);\
160 COPY(tstamp.tv_nsec);\
167 COPY(suspended_state);\
170 DEFINE_ALSA_IOCTL(pcm_uframes_str);
171 DEFINE_ALSA_IOCTL(pcm_sframes_str);
172 DEFINE_ALSA_IOCTL_BIG(pcm_hw_params);
173 DEFINE_ALSA_IOCTL(pcm_sw_params);
174 DEFINE_ALSA_IOCTL(pcm_channel_info);
175 DEFINE_ALSA_IOCTL(pcm_status);
179 struct sndrv_xferi32 {
183 } __attribute__((packed));
185 static int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
187 struct sndrv_xferi32 data32;
188 struct sndrv_xferi data;
192 if (copy_from_user(&data32, (void __user *)arg, sizeof(data32)))
194 memset(&data, 0, sizeof(data));
195 data.result = data32.result;
196 data.buf = compat_ptr(data32.buf);
197 data.frames = data32.frames;
200 err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
204 /* copy the result */
205 data32.result = data.result;
206 if (copy_to_user((void __user *)arg, &data32, sizeof(data32)))
212 /* snd_xfern needs remapping of bufs */
213 struct sndrv_xfern32 {
215 u32 bufs; /* this is void **; */
217 } __attribute__((packed));
220 * xfern ioctl nees to copy (up to) 128 pointers on stack.
221 * although we may pass the copied pointers through f_op->ioctl, but the ioctl
222 * handler there expands again the same 128 pointers on stack, so it is better
223 * to handle the function (calling pcm_readv/writev) directly in this handler.
225 static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
227 snd_pcm_file_t *pcm_file;
228 snd_pcm_substream_t *substream;
229 struct sndrv_xfern32 data32;
230 struct sndrv_xfern32 __user *srcptr = (void __user *)arg;
231 void __user **bufs = NULL;
236 /* FIXME: need to check whether fop->ioctl is sane */
238 pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO);
239 substream = pcm_file->substream;
240 snd_assert(substream != NULL && substream->runtime, return -ENXIO);
242 /* check validty of the command */
243 switch (native_ctl) {
244 case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
245 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
247 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
250 case SNDRV_PCM_IOCTL_READN_FRAMES:
251 if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
255 if ((ch = substream->runtime->channels) > 128)
257 if (get_user(data32.frames, &srcptr->frames))
259 __get_user(data32.bufs, &srcptr->bufs);
260 bufptr = compat_ptr(data32.bufs);
261 bufs = kmalloc(sizeof(void *) * 128, GFP_KERNEL);
264 for (i = 0; i < ch; i++) {
266 if (get_user(ptr, bufptr))
268 bufs[ch] = compat_ptr(ptr);
273 switch (native_ctl) {
274 case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
275 err = snd_pcm_lib_writev(substream, bufs, data32.frames);
277 case SNDRV_PCM_IOCTL_READN_FRAMES:
278 err = snd_pcm_lib_readv(substream, bufs, data32.frames);
283 if (put_user(err, &srcptr->result))
291 struct sndrv_pcm_hw_params_old32 {
293 u32 masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
294 SNDRV_PCM_HW_PARAM_ACCESS + 1];
295 struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
296 SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
304 unsigned char reserved[64];
305 } __attribute__((packed));
307 #define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
308 #define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
310 static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, struct sndrv_pcm_hw_params_old32 *oparams)
314 memset(params, 0, sizeof(*params));
315 params->flags = oparams->flags;
316 for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
317 params->masks[i].bits[0] = oparams->masks[i];
318 memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
319 params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
320 params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
321 params->info = oparams->info;
322 params->msbits = oparams->msbits;
323 params->rate_num = oparams->rate_num;
324 params->rate_den = oparams->rate_den;
325 params->fifo_size = oparams->fifo_size;
328 static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old32 *oparams, snd_pcm_hw_params_t *params)
332 memset(oparams, 0, sizeof(*oparams));
333 oparams->flags = params->flags;
334 for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
335 oparams->masks[i] = params->masks[i].bits[0];
336 memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
337 oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
338 oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
339 oparams->info = params->info;
340 oparams->msbits = params->msbits;
341 oparams->rate_num = params->rate_num;
342 oparams->rate_den = params->rate_den;
343 oparams->fifo_size = params->fifo_size;
346 static int _snd_ioctl32_pcm_hw_params_old(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
348 struct sndrv_pcm_hw_params_old32 *data32;
349 struct sndrv_pcm_hw_params *data;
353 data32 = snd_kcalloc(sizeof(*data32), GFP_KERNEL);
354 data = snd_kcalloc(sizeof(*data), GFP_KERNEL);
355 if (data32 == NULL || data == NULL) {
359 if (copy_from_user(data32, (void __user *)arg, sizeof(*data32))) {
363 snd_pcm_hw_convert_from_old_params(data, data32);
366 err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
370 snd_pcm_hw_convert_to_old_params(data32, data);
372 if (copy_to_user((void __user *)arg, data32, sizeof(*data32)))
386 DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine, pcm_hw_params, SNDRV_PCM_IOCTL_HW_REFINE);
387 DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params, pcm_hw_params, SNDRV_PCM_IOCTL_HW_PARAMS);
388 DEFINE_ALSA_IOCTL_ENTRY(pcm_sw_params, pcm_sw_params, SNDRV_PCM_IOCTL_SW_PARAMS);
389 DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine_old, pcm_hw_params_old, SNDRV_PCM_IOCTL_HW_REFINE);
390 DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params_old, pcm_hw_params_old, SNDRV_PCM_IOCTL_HW_PARAMS);
391 DEFINE_ALSA_IOCTL_ENTRY(pcm_status, pcm_status, SNDRV_PCM_IOCTL_STATUS);
392 DEFINE_ALSA_IOCTL_ENTRY(pcm_delay, pcm_sframes_str, SNDRV_PCM_IOCTL_DELAY);
393 DEFINE_ALSA_IOCTL_ENTRY(pcm_channel_info, pcm_channel_info, SNDRV_PCM_IOCTL_CHANNEL_INFO);
394 DEFINE_ALSA_IOCTL_ENTRY(pcm_rewind, pcm_uframes_str, SNDRV_PCM_IOCTL_REWIND);
395 DEFINE_ALSA_IOCTL_ENTRY(pcm_readi, xferi, SNDRV_PCM_IOCTL_READI_FRAMES);
396 DEFINE_ALSA_IOCTL_ENTRY(pcm_writei, xferi, SNDRV_PCM_IOCTL_WRITEI_FRAMES);
397 DEFINE_ALSA_IOCTL_ENTRY(pcm_readn, xfern, SNDRV_PCM_IOCTL_READN_FRAMES);
398 DEFINE_ALSA_IOCTL_ENTRY(pcm_writen, xfern, SNDRV_PCM_IOCTL_WRITEN_FRAMES);
403 #define AP(x) snd_ioctl32_##x
406 SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32),
407 SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32),
408 SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32),
409 SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32),
410 SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
411 SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32),
412 SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
413 SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32),
414 SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
415 SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
416 SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
417 SNDRV_PCM_IOCTL_HW_REFINE_OLD32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old32),
418 SNDRV_PCM_IOCTL_HW_PARAMS_OLD32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old32),
422 struct ioctl32_mapper pcm_mappers[] = {
423 MAP_COMPAT(SNDRV_PCM_IOCTL_PVERSION),
424 MAP_COMPAT(SNDRV_PCM_IOCTL_INFO),
425 MAP_COMPAT(SNDRV_PCM_IOCTL_TSTAMP),
426 { SNDRV_PCM_IOCTL_HW_REFINE32, AP(pcm_hw_refine) },
427 { SNDRV_PCM_IOCTL_HW_PARAMS32, AP(pcm_hw_params) },
428 { SNDRV_PCM_IOCTL_HW_REFINE_OLD32, AP(pcm_hw_refine_old) },
429 { SNDRV_PCM_IOCTL_HW_PARAMS_OLD32, AP(pcm_hw_params_old) },
430 MAP_COMPAT(SNDRV_PCM_IOCTL_HW_FREE),
431 { SNDRV_PCM_IOCTL_SW_PARAMS32, AP(pcm_sw_params) },
432 { SNDRV_PCM_IOCTL_STATUS32, AP(pcm_status) },
433 { SNDRV_PCM_IOCTL_DELAY32, AP(pcm_delay) },
434 { SNDRV_PCM_IOCTL_CHANNEL_INFO32, AP(pcm_channel_info) },
435 MAP_COMPAT(SNDRV_PCM_IOCTL_PREPARE),
436 MAP_COMPAT(SNDRV_PCM_IOCTL_RESET),
437 MAP_COMPAT(SNDRV_PCM_IOCTL_START),
438 MAP_COMPAT(SNDRV_PCM_IOCTL_DROP),
439 MAP_COMPAT(SNDRV_PCM_IOCTL_DRAIN),
440 MAP_COMPAT(SNDRV_PCM_IOCTL_PAUSE),
441 { SNDRV_PCM_IOCTL_REWIND32, AP(pcm_rewind) },
442 MAP_COMPAT(SNDRV_PCM_IOCTL_RESUME),
443 MAP_COMPAT(SNDRV_PCM_IOCTL_XRUN),
444 { SNDRV_PCM_IOCTL_WRITEI_FRAMES32, AP(pcm_writei) },
445 { SNDRV_PCM_IOCTL_READI_FRAMES32, AP(pcm_readi) },
446 { SNDRV_PCM_IOCTL_WRITEN_FRAMES32, AP(pcm_writen) },
447 { SNDRV_PCM_IOCTL_READN_FRAMES32, AP(pcm_readn) },
448 MAP_COMPAT(SNDRV_PCM_IOCTL_LINK),
449 MAP_COMPAT(SNDRV_PCM_IOCTL_UNLINK),