staging: most: fix channel operation in multi-aim context
[firefly-linux-kernel-4.4.55.git] / drivers / staging / most / aim-sound / sound.c
1 /*
2  * sound.c - Audio Application Interface Module for Mostcore
3  *
4  * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * This file is licensed under GPLv2.
12  */
13
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
16 #include <linux/module.h>
17 #include <linux/printk.h>
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <linux/sched.h>
23 #include <linux/kthread.h>
24 #include <mostcore.h>
25
26 #define DRIVER_NAME "sound"
27
28 static struct list_head dev_list;
29 static struct most_aim audio_aim;
30
31 /**
32  * struct channel - private structure to keep channel specific data
33  * @substream: stores the substream structure
34  * @iface: interface for which the channel belongs to
35  * @cfg: channel configuration
36  * @card: registered sound card
37  * @list: list for private use
38  * @id: channel index
39  * @period_pos: current period position (ring buffer)
40  * @buffer_pos: current buffer position (ring buffer)
41  * @is_stream_running: identifies whether a stream is running or not
42  * @opened: set when the stream is opened
43  * @playback_task: playback thread
44  * @playback_waitq: waitq used by playback thread
45  */
46 struct channel {
47         struct snd_pcm_substream *substream;
48         struct most_interface *iface;
49         struct most_channel_config *cfg;
50         struct snd_card *card;
51         struct list_head list;
52         int id;
53         unsigned int period_pos;
54         unsigned int buffer_pos;
55         bool is_stream_running;
56
57         struct task_struct *playback_task;
58         wait_queue_head_t playback_waitq;
59
60         void (*copy_fn)(void *alsa, void *most, unsigned int bytes);
61 };
62
63 #define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
64                        SNDRV_PCM_INFO_MMAP_VALID | \
65                        SNDRV_PCM_INFO_BATCH | \
66                        SNDRV_PCM_INFO_INTERLEAVED | \
67                        SNDRV_PCM_INFO_BLOCK_TRANSFER)
68
69 /**
70  * Initialization of struct snd_pcm_hardware
71  */
72 static struct snd_pcm_hardware pcm_hardware_template = {
73         .info               = MOST_PCM_INFO,
74         .rates              = SNDRV_PCM_RATE_48000,
75         .rate_min           = 48000,
76         .rate_max           = 48000,
77         .channels_min       = 1,
78         .channels_max       = 8,
79 };
80
81 #define swap16(val) ( \
82         (((u16)(val) << 8) & (u16)0xFF00) | \
83         (((u16)(val) >> 8) & (u16)0x00FF))
84
85 #define swap32(val) ( \
86         (((u32)(val) << 24) & (u32)0xFF000000) | \
87         (((u32)(val) <<  8) & (u32)0x00FF0000) | \
88         (((u32)(val) >>  8) & (u32)0x0000FF00) | \
89         (((u32)(val) >> 24) & (u32)0x000000FF))
90
91 static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes)
92 {
93         unsigned int i = 0;
94
95         while (i < (bytes / 2)) {
96                 dest[i] = swap16(source[i]);
97                 i++;
98         }
99 }
100
101 static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes)
102 {
103         unsigned int i = 0;
104
105         while (i < bytes - 2) {
106                 dest[i] = source[i + 2];
107                 dest[i + 1] = source[i + 1];
108                 dest[i + 2] = source[i];
109                 i += 3;
110         }
111 }
112
113 static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes)
114 {
115         unsigned int i = 0;
116
117         while (i < bytes / 4) {
118                 dest[i] = swap32(source[i]);
119                 i++;
120         }
121 }
122
123 static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes)
124 {
125         memcpy(most, alsa, bytes);
126 }
127
128 static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes)
129 {
130         swap_copy16(most, alsa, bytes);
131 }
132
133 static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes)
134 {
135         swap_copy24(most, alsa, bytes);
136 }
137
138 static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes)
139 {
140         swap_copy32(most, alsa, bytes);
141 }
142
143 static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes)
144 {
145         memcpy(alsa, most, bytes);
146 }
147
148 static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes)
149 {
150         swap_copy16(alsa, most, bytes);
151 }
152
153 static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes)
154 {
155         swap_copy24(alsa, most, bytes);
156 }
157
158 static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes)
159 {
160         swap_copy32(alsa, most, bytes);
161 }
162
163 /**
164  * get_channel - get pointer to channel
165  * @iface: interface structure
166  * @channel_id: channel ID
167  *
168  * This traverses the channel list and returns the channel matching the
169  * ID and interface.
170  *
171  * Returns pointer to channel on success or NULL otherwise.
172  */
173 static struct channel *get_channel(struct most_interface *iface,
174                                    int channel_id)
175 {
176         struct channel *channel, *tmp;
177
178         list_for_each_entry_safe(channel, tmp, &dev_list, list) {
179                 if ((channel->iface == iface) && (channel->id == channel_id))
180                         return channel;
181         }
182
183         return NULL;
184 }
185
186 /**
187  * copy_data - implements data copying function
188  * @channel: channel
189  * @mbo: MBO from core
190  *
191  * Copy data from/to ring buffer to/from MBO and update the buffer position
192  */
193 static bool copy_data(struct channel *channel, struct mbo *mbo)
194 {
195         struct snd_pcm_runtime *const runtime = channel->substream->runtime;
196         unsigned int const frame_bytes = channel->cfg->subbuffer_size;
197         unsigned int const buffer_size = runtime->buffer_size;
198         unsigned int frames;
199         unsigned int fr0;
200
201         if (channel->cfg->direction & MOST_CH_RX)
202                 frames = mbo->processed_length / frame_bytes;
203         else
204                 frames = mbo->buffer_length / frame_bytes;
205         fr0 = min(buffer_size - channel->buffer_pos, frames);
206
207         channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes,
208                          mbo->virt_address,
209                          fr0 * frame_bytes);
210
211         if (frames > fr0) {
212                 /* wrap around at end of ring buffer */
213                 channel->copy_fn(runtime->dma_area,
214                                  mbo->virt_address + fr0 * frame_bytes,
215                                  (frames - fr0) * frame_bytes);
216         }
217
218         channel->buffer_pos += frames;
219         if (channel->buffer_pos >= buffer_size)
220                 channel->buffer_pos -= buffer_size;
221         channel->period_pos += frames;
222         if (channel->period_pos >= runtime->period_size) {
223                 channel->period_pos -= runtime->period_size;
224                 return true;
225         }
226
227         return false;
228 }
229
230 /**
231  * playback_thread - function implements the playback thread
232  * @data: private data
233  *
234  * Thread which does the playback functionality in a loop. It waits for a free
235  * MBO from mostcore for a particular channel and copy the data from ring buffer
236  * to MBO. Submit the MBO back to mostcore, after copying the data.
237  *
238  * Returns 0 on success or error code otherwise.
239  */
240 static int playback_thread(void *data)
241 {
242         struct channel *const channel = data;
243
244         pr_info("playback thread started\n");
245
246         while (!kthread_should_stop()) {
247                 struct mbo *mbo = NULL;
248                 bool period_elapsed = false;
249                 int ret;
250
251                 wait_event_interruptible(
252                         channel->playback_waitq,
253                         kthread_should_stop() ||
254                         (mbo = most_get_mbo(channel->iface, channel->id)));
255
256                 if (!mbo)
257                         continue;
258
259                 if (channel->is_stream_running)
260                         period_elapsed = copy_data(channel, mbo);
261                 else
262                         memset(mbo->virt_address, 0, mbo->buffer_length);
263
264                 ret = most_submit_mbo(mbo);
265                 if (ret)
266                         channel->is_stream_running = false;
267
268                 if (period_elapsed)
269                         snd_pcm_period_elapsed(channel->substream);
270         }
271
272         return 0;
273 }
274
275 /**
276  * pcm_open - implements open callback function for PCM middle layer
277  * @substream: pointer to ALSA PCM substream
278  *
279  * This is called when a PCM substream is opened. At least, the function should
280  * initialize the runtime->hw record.
281  *
282  * Returns 0 on success or error code otherwise.
283  */
284 static int pcm_open(struct snd_pcm_substream *substream)
285 {
286         struct channel *channel = substream->private_data;
287         struct snd_pcm_runtime *runtime = substream->runtime;
288         struct most_channel_config *cfg = channel->cfg;
289
290         pr_info("pcm_open(), %s\n", substream->name);
291
292         channel->substream = substream;
293
294         if (cfg->direction == MOST_CH_TX) {
295                 init_waitqueue_head(&channel->playback_waitq);
296                 channel->playback_task = kthread_run(&playback_thread, channel,
297                                                      "most_audio_playback");
298                 if (IS_ERR(channel->playback_task))
299                         return PTR_ERR(channel->playback_task);
300         }
301
302         if (most_start_channel(channel->iface, channel->id, &audio_aim)) {
303                 pr_err("most_start_channel() failed!\n");
304                 if (cfg->direction == MOST_CH_TX)
305                         kthread_stop(channel->playback_task);
306                 return -EBUSY;
307         }
308
309         runtime->hw = pcm_hardware_template;
310         runtime->hw.buffer_bytes_max = cfg->num_buffers * cfg->buffer_size;
311         runtime->hw.period_bytes_min = cfg->buffer_size;
312         runtime->hw.period_bytes_max = cfg->buffer_size;
313         runtime->hw.periods_min = 1;
314         runtime->hw.periods_max = cfg->num_buffers;
315
316         return 0;
317 }
318
319 /**
320  * pcm_close - implements close callback function for PCM middle layer
321  * @substream: sub-stream pointer
322  *
323  * Obviously, this is called when a PCM substream is closed. Any private
324  * instance for a PCM substream allocated in the open callback will be
325  * released here.
326  *
327  * Returns 0 on success or error code otherwise.
328  */
329 static int pcm_close(struct snd_pcm_substream *substream)
330 {
331         struct channel *channel = substream->private_data;
332
333         pr_info("pcm_close(), %s\n", substream->name);
334
335         if (channel->cfg->direction == MOST_CH_TX)
336                 kthread_stop(channel->playback_task);
337         most_stop_channel(channel->iface, channel->id, &audio_aim);
338
339         return 0;
340 }
341
342 /**
343  * pcm_hw_params - implements hw_params callback function for PCM middle layer
344  * @substream: sub-stream pointer
345  * @hw_params: contains the hardware parameters set by the application
346  *
347  * This is called when the hardware parameters is set by the application, that
348  * is, once when the buffer size, the period size, the format, etc. are defined
349  * for the PCM substream. Many hardware setups should be done is this callback,
350  * including the allocation of buffers.
351  *
352  * Returns 0 on success or error code otherwise.
353  */
354 static int pcm_hw_params(struct snd_pcm_substream *substream,
355                          struct snd_pcm_hw_params *hw_params)
356 {
357         pr_info("pcm_hw_params()\n");
358
359         return snd_pcm_lib_alloc_vmalloc_buffer(substream,
360                                                 params_buffer_bytes(hw_params));
361 }
362
363 /**
364  * pcm_hw_free - implements hw_free callback function for PCM middle layer
365  * @substream: substream pointer
366  *
367  * This is called to release the resources allocated via hw_params.
368  * This function will be always called before the close callback is called.
369  *
370  * Returns 0 on success or error code otherwise.
371  */
372 static int pcm_hw_free(struct snd_pcm_substream *substream)
373 {
374         pr_info("pcm_hw_free()\n");
375
376         return snd_pcm_lib_free_vmalloc_buffer(substream);
377 }
378
379 /**
380  * pcm_prepare - implements prepare callback function for PCM middle layer
381  * @substream: substream pointer
382  *
383  * This callback is called when the PCM is "prepared". Format rate, sample rate,
384  * etc., can be set here. This callback can be called many times at each setup.
385  *
386  * Returns 0 on success or error code otherwise.
387  */
388 static int pcm_prepare(struct snd_pcm_substream *substream)
389 {
390         struct channel *channel = substream->private_data;
391         struct snd_pcm_runtime *runtime = substream->runtime;
392         struct most_channel_config *cfg = channel->cfg;
393         int width = snd_pcm_format_physical_width(runtime->format);
394
395         channel->copy_fn = NULL;
396
397         if (cfg->direction == MOST_CH_TX) {
398                 if (snd_pcm_format_big_endian(runtime->format) || width == 8)
399                         channel->copy_fn = alsa_to_most_memcpy;
400                 else if (width == 16)
401                         channel->copy_fn = alsa_to_most_copy16;
402                 else if (width == 24)
403                         channel->copy_fn = alsa_to_most_copy24;
404                 else if (width == 32)
405                         channel->copy_fn = alsa_to_most_copy32;
406         } else {
407                 if (snd_pcm_format_big_endian(runtime->format) || width == 8)
408                         channel->copy_fn = most_to_alsa_memcpy;
409                 else if (width == 16)
410                         channel->copy_fn = most_to_alsa_copy16;
411                 else if (width == 24)
412                         channel->copy_fn = most_to_alsa_copy24;
413                 else if (width == 32)
414                         channel->copy_fn = most_to_alsa_copy32;
415         }
416
417         if (!channel->copy_fn) {
418                 pr_err("unsupported format\n");
419                 return -EINVAL;
420         }
421
422         channel->period_pos = 0;
423         channel->buffer_pos = 0;
424
425         return 0;
426 }
427
428 /**
429  * pcm_trigger - implements trigger callback function for PCM middle layer
430  * @substream: substream pointer
431  * @cmd: action to perform
432  *
433  * This is called when the PCM is started, stopped or paused. The action will be
434  * specified in the second argument, SNDRV_PCM_TRIGGER_XXX
435  *
436  * Returns 0 on success or error code otherwise.
437  */
438 static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
439 {
440         struct channel *channel = substream->private_data;
441
442         switch (cmd) {
443         case SNDRV_PCM_TRIGGER_START:
444                 channel->is_stream_running = true;
445                 return 0;
446
447         case SNDRV_PCM_TRIGGER_STOP:
448                 channel->is_stream_running = false;
449                 return 0;
450
451         default:
452                 pr_info("pcm_trigger(), invalid\n");
453                 return -EINVAL;
454         }
455         return 0;
456 }
457
458 /**
459  * pcm_pointer - implements pointer callback function for PCM middle layer
460  * @substream: substream pointer
461  *
462  * This callback is called when the PCM middle layer inquires the current
463  * hardware position on the buffer. The position must be returned in frames,
464  * ranging from 0 to buffer_size-1.
465  */
466 static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
467 {
468         struct channel *channel = substream->private_data;
469
470         return channel->buffer_pos;
471 }
472
473 /**
474  * Initialization of struct snd_pcm_ops
475  */
476 static struct snd_pcm_ops pcm_ops = {
477         .open       = pcm_open,
478         .close      = pcm_close,
479         .ioctl      = snd_pcm_lib_ioctl,
480         .hw_params  = pcm_hw_params,
481         .hw_free    = pcm_hw_free,
482         .prepare    = pcm_prepare,
483         .trigger    = pcm_trigger,
484         .pointer    = pcm_pointer,
485         .page       = snd_pcm_lib_get_vmalloc_page,
486         .mmap       = snd_pcm_lib_mmap_vmalloc,
487 };
488
489
490 static int split_arg_list(char *buf, char **card_name, char **pcm_format)
491 {
492         *card_name = strsep(&buf, ".");
493         if (!*card_name)
494                 return -EIO;
495         *pcm_format = strsep(&buf, ".\n");
496         if (!*pcm_format)
497                 return -EIO;
498         return 0;
499 }
500
501 static int audio_set_pcm_format(char *pcm_format,
502                                 struct most_channel_config *cfg)
503 {
504         if (!strcmp(pcm_format, "1x8")) {
505                 if (cfg->subbuffer_size != 1)
506                         goto error;
507                 pr_info("PCM format is 8-bit mono\n");
508                 pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S8;
509         } else if (!strcmp(pcm_format, "2x16")) {
510                 if (cfg->subbuffer_size != 4)
511                         goto error;
512                 pr_info("PCM format is 16-bit stereo\n");
513                 pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S16_LE |
514                                                 SNDRV_PCM_FMTBIT_S16_BE;
515         } else if (!strcmp(pcm_format, "2x24")) {
516                 if (cfg->subbuffer_size != 6)
517                         goto error;
518                 pr_info("PCM format is 24-bit stereo\n");
519                 pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S24_3LE |
520                                                 SNDRV_PCM_FMTBIT_S24_3BE;
521         } else if (!strcmp(pcm_format, "2x32")) {
522                 if (cfg->subbuffer_size != 8)
523                         goto error;
524                 pr_info("PCM format is 32-bit stereo\n");
525                 pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S32_LE |
526                                                 SNDRV_PCM_FMTBIT_S32_BE;
527         } else {
528                 pr_err("PCM format %s not supported\n", pcm_format);
529                 return -EIO;
530         }
531         return 0;
532 error:
533         pr_err("Audio resolution doesn't fit subbuffer size\n");
534         return -EINVAL;
535 }
536
537 /**
538  * audio_probe_channel - probe function of the driver module
539  * @iface: pointer to interface instance
540  * @channel_id: channel index/ID
541  * @cfg: pointer to actual channel configuration
542  * @parent: pointer to kobject (needed for sysfs hook-up)
543  * @arg_list: string that provides the name of the device to be created in /dev
544  *            plus the desired audio resolution
545  *
546  * Creates sound card, pcm device, sets pcm ops and registers sound card.
547  *
548  * Returns 0 on success or error code otherwise.
549  */
550 static int audio_probe_channel(struct most_interface *iface, int channel_id,
551                                struct most_channel_config *cfg,
552                                struct kobject *parent, char *arg_list)
553 {
554         struct channel *channel;
555         struct snd_card *card;
556         struct snd_pcm *pcm;
557         int playback_count = 0;
558         int capture_count = 0;
559         int ret;
560         int direction;
561         char *card_name;
562         char *pcm_format;
563
564         pr_info("sound_probe_channel()\n");
565
566         if (!iface)
567                 return -EINVAL;
568
569         if (cfg->data_type != MOST_CH_SYNC) {
570                 pr_err("Incompatible channel type\n");
571                 return -EINVAL;
572         }
573
574         if (get_channel(iface, channel_id)) {
575                 pr_err("channel (%s:%d) is already linked\n",
576                        iface->description, channel_id);
577                 return -EINVAL;
578         }
579
580         if (cfg->direction == MOST_CH_TX) {
581                 playback_count = 1;
582                 direction = SNDRV_PCM_STREAM_PLAYBACK;
583         } else {
584                 capture_count = 1;
585                 direction = SNDRV_PCM_STREAM_CAPTURE;
586         }
587
588         ret = split_arg_list(arg_list, &card_name, &pcm_format);
589         if (ret < 0) {
590                 pr_info("PCM format missing\n");
591                 return ret;
592         }
593         if (audio_set_pcm_format(pcm_format, cfg))
594                 return ret;
595
596         ret = snd_card_new(NULL, -1, card_name, THIS_MODULE,
597                            sizeof(*channel), &card);
598         if (ret < 0)
599                 return ret;
600
601         channel = card->private_data;
602         channel->card = card;
603         channel->cfg = cfg;
604         channel->iface = iface;
605         channel->id = channel_id;
606
607         snprintf(card->driver, sizeof(card->driver), "%s", DRIVER_NAME);
608         snprintf(card->shortname, sizeof(card->shortname), "MOST:%d",
609                  card->number);
610         snprintf(card->longname, sizeof(card->longname), "%s at %s, ch %d",
611                  card->shortname, iface->description, channel_id);
612
613         ret = snd_pcm_new(card, card_name, 0, playback_count,
614                           capture_count, &pcm);
615         if (ret < 0)
616                 goto err_free_card;
617
618         pcm->private_data = channel;
619
620         snd_pcm_set_ops(pcm, direction, &pcm_ops);
621
622         ret = snd_card_register(card);
623         if (ret < 0)
624                 goto err_free_card;
625
626         list_add_tail(&channel->list, &dev_list);
627
628         return 0;
629
630 err_free_card:
631         snd_card_free(card);
632         return ret;
633 }
634
635 /**
636  * audio_disconnect_channel - function to disconnect a channel
637  * @iface: pointer to interface instance
638  * @channel_id: channel index
639  *
640  * This frees allocated memory and removes the sound card from ALSA
641  *
642  * Returns 0 on success or error code otherwise.
643  */
644 static int audio_disconnect_channel(struct most_interface *iface,
645                                     int channel_id)
646 {
647         struct channel *channel;
648
649         pr_info("sound_disconnect_channel()\n");
650
651         channel = get_channel(iface, channel_id);
652         if (!channel) {
653                 pr_err("sound_disconnect_channel(), invalid channel %d\n",
654                        channel_id);
655                 return -EINVAL;
656         }
657
658         list_del(&channel->list);
659         snd_card_free(channel->card);
660
661         return 0;
662 }
663
664 /**
665  * audio_rx_completion - completion handler for rx channels
666  * @mbo: pointer to buffer object that has completed
667  *
668  * This searches for the channel this MBO belongs to and copy the data from MBO
669  * to ring buffer
670  *
671  * Returns 0 on success or error code otherwise.
672  */
673 static int audio_rx_completion(struct mbo *mbo)
674 {
675         struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id);
676         bool period_elapsed = false;
677
678         if (!channel) {
679                 pr_err("sound_rx_completion(), invalid channel %d\n",
680                        mbo->hdm_channel_id);
681                 return -EINVAL;
682         }
683
684         if (channel->is_stream_running)
685                 period_elapsed = copy_data(channel, mbo);
686
687         most_put_mbo(mbo);
688
689         if (period_elapsed)
690                 snd_pcm_period_elapsed(channel->substream);
691
692         return 0;
693 }
694
695 /**
696  * audio_tx_completion - completion handler for tx channels
697  * @iface: pointer to interface instance
698  * @channel_id: channel index/ID
699  *
700  * This searches the channel that belongs to this combination of interface
701  * pointer and channel ID and wakes a process sitting in the wait queue of
702  * this channel.
703  *
704  * Returns 0 on success or error code otherwise.
705  */
706 static int audio_tx_completion(struct most_interface *iface, int channel_id)
707 {
708         struct channel *channel = get_channel(iface, channel_id);
709
710         if (!channel) {
711                 pr_err("sound_tx_completion(), invalid channel %d\n",
712                        channel_id);
713                 return -EINVAL;
714         }
715
716         wake_up_interruptible(&channel->playback_waitq);
717
718         return 0;
719 }
720
721 /**
722  * Initialization of the struct most_aim
723  */
724 static struct most_aim audio_aim = {
725         .name = DRIVER_NAME,
726         .probe_channel = audio_probe_channel,
727         .disconnect_channel = audio_disconnect_channel,
728         .rx_completion = audio_rx_completion,
729         .tx_completion = audio_tx_completion,
730 };
731
732 static int __init audio_init(void)
733 {
734         pr_info("init()\n");
735
736         INIT_LIST_HEAD(&dev_list);
737
738         return most_register_aim(&audio_aim);
739 }
740
741 static void __exit audio_exit(void)
742 {
743         struct channel *channel, *tmp;
744
745         pr_info("exit()\n");
746
747         list_for_each_entry_safe(channel, tmp, &dev_list, list) {
748                 list_del(&channel->list);
749                 snd_card_free(channel->card);
750         }
751
752         most_deregister_aim(&audio_aim);
753 }
754
755 module_init(audio_init);
756 module_exit(audio_exit);
757
758 MODULE_LICENSE("GPL");
759 MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>");
760 MODULE_DESCRIPTION("Audio Application Interface Module for MostCore");