blob: c631cac4c5d2b9367b75d8fa8fb15ad1ef86b54c [file] [log] [blame]
Markus Rechbergera52932b2008-01-05 09:55:47 -03001/*
2 * Empiatech em28x1 audio extension
3 *
4 * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
5 *
6 * This driver is based on my previous au600 usb pstn audio driver
7 * and inherits all the copyrights
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 as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/kernel.h>
25#include <linux/usb.h>
26#include <linux/init.h>
27#include <linux/sound.h>
28#include <linux/spinlock.h>
29#include <linux/soundcard.h>
30#include <linux/slab.h>
31#include <linux/vmalloc.h>
32#include <linux/proc_fs.h>
33#include <linux/moduleparam.h>
34#include <sound/driver.h>
35#include <sound/core.h>
36#include <sound/pcm.h>
37#include <sound/pcm_params.h>
38#include <sound/info.h>
39#include <sound/initval.h>
40#include <sound/control.h>
41//#include <linux/video_decoder.h>
42//#include <media/tuner.h>
43#include <media/v4l2-common.h>
44#include "em28xx.h"
45
46static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030047static int em28xx_cmd(struct em28xx *dev, int cmd, int arg);
Markus Rechbergera52932b2008-01-05 09:55:47 -030048
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030049static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
50 size_t size)
Markus Rechbergera52932b2008-01-05 09:55:47 -030051{
52 struct snd_pcm_runtime *runtime = subs->runtime;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030053 if (runtime->dma_area) {
54 if (runtime->dma_bytes > size)
Markus Rechbergera52932b2008-01-05 09:55:47 -030055 return 0;
56 vfree(runtime->dma_area);
57 }
58 runtime->dma_area = vmalloc(size);
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030059 if (!runtime->dma_area)
Markus Rechbergera52932b2008-01-05 09:55:47 -030060 return -ENOMEM;
61 runtime->dma_bytes = size;
62 return 0;
63}
64
65static struct snd_pcm_hardware snd_em28xx_hw_capture = {
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030066 .info =
67 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
68 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID,
Markus Rechbergera52932b2008-01-05 09:55:47 -030069 .formats = SNDRV_PCM_FMTBIT_S16_LE,
70 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
71 .rate_min = 48000,
72 .rate_max = 48000,
73 .channels_min = 2,
74 .channels_max = 2,
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030075 .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
76 .period_bytes_min = 64, //12544/2,
Markus Rechbergera52932b2008-01-05 09:55:47 -030077 .period_bytes_max = 12544,
78 .periods_min = 2,
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030079 .periods_max = 98, //12544,
Markus Rechbergera52932b2008-01-05 09:55:47 -030080};
81
82static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
83{
84 int ret = 0;
85 int mode;
86 struct em28xx *dev = snd_pcm_substream_chip(substream);
87 struct snd_pcm_runtime *runtime = substream->runtime;
88 printk("opening radio device and trying to acquire exclusive lock\n");
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -030089 switch (dev->mode) {
90 case TUNER_STUB_DVBC_TV:
91 case TUNER_STUB_DVBT_TV:
92 case TUNER_STUB_ATSC_TV:
93 /* digital has no support for analog audio */
94 if (ret != 0) {
95 printk("device is already in use by DVB-T\n");
96 return -EINVAL;
97 } else {
98 struct v4l2_tuner tuner;
99 printk("switching device to FM mode\n");
Markus Rechbergera52932b2008-01-05 09:55:47 -0300100
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300101 mode = TUNER_STUB_RADIO;
102 memset(&tuner, 0x0, sizeof(struct v4l2_tuner));
103 tuner.type = V4L2_TUNER_RADIO;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300104
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300105 /* enable GPIO for analog TV */
106 dev->em28xx_gpio_control(dev, EM28XX_MODE,
107 (void *)mode);
108 dev->mode = mode;
109 /* upload firmware */
110 tuner_run_cmd(dev->tobj, TUNER_CMD_INIT, (void *)mode);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300111
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300112 /* required for devices which have kerneldriver dependencies */
113// em28xx_config(dev);
114// em28xx_config_i2c(dev);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300115
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300116 /* this is moreover to switch the decoder to FM */
117 em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, &tuner);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300118
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300119 dev->em28xx_write_regs(dev, 0x0f, "\x87", 1);
120 ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1);
121 em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0);
122 /* TODO switch to FM mode */
Markus Rechbergera52932b2008-01-05 09:55:47 -0300123
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300124 printk("em28xx-audio: %d mode\n", mode);
125 tuner_run_cmd(dev->tobj, TUNER_CMD_G_MODE, &mode);
126 printk("retrieved mode from tuner: %d\n", mode);
127 }
128 break;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300129
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300130 case TUNER_STUB_ANALOG_TV:
131 printk("em28xx-audio: device is currently in analog TV mode\n");
132 /* unmute by default */
133 dev->em28xx_write_regs(dev, 0x0f, "\x87", 1);
134 break;
135 case TUNER_STUB_RADIO:
136 /* check current mode and put a hard lock onto it */
137 printk
138 ("em28xx-audio: device is currently in analogue FM mode\n");
139 /* unmute by default here */
140 dev->em28xx_write_regs(dev, 0x0f, "\x87", 1);
141 ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1);
142 if (ret == 0)
143 printk("device is locked in fmradio mode now\n");
144 break;
145 default:
146 printk("em28xx-audio: unhandled mode %d\n", dev->mode);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300147 }
148
149 runtime->hw = snd_em28xx_hw_capture;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300150 if (dev->alt == 0 && dev->adev->users == 0) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300151 int errCode;
152 dev->alt = 7;
153 errCode = usb_set_interface(dev->udev, 0, 7);
154 printk("changing alternate number to 7\n");
155 }
156 dev->adev->users++;
157 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
158 dev->adev->capture_pcm_substream = substream;
159 runtime->private_data = dev;
160 return 0;
161}
162
163static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
164{
165 struct em28xx *dev = snd_pcm_substream_chip(substream);
166 int amode = 0;
167 dev->adev->users--;
168
169 /* decrease audio reference */
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300170 switch (dev->mode) {
171 case TUNER_STUB_ANALOG_TV:
172 amode = EM28XX_VIDEO;
173 break;
174 case TUNER_STUB_RADIO:
175 amode = EM28XX_RADIO;
176 break;
177 default:
178 printk("invalid mode: %d\n", dev->mode);
179 break;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300180 }
181
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300182 dev->em28xx_acquire(dev, amode, 0);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300183
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300184 if (dev->adev->users == 0 && dev->adev->shutdown == 1) {
185 printk("audio users: %d\n", dev->adev->users);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300186 printk("disabling audio stream!\n");
187 dev->adev->shutdown = 0;
188 printk("released lock\n");
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300189 em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300190 }
191 return 0;
192}
193
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300194static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
195 struct snd_pcm_hw_params *hw_params)
Markus Rechbergera52932b2008-01-05 09:55:47 -0300196{
197 unsigned int channels, rate, format;
198 int ret;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300199 ret =
200 snd_pcm_alloc_vmalloc_buffer(substream,
201 params_buffer_bytes(hw_params));
Markus Rechbergera52932b2008-01-05 09:55:47 -0300202 format = params_format(hw_params);
203 rate = params_rate(hw_params);
204 channels = params_channels(hw_params);
205 /* TODO: set up em28xx audio chip to deliver the correct audio format, current default is 48000hz multiplexed => 96000hz mono
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300206 which shouldn't matter since analogue TV only supports mono */
Markus Rechbergera52932b2008-01-05 09:55:47 -0300207 return 0;
208}
209
210static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
211{
212 struct em28xx *dev = snd_pcm_substream_chip(substream);
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300213 if (dev->adev->capture_stream == STREAM_ON) {
214 em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300215 }
216 return 0;
217}
218
219static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
220{
221 return 0;
222}
223
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300224static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
225 int cmd)
Markus Rechbergera52932b2008-01-05 09:55:47 -0300226{
227 struct em28xx *dev = snd_pcm_substream_chip(substream);
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300228 switch (cmd) {
229 case SNDRV_PCM_TRIGGER_START:
230 em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
231 return 0;
232 case SNDRV_PCM_TRIGGER_STOP:
233 dev->adev->shutdown = 1;
234 return 0;
235 default:
236 return -EINVAL;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300237 }
238}
239
240static void em28xx_audio_isocirq(struct urb *urb)
241{
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300242 struct em28xx *dev = urb->context;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300243 int i;
244 unsigned int oldptr;
245 unsigned long flags;
246 int period_elapsed = 0;
247 int status;
248 unsigned char *cp;
249 unsigned int stride;
250 struct snd_pcm_substream *substream;
251 struct snd_pcm_runtime *runtime;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300252 if (dev->adev->capture_pcm_substream) {
253 substream = dev->adev->capture_pcm_substream;
254 runtime = substream->runtime;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300255
256 stride = runtime->frame_bits >> 3;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300257 for (i = 0; i < urb->number_of_packets; i++) {
258 int length =
259 urb->iso_frame_desc[i].actual_length / stride;
260 cp = (unsigned char *)urb->transfer_buffer +
261 urb->iso_frame_desc[i].offset;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300262
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300263 if (!length)
Markus Rechbergera52932b2008-01-05 09:55:47 -0300264 continue;
265
266 spin_lock_irqsave(&dev->adev->slock, flags);
267 oldptr = dev->adev->hwptr_done_capture;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300268 dev->adev->hwptr_done_capture += length;
269 if (dev->adev->hwptr_done_capture >=
270 runtime->buffer_size)
271 dev->adev->hwptr_done_capture -=
272 runtime->buffer_size;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300273
274 dev->adev->capture_transfer_done += length;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300275 if (dev->adev->capture_transfer_done >=
276 runtime->period_size) {
277 dev->adev->capture_transfer_done -=
278 runtime->period_size;
279 period_elapsed = 1;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300280 }
281 spin_unlock_irqrestore(&dev->adev->slock, flags);
282
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300283 if (oldptr + length >= runtime->buffer_size) {
284 unsigned int cnt =
285 runtime->buffer_size - oldptr - 1;
286 memcpy(runtime->dma_area + oldptr * stride, cp,
287 cnt * stride);
288 memcpy(runtime->dma_area, cp + cnt,
289 length * stride - cnt * stride);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300290 } else {
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300291 memcpy(runtime->dma_area + oldptr * stride, cp,
292 length * stride);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300293 }
294 }
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300295 if (period_elapsed) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300296 snd_pcm_period_elapsed(substream);
297 }
298 }
299 urb->status = 0;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300300
301 if (dev->adev->shutdown)
Markus Rechbergera52932b2008-01-05 09:55:47 -0300302 return;
303
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300304 if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
305 em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
306 status);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300307 }
308 return;
309}
310
311static int em28xx_isoc_audio_deinit(struct em28xx *dev)
312{
313 int i;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300314 for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300315 usb_kill_urb(dev->adev->urb[i]);
316 usb_free_urb(dev->adev->urb[i]);
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300317 dev->adev->urb[i] = NULL;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300318 }
319 return 0;
320}
321
322static int em28xx_init_audio_isoc(struct em28xx *dev)
323{
324 int i;
325 int errCode;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300326 const int sb_size =
327 EM28XX_NUM_AUDIO_PACKETS * EM28XX_AUDIO_MAX_PACKET_SIZE;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300328
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300329 for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300330 struct urb *urb;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300331 int j, k;
332 dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
333 if (!dev->adev->transfer_buffer[i]) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300334 return -ENOMEM;
335 }
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300336 memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
337 urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
338 if (urb) {
339 urb->dev = dev->udev;
340 urb->context = dev;
341 urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300342 urb->transfer_flags = URB_ISO_ASAP;
343 urb->transfer_buffer = dev->adev->transfer_buffer[i];
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300344 urb->interval = 1;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300345 urb->complete = em28xx_audio_isocirq;
346 urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
347 urb->transfer_buffer_length = sb_size;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300348 for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
349 j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300350 urb->iso_frame_desc[j].offset = k;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300351 urb->iso_frame_desc[j].length =
352 EM28XX_AUDIO_MAX_PACKET_SIZE;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300353 }
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300354 dev->adev->urb[i] = urb;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300355 } else {
356 return -ENOMEM;
357 }
358 }
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300359 for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300360 errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300361 if (errCode) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300362 em28xx_isoc_audio_deinit(dev);
363 return errCode;
364 }
365 }
366 return 0;
367}
368
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300369static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
Markus Rechbergera52932b2008-01-05 09:55:47 -0300370{
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300371 switch (cmd) {
372 case EM28XX_CAPTURE_STREAM_EN:
373 if (dev->adev->capture_stream == STREAM_OFF && arg == 1) {
374 dev->adev->capture_stream = STREAM_ON;
375 em28xx_init_audio_isoc(dev);
376 } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) {
377 dev->adev->capture_stream = STREAM_OFF;
378 em28xx_isoc_audio_deinit(dev);
379 } else {
380 printk
381 ("An underrun occured very likely... ignoring it\n");
382 }
383 return 0;
384 default:
385 return -EINVAL;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300386 }
387}
388
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300389static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
390 *substream)
Markus Rechbergera52932b2008-01-05 09:55:47 -0300391{
392 struct em28xx *dev;
393 snd_pcm_uframes_t hwptr_done;
394 dev = snd_pcm_substream_chip(substream);
395 hwptr_done = dev->adev->hwptr_done_capture;
396 return hwptr_done;
397}
398
399static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
400 unsigned long offset)
401{
402 void *pageptr = subs->runtime->dma_area + offset;
403 return vmalloc_to_page(pageptr);
404}
405
406static struct snd_pcm_ops snd_em28xx_pcm_capture = {
407 .open = snd_em28xx_capture_open,
408 .close = snd_em28xx_pcm_close,
409 .ioctl = snd_pcm_lib_ioctl,
410 .hw_params = snd_em28xx_hw_capture_params,
411 .hw_free = snd_em28xx_hw_capture_free,
412 .prepare = snd_em28xx_prepare,
413 .trigger = snd_em28xx_capture_trigger,
414 .pointer = snd_em28xx_capture_pointer,
415 .page = snd_pcm_get_vmalloc_page,
416};
417
Markus Rechbergera52932b2008-01-05 09:55:47 -0300418static int em28xx_audio_init(struct em28xx *dev)
419{
420 struct em28xx_audio *adev;
421 struct snd_pcm *pcm;
422 struct snd_card *card;
423 static int devnr;
424 int ret;
425 int err;
426 printk("em28xx-audio.c: probing for em28x1 non standard usbaudio\n");
427 printk("em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n");
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300428 adev = kzalloc(sizeof(*adev), GFP_KERNEL);
429 if (!adev) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300430 printk("em28xx-audio.c: out of memory\n");
431 return -1;
432 }
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300433 card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
434 if (card == NULL) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300435 kfree(adev);
436 return -ENOMEM;
437 }
438
439 spin_lock_init(&adev->slock);
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300440 ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
Markus Rechbergera52932b2008-01-05 09:55:47 -0300441 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
442 pcm->info_flags = 0;
443 pcm->private_data = dev;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300444 strcpy(pcm->name, "Empia 28xx Capture");
Markus Rechbergera52932b2008-01-05 09:55:47 -0300445 strcpy(card->driver, "Empia Em28xx Audio");
446 strcpy(card->shortname, "Em28xx Audio");
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300447 strcpy(card->longname, "Empia Em28xx Audio");
Markus Rechbergera52932b2008-01-05 09:55:47 -0300448
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300449 if ((err = snd_card_register(card)) < 0) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300450 snd_card_free(card);
451 return -ENOMEM;
452 }
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300453 adev->sndcard = card;
454 adev->udev = dev->udev;
455 dev->adev = adev;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300456 return 0;
457}
458
459static int em28xx_audio_fini(struct em28xx *dev)
460{
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300461 if (dev == NULL)
Markus Rechbergera52932b2008-01-05 09:55:47 -0300462 return 0;
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300463 if (dev->adev) {
Markus Rechbergera52932b2008-01-05 09:55:47 -0300464 snd_card_free(dev->adev->sndcard);
465 kfree(dev->adev);
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300466 dev->adev = NULL;
Markus Rechbergera52932b2008-01-05 09:55:47 -0300467 }
468 return 0;
469}
470
471static struct em28xx_ops audio_ops = {
Mauro Carvalho Chehab1a6f11e2008-01-05 09:56:24 -0300472 .id = EM28XX_AUDIO,
473 .name = "Em28xx Audio Extension",
474 .init = em28xx_audio_init,
475 .fini = em28xx_audio_fini,
Markus Rechbergera52932b2008-01-05 09:55:47 -0300476};
477
478static int __init em28xx_alsa_register(void)
479{
480 request_module("em28xx");
481 request_module("tuner");
482 return em28xx_register_extension(&audio_ops);
483}
484
485static void __exit em28xx_alsa_unregister(void)
486{
487 em28xx_unregister_extension(&audio_ops);
488}
489
490MODULE_LICENSE("GPL");
491MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
492MODULE_DESCRIPTION("Em28xx Audio driver");
493
494module_init(em28xx_alsa_register);
495module_exit(em28xx_alsa_unregister);