sound: soc: rt56xx: Fix compiler warning
[linux-2.6.git] / sound / soc / codecs / rt56xx_ioctl.c
1 /*
2  * rt56xx_ioctl.h  --  RT56XX ALSA SoC audio driver IO control
3  *
4  * Copyright (c) 2011-2013 REALTEK SEMICONDUCTOR CORP. All rights reserved.
5  * Author: Bard Liao <bardliao@realtek.com>
6  *
7  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include <linux/module.h>
15 #include <linux/spi/spi.h>
16 #include <sound/soc.h>
17 #include "rt56xx_ioctl.h"
18
19 static struct rt56xx_ops rt56xx_ioctl_ops;
20
21 #if defined(CONFIG_SND_HWDEP) || defined(CONFIG_SND_HWDEP_MODULE)
22 #define RT_CE_CODEC_HWDEP_NAME "rt56xx hwdep "
23 static int rt56xx_hwdep_open(struct snd_hwdep *hw, struct file *file)
24 {
25         struct snd_soc_codec *codec = hw->private_data;
26         dev_dbg(codec->dev, "%s()\n", __func__);
27         return 0;
28 }
29
30 static int rt56xx_hwdep_release(struct snd_hwdep *hw, struct file *file)
31 {
32         struct snd_soc_codec *codec = hw->private_data;
33         dev_dbg(codec->dev, "%s()\n", __func__);
34         return 0;
35 }
36
37 static int rt56xx_hwdep_ioctl_common(struct snd_hwdep *hw,
38                 struct file *file, unsigned int cmd, unsigned long arg)
39 {
40         struct snd_soc_codec *codec = hw->private_data;
41         struct rt56xx_cmd __user *_rt56xx = (struct rt56xx_cmd *)arg;
42         struct rt56xx_cmd rt56xx;
43         int *buf, *p;
44
45         if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx))) {
46                 dev_err(codec->dev, "copy_from_user faild\n");
47                 return -EFAULT;
48         }
49         dev_dbg(codec->dev, "%s(): rt56xx.number=%d, cmd=%d\n",
50                         __func__, rt56xx.number, cmd);
51         buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL);
52         if (buf == NULL)
53                 return -ENOMEM;
54         if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number))
55                 goto err;
56
57         switch (cmd) {
58         case RT_READ_CODEC_REG_IOCTL:
59                 for (p = buf; p < buf + rt56xx.number / 2; p++)
60                         *(p + rt56xx.number / 2) = snd_soc_read(codec, *p);
61
62                 if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
63                         goto err;
64                 break;
65         case RT_WRITE_CODEC_REG_IOCTL:
66                 for (p = buf; p < buf + rt56xx.number / 2; p++)
67                         snd_soc_write(codec, *p, *(p + rt56xx.number / 2));
68                 break;
69         case RT_READ_CODEC_INDEX_IOCTL:
70                 if (NULL == rt56xx_ioctl_ops.index_read)
71                         goto err;
72
73                 for (p = buf; p < buf + rt56xx.number / 2; p++)
74                         *(p+rt56xx.number/2) = rt56xx_ioctl_ops.index_read(
75                                                         codec, *p);
76                 if (copy_to_user(rt56xx.buf, buf,
77                         sizeof(*buf) * rt56xx.number))
78                         goto err;
79                 break;
80         case RT_WRITE_CODEC_INDEX_IOCTL:
81                 if (NULL == rt56xx_ioctl_ops.index_write)
82                         goto err;
83
84                 for (p = buf; p < buf + rt56xx.number / 2; p++)
85                         rt56xx_ioctl_ops.index_write(codec, *p,
86                                 *(p+rt56xx.number/2));
87                 break;
88         default:
89                 if (NULL == rt56xx_ioctl_ops.ioctl_common)
90                         goto err;
91
92                 rt56xx_ioctl_ops.ioctl_common(hw, file, cmd, arg);
93                 break;
94         }
95
96         kfree(buf);
97         return 0;
98
99 err:
100         kfree(buf);
101         return -EFAULT;
102 }
103
104 static int rt56xx_codec_dump_reg(struct snd_hwdep *hw,
105                 struct file *file, unsigned long arg)
106 {
107         struct snd_soc_codec *codec = hw->private_data;
108         struct rt56xx_cmd __user *_rt56xx = (struct rt56xx_cmd *)arg;
109         struct rt56xx_cmd rt56xx;
110         int i, *buf, number = codec->driver->reg_cache_size;
111
112         dev_dbg(codec->dev, "enter %s, number = %d\n", __func__, number);
113         if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))
114                 return -EFAULT;
115
116         buf = kmalloc(sizeof(*buf) * number, GFP_KERNEL);
117         if (buf == NULL)
118                 return -ENOMEM;
119
120         for (i = 0; i < number/2; i++) {
121                 buf[i] = i << 1;
122                 buf[i + number / 2] = codec->read(codec, buf[i]);
123         }
124         if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * i))
125                 goto err;
126         rt56xx.number = number;
127         if (copy_to_user(_rt56xx, &rt56xx, sizeof(rt56xx)))
128                 goto err;
129         kfree(buf);
130         return 0;
131
132 err:
133         kfree(buf);
134         return -EFAULT;
135 }
136
137 static int rt56xx_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
138                         unsigned int cmd, unsigned long arg)
139 {
140         switch (cmd) {
141         case RT_READ_ALL_CODEC_REG_IOCTL:
142                 return rt56xx_codec_dump_reg(hw, file, arg);
143
144         default:
145                 return rt56xx_hwdep_ioctl_common(hw, file, cmd, arg);
146         }
147
148         return 0;
149 }
150
151 int realtek_ce_init_hwdep(struct snd_soc_codec *codec)
152 {
153         struct snd_hwdep *hw;
154         struct snd_card *card = codec->card->snd_card;
155         int err;
156
157         dev_dbg(codec->dev, "enter %s\n", __func__);
158
159         err = snd_hwdep_new(card, RT_CE_CODEC_HWDEP_NAME, 0, &hw);
160         if (err < 0)
161                 return err;
162
163         strcpy(hw->name, RT_CE_CODEC_HWDEP_NAME);
164         hw->private_data = codec;
165         hw->ops.open = rt56xx_hwdep_open;
166         hw->ops.release = rt56xx_hwdep_release;
167         hw->ops.ioctl = rt56xx_hwdep_ioctl;
168
169         return 0;
170 }
171 EXPORT_SYMBOL_GPL(realtek_ce_init_hwdep);
172 #endif
173
174 struct rt56xx_ops *rt56xx_get_ioctl_ops(void)
175 {
176         return &rt56xx_ioctl_ops;
177 }
178 EXPORT_SYMBOL_GPL(rt56xx_get_ioctl_ops);