ARM: provide arm_has_idmap_alias() helper
[cascardo/linux.git] / sound / usb / media.c
1 /*
2  * media.c - Media Controller specific ALSA driver code
3  *
4  * Copyright (c) 2016 Shuah Khan <shuahkh@osg.samsung.com>
5  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
6  *
7  * This file is released under the GPLv2.
8  */
9
10 /*
11  * This file adds Media Controller support to ALSA driver
12  * to use the Media Controller API to share tuner with DVB
13  * and V4L2 drivers that control media device. Media device
14  * is created based on existing quirks framework. Using this
15  * approach, the media controller API usage can be added for
16  * a specific device.
17 */
18
19 #include <linux/init.h>
20 #include <linux/list.h>
21 #include <linux/mutex.h>
22 #include <linux/slab.h>
23 #include <linux/usb.h>
24
25 #include <sound/pcm.h>
26 #include <sound/core.h>
27
28 #include "usbaudio.h"
29 #include "card.h"
30 #include "mixer.h"
31 #include "media.h"
32
33 static int media_snd_enable_source(struct media_ctl *mctl)
34 {
35         if (mctl && mctl->media_dev->enable_source)
36                 return mctl->media_dev->enable_source(&mctl->media_entity,
37                                                       &mctl->media_pipe);
38         return 0;
39 }
40
41 static void media_snd_disable_source(struct media_ctl *mctl)
42 {
43         if (mctl && mctl->media_dev->disable_source)
44                 mctl->media_dev->disable_source(&mctl->media_entity);
45 }
46
47 int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
48                         int stream)
49 {
50         struct media_device *mdev;
51         struct media_ctl *mctl;
52         struct device *pcm_dev = &pcm->streams[stream].dev;
53         u32 intf_type;
54         int ret = 0;
55         u16 mixer_pad;
56         struct media_entity *entity;
57
58         mdev = subs->stream->chip->media_dev;
59         if (!mdev)
60                 return -ENODEV;
61
62         if (subs->media_ctl)
63                 return 0;
64
65         /* allocate media_ctl */
66         mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
67         if (!mctl)
68                 return -ENOMEM;
69
70         mctl->media_dev = mdev;
71         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
72                 intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK;
73                 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK;
74                 mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE;
75                 mixer_pad = 1;
76         } else {
77                 intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE;
78                 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE;
79                 mctl->media_pad.flags = MEDIA_PAD_FL_SINK;
80                 mixer_pad = 2;
81         }
82         mctl->media_entity.name = pcm->name;
83         media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad);
84         ret =  media_device_register_entity(mctl->media_dev,
85                                             &mctl->media_entity);
86         if (ret)
87                 goto free_mctl;
88
89         mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0,
90                                                   MAJOR(pcm_dev->devt),
91                                                   MINOR(pcm_dev->devt));
92         if (!mctl->intf_devnode) {
93                 ret = -ENOMEM;
94                 goto unregister_entity;
95         }
96         mctl->intf_link = media_create_intf_link(&mctl->media_entity,
97                                                  &mctl->intf_devnode->intf,
98                                                  MEDIA_LNK_FL_ENABLED);
99         if (!mctl->intf_link) {
100                 ret = -ENOMEM;
101                 goto devnode_remove;
102         }
103
104         /* create link between mixer and audio */
105         media_device_for_each_entity(entity, mdev) {
106                 switch (entity->function) {
107                 case MEDIA_ENT_F_AUDIO_MIXER:
108                         ret = media_create_pad_link(entity, mixer_pad,
109                                                     &mctl->media_entity, 0,
110                                                     MEDIA_LNK_FL_ENABLED);
111                         if (ret)
112                                 goto remove_intf_link;
113                         break;
114                 }
115         }
116
117         subs->media_ctl = mctl;
118         return 0;
119
120 remove_intf_link:
121         media_remove_intf_link(mctl->intf_link);
122 devnode_remove:
123         media_devnode_remove(mctl->intf_devnode);
124 unregister_entity:
125         media_device_unregister_entity(&mctl->media_entity);
126 free_mctl:
127         kfree(mctl);
128         return ret;
129 }
130
131 void media_snd_stream_delete(struct snd_usb_substream *subs)
132 {
133         struct media_ctl *mctl = subs->media_ctl;
134
135         if (mctl && mctl->media_dev) {
136                 struct media_device *mdev;
137
138                 mdev = subs->stream->chip->media_dev;
139                 if (mdev && media_devnode_is_registered(&mdev->devnode)) {
140                         media_devnode_remove(mctl->intf_devnode);
141                         media_device_unregister_entity(&mctl->media_entity);
142                         media_entity_cleanup(&mctl->media_entity);
143                 }
144                 kfree(mctl);
145                 subs->media_ctl = NULL;
146         }
147 }
148
149 int media_snd_start_pipeline(struct snd_usb_substream *subs)
150 {
151         struct media_ctl *mctl = subs->media_ctl;
152
153         if (mctl)
154                 return media_snd_enable_source(mctl);
155         return 0;
156 }
157
158 void media_snd_stop_pipeline(struct snd_usb_substream *subs)
159 {
160         struct media_ctl *mctl = subs->media_ctl;
161
162         if (mctl)
163                 media_snd_disable_source(mctl);
164 }
165
166 int media_snd_mixer_init(struct snd_usb_audio *chip)
167 {
168         struct device *ctl_dev = &chip->card->ctl_dev;
169         struct media_intf_devnode *ctl_intf;
170         struct usb_mixer_interface *mixer;
171         struct media_device *mdev = chip->media_dev;
172         struct media_mixer_ctl *mctl;
173         u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL;
174         int ret;
175
176         if (!mdev)
177                 return -ENODEV;
178
179         ctl_intf = chip->ctl_intf_media_devnode;
180         if (!ctl_intf) {
181                 ctl_intf = media_devnode_create(mdev, intf_type, 0,
182                                                 MAJOR(ctl_dev->devt),
183                                                 MINOR(ctl_dev->devt));
184                 if (!ctl_intf)
185                         return -ENOMEM;
186                 chip->ctl_intf_media_devnode = ctl_intf;
187         }
188
189         list_for_each_entry(mixer, &chip->mixer_list, list) {
190
191                 if (mixer->media_mixer_ctl)
192                         continue;
193
194                 /* allocate media_mixer_ctl */
195                 mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
196                 if (!mctl)
197                         return -ENOMEM;
198
199                 mctl->media_dev = mdev;
200                 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER;
201                 mctl->media_entity.name = chip->card->mixername;
202                 mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK;
203                 mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE;
204                 mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE;
205                 media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX,
206                                   mctl->media_pad);
207                 ret =  media_device_register_entity(mctl->media_dev,
208                                                     &mctl->media_entity);
209                 if (ret) {
210                         kfree(mctl);
211                         return ret;
212                 }
213
214                 mctl->intf_link = media_create_intf_link(&mctl->media_entity,
215                                                          &ctl_intf->intf,
216                                                          MEDIA_LNK_FL_ENABLED);
217                 if (!mctl->intf_link) {
218                         media_device_unregister_entity(&mctl->media_entity);
219                         media_entity_cleanup(&mctl->media_entity);
220                         kfree(mctl);
221                         return -ENOMEM;
222                 }
223                 mctl->intf_devnode = ctl_intf;
224                 mixer->media_mixer_ctl = mctl;
225         }
226         return 0;
227 }
228
229 static void media_snd_mixer_delete(struct snd_usb_audio *chip)
230 {
231         struct usb_mixer_interface *mixer;
232         struct media_device *mdev = chip->media_dev;
233
234         if (!mdev)
235                 return;
236
237         list_for_each_entry(mixer, &chip->mixer_list, list) {
238                 struct media_mixer_ctl *mctl;
239
240                 mctl = mixer->media_mixer_ctl;
241                 if (!mixer->media_mixer_ctl)
242                         continue;
243
244                 if (media_devnode_is_registered(&mdev->devnode)) {
245                         media_device_unregister_entity(&mctl->media_entity);
246                         media_entity_cleanup(&mctl->media_entity);
247                 }
248                 kfree(mctl);
249                 mixer->media_mixer_ctl = NULL;
250         }
251         if (media_devnode_is_registered(&mdev->devnode))
252                 media_devnode_remove(chip->ctl_intf_media_devnode);
253         chip->ctl_intf_media_devnode = NULL;
254 }
255
256 int media_snd_device_create(struct snd_usb_audio *chip,
257                         struct usb_interface *iface)
258 {
259         struct media_device *mdev;
260         struct usb_device *usbdev = interface_to_usbdev(iface);
261         int ret;
262
263         mdev = media_device_get_devres(&usbdev->dev);
264         if (!mdev)
265                 return -ENOMEM;
266         if (!mdev->dev) {
267                 /* register media device */
268                 mdev->dev = &usbdev->dev;
269                 if (usbdev->product)
270                         strlcpy(mdev->model, usbdev->product,
271                                 sizeof(mdev->model));
272                 if (usbdev->serial)
273                         strlcpy(mdev->serial, usbdev->serial,
274                                 sizeof(mdev->serial));
275                 strcpy(mdev->bus_info, usbdev->devpath);
276                 mdev->hw_revision = le16_to_cpu(usbdev->descriptor.bcdDevice);
277                 media_device_init(mdev);
278         }
279         if (!media_devnode_is_registered(&mdev->devnode)) {
280                 ret = media_device_register(mdev);
281                 if (ret) {
282                         dev_err(&usbdev->dev,
283                                 "Couldn't register media device. Error: %d\n",
284                                 ret);
285                         return ret;
286                 }
287         }
288
289         /* save media device - avoid lookups */
290         chip->media_dev = mdev;
291
292         /* Create media entities for mixer and control dev */
293         ret = media_snd_mixer_init(chip);
294         if (ret) {
295                 dev_err(&usbdev->dev,
296                         "Couldn't create media mixer entities. Error: %d\n",
297                         ret);
298
299                 /* clear saved media_dev */
300                 chip->media_dev = NULL;
301
302                 return ret;
303         }
304         return 0;
305 }
306
307 void media_snd_device_delete(struct snd_usb_audio *chip)
308 {
309         struct media_device *mdev = chip->media_dev;
310
311         media_snd_mixer_delete(chip);
312
313         if (mdev) {
314                 if (media_devnode_is_registered(&mdev->devnode))
315                         media_device_unregister(mdev);
316                 chip->media_dev = NULL;
317         }
318 }