blob: a5632c7e6438226d4a0bfdf2a3ddd6b43184fda4 [file] [log] [blame]
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001/*
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -03002 em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
3 video capture devices
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08004
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08005 Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
6 Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab2e7c6dc2006-04-03 07:53:40 -03007 Mauro Carvalho Chehab <mchehab@infradead.org>
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08008 Sascha Sommer <saschasommer@freenet.de>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08009
Mauro Carvalho Chehab439090d2006-01-23 17:10:54 -020010 Some parts based on SN9C10x PC Camera Controllers GPL driver made
11 by Luca Risolia <luca.risolia@studio.unibo.it>
12
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080013 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/init.h>
29#include <linux/list.h>
30#include <linux/module.h>
31#include <linux/kernel.h>
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020032#include <linux/bitmap.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080033#include <linux/usb.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080034#include <linux/i2c.h>
Mauro Carvalho Chehabb296fc62005-11-08 21:38:37 -080035#include <linux/version.h>
Trent Piepho6d35c8f2007-11-01 01:16:09 -030036#include <linux/mm.h>
Ingo Molnar1e4baed2006-01-15 07:52:23 -020037#include <linux/mutex.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080038
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080039#include "em28xx.h"
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -020040#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030041#include <media/v4l2-ioctl.h>
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -030042#include <media/v4l2-chip-ident.h>
Hans Verkuil2474ed42006-03-19 12:35:57 -030043#include <media/msp3400.h>
Mauro Carvalho Chehabed086312008-01-24 06:59:20 -030044#include <media/tuner.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080045
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080046#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
47 "Markus Rechberger <mrechberger@gmail.com>, " \
Mauro Carvalho Chehab2e7c6dc2006-04-03 07:53:40 -030048 "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080049 "Sascha Sommer <saschasommer@freenet.de>"
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080050
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080051#define DRIVER_DESC "Empia em28xx based USB video device driver"
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -030052#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 2)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080053
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080054#define em28xx_videodbg(fmt, arg...) do {\
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080055 if (video_debug) \
56 printk(KERN_INFO "%s %s :"fmt, \
Harvey Harrisond80e1342008-04-08 23:20:00 -030057 dev->name, __func__ , ##arg); } while (0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080058
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030059static unsigned int isoc_debug;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -030060module_param(isoc_debug, int, 0644);
61MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030062
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -030063#define em28xx_isocdbg(fmt, arg...) \
64do {\
65 if (isoc_debug) { \
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030066 printk(KERN_INFO "%s %s :"fmt, \
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -030067 dev->name, __func__ , ##arg); \
68 } \
69 } while (0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030070
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080071MODULE_AUTHOR(DRIVER_AUTHOR);
72MODULE_DESCRIPTION(DRIVER_DESC);
73MODULE_LICENSE("GPL");
74
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020075static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -030076static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
77static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
78
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020079module_param_array(video_nr, int, NULL, 0444);
80module_param_array(vbi_nr, int, NULL, 0444);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -030081module_param_array(radio_nr, int, NULL, 0444);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -030082MODULE_PARM_DESC(video_nr, "video device numbers");
83MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
84MODULE_PARM_DESC(radio_nr, "radio device numbers");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080085
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030086static unsigned int video_debug;
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -030087module_param(video_debug, int, 0644);
88MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080089
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -030090/* supported video standards */
91static struct em28xx_fmt format[] = {
92 {
Mauro Carvalho Chehab58fc1ce2009-07-03 02:54:18 -030093 .name = "16 bpp YUY2, 4:2:2, packed",
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -030094 .fourcc = V4L2_PIX_FMT_YUYV,
95 .depth = 16,
Devin Heitmueller3fbf9302008-12-29 23:34:37 -030096 .reg = EM28XX_OUTFMT_YUV422_Y0UY1V,
Mauro Carvalho Chehab43cb9fe2009-06-30 08:36:17 -030097 }, {
Mauro Carvalho Chehab58fc1ce2009-07-03 02:54:18 -030098 .name = "16 bpp RGB 565, LE",
Mauro Carvalho Chehab43cb9fe2009-06-30 08:36:17 -030099 .fourcc = V4L2_PIX_FMT_RGB565,
100 .depth = 16,
Mauro Carvalho Chehab58fc1ce2009-07-03 02:54:18 -0300101 .reg = EM28XX_OUTFMT_RGB_16_656,
102 }, {
103 .name = "8 bpp Bayer BGBG..GRGR",
104 .fourcc = V4L2_PIX_FMT_SBGGR8,
105 .depth = 8,
106 .reg = EM28XX_OUTFMT_RGB_8_BGBG,
107 }, {
108 .name = "8 bpp Bayer GRGR..BGBG",
109 .fourcc = V4L2_PIX_FMT_SGRBG8,
110 .depth = 8,
111 .reg = EM28XX_OUTFMT_RGB_8_GRGR,
112 }, {
113 .name = "8 bpp Bayer GBGB..RGRG",
114 .fourcc = V4L2_PIX_FMT_SGBRG8,
115 .depth = 8,
116 .reg = EM28XX_OUTFMT_RGB_8_GBGB,
117 }, {
118 .name = "12 bpp YUV411",
119 .fourcc = V4L2_PIX_FMT_YUV411P,
120 .depth = 12,
121 .reg = EM28XX_OUTFMT_YUV411,
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -0300122 },
123};
124
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800125/* supported controls */
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -0200126/* Common to all boards */
Mauro Carvalho Chehabed10daa2009-07-19 09:10:06 -0300127static struct v4l2_queryctrl ac97_qctrl[] = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800128 {
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -0200129 .id = V4L2_CID_AUDIO_VOLUME,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Volume",
132 .minimum = 0x0,
133 .maximum = 0x1f,
134 .step = 0x1,
135 .default_value = 0x1f,
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300136 .flags = V4L2_CTRL_FLAG_SLIDER,
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300137 }, {
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -0200138 .id = V4L2_CID_AUDIO_MUTE,
139 .type = V4L2_CTRL_TYPE_BOOLEAN,
140 .name = "Mute",
141 .minimum = 0,
142 .maximum = 1,
143 .step = 1,
144 .default_value = 1,
145 .flags = 0,
146 }
147};
148
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300149/* ------------------------------------------------------------------
150 DMA and thread functions
151 ------------------------------------------------------------------*/
152
153/*
154 * Announces that a buffer were filled and request the next
155 */
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300156static inline void buffer_filled(struct em28xx *dev,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300157 struct em28xx_dmaqueue *dma_q,
158 struct em28xx_buffer *buf)
159{
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300160 /* Advice that buffer was filled */
161 em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
162 buf->vb.state = VIDEOBUF_DONE;
163 buf->vb.field_count++;
164 do_gettimeofday(&buf->vb.ts);
165
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300166 dev->isoc_ctl.vid_buf = NULL;
167
168 list_del(&buf->vb.queue);
169 wake_up(&buf->vb.done);
170}
171
172static inline void vbi_buffer_filled(struct em28xx *dev,
173 struct em28xx_dmaqueue *dma_q,
174 struct em28xx_buffer *buf)
175{
176 /* Advice that buffer was filled */
177 em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
178
179 buf->vb.state = VIDEOBUF_DONE;
180 buf->vb.field_count++;
181 do_gettimeofday(&buf->vb.ts);
182
183 dev->isoc_ctl.vbi_buf = NULL;
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300184
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300185 list_del(&buf->vb.queue);
186 wake_up(&buf->vb.done);
187}
188
189/*
190 * Identify the buffer header type and properly handles
191 */
192static void em28xx_copy_video(struct em28xx *dev,
193 struct em28xx_dmaqueue *dma_q,
194 struct em28xx_buffer *buf,
195 unsigned char *p,
196 unsigned char *outp, unsigned long len)
197{
198 void *fieldstart, *startwrite, *startread;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300199 int linesdone, currlinedone, offset, lencopy, remain;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300200 int bytesperline = dev->width << 1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300201
202 if (dma_q->pos + len > buf->vb.size)
203 len = buf->vb.size - dma_q->pos;
204
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300205 if (p[0] != 0x88 && p[0] != 0x22) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300206 em28xx_isocdbg("frame is not complete\n");
207 len += 4;
208 } else
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300209 p += 4;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300210
211 startread = p;
212 remain = len;
213
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -0300214 if (dev->progressive)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300215 fieldstart = outp;
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -0300216 else {
217 /* Interlaces two half frames */
218 if (buf->top_field)
219 fieldstart = outp;
220 else
221 fieldstart = outp + bytesperline;
222 }
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300223
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300224 linesdone = dma_q->pos / bytesperline;
225 currlinedone = dma_q->pos % bytesperline;
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -0300226
227 if (dev->progressive)
228 offset = linesdone * bytesperline + currlinedone;
229 else
230 offset = linesdone * bytesperline * 2 + currlinedone;
231
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300232 startwrite = fieldstart + offset;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300233 lencopy = bytesperline - currlinedone;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300234 lencopy = lencopy > remain ? remain : lencopy;
235
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300236 if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
Mauro Carvalho Chehabea8df7e2008-04-13 14:39:29 -0300237 em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300238 ((char *)startwrite + lencopy) -
239 ((char *)outp + buf->vb.size));
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300240 remain = (char *)outp + buf->vb.size - (char *)startwrite;
241 lencopy = remain;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300242 }
Aidan Thorntone0fadfd2008-04-13 14:56:02 -0300243 if (lencopy <= 0)
244 return;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300245 memcpy(startwrite, startread, lencopy);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300246
247 remain -= lencopy;
248
249 while (remain > 0) {
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300250 startwrite += lencopy + bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300251 startread += lencopy;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300252 if (bytesperline > remain)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300253 lencopy = remain;
254 else
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300255 lencopy = bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300256
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300257 if ((char *)startwrite + lencopy > (char *)outp +
258 buf->vb.size) {
Mauro Carvalho Chehabea8df7e2008-04-13 14:39:29 -0300259 em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300260 ((char *)startwrite + lencopy) -
261 ((char *)outp + buf->vb.size));
262 lencopy = remain = (char *)outp + buf->vb.size -
263 (char *)startwrite;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300264 }
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300265 if (lencopy <= 0)
266 break;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300267
268 memcpy(startwrite, startread, lencopy);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300269
270 remain -= lencopy;
271 }
272
273 dma_q->pos += len;
274}
275
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300276static void em28xx_copy_vbi(struct em28xx *dev,
277 struct em28xx_dmaqueue *dma_q,
278 struct em28xx_buffer *buf,
279 unsigned char *p,
280 unsigned char *outp, unsigned long len)
281{
282 void *startwrite, *startread;
283 int offset;
284 int bytesperline = 720;
285
286 if (dev == NULL) {
287 printk("dev is null\n");
288 return;
289 }
290
291 if (dma_q == NULL) {
292 printk("dma_q is null\n");
293 return;
294 }
295 if (buf == NULL) {
296 return;
297 }
298 if (p == NULL) {
299 printk("p is null\n");
300 return;
301 }
302 if (outp == NULL) {
303 printk("outp is null\n");
304 return;
305 }
306
307 if (dma_q->pos + len > buf->vb.size)
308 len = buf->vb.size - dma_q->pos;
309
310 if ((p[0] == 0x33 && p[1] == 0x95) ||
311 (p[0] == 0x88 && p[1] == 0x88)) {
312 /* Header field, advance past it */
313 p += 4;
314 } else {
315 len += 4;
316 }
317
318 startread = p;
319
320 startwrite = outp + dma_q->pos;
321 offset = dma_q->pos;
322
323 /* Make sure the bottom field populates the second half of the frame */
324 if (buf->top_field == 0) {
325 startwrite += bytesperline * 0x0c;
326 offset += bytesperline * 0x0c;
327 }
328
329 memcpy(startwrite, startread, len);
330 dma_q->pos += len;
331}
332
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300333static inline void print_err_status(struct em28xx *dev,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300334 int packet, int status)
335{
336 char *errmsg = "Unknown";
337
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300338 switch (status) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300339 case -ENOENT:
340 errmsg = "unlinked synchronuously";
341 break;
342 case -ECONNRESET:
343 errmsg = "unlinked asynchronuously";
344 break;
345 case -ENOSR:
346 errmsg = "Buffer error (overrun)";
347 break;
348 case -EPIPE:
349 errmsg = "Stalled (device not responding)";
350 break;
351 case -EOVERFLOW:
352 errmsg = "Babble (bad cable?)";
353 break;
354 case -EPROTO:
355 errmsg = "Bit-stuff error (bad cable?)";
356 break;
357 case -EILSEQ:
358 errmsg = "CRC/Timeout (could be anything)";
359 break;
360 case -ETIME:
361 errmsg = "Device does not respond";
362 break;
363 }
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300364 if (packet < 0) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300365 em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
366 } else {
367 em28xx_isocdbg("URB packet %d, status %d [%s].\n",
368 packet, status, errmsg);
369 }
370}
371
372/*
373 * video-buf generic routine to get the next available buffer
374 */
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300375static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300376 struct em28xx_buffer **buf)
377{
378 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300379 char *outp;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300380
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300381 if (list_empty(&dma_q->active)) {
382 em28xx_isocdbg("No active queue to serve\n");
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300383 dev->isoc_ctl.vid_buf = NULL;
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300384 *buf = NULL;
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300385 return;
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300386 }
387
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300388 /* Get the next buffer */
389 *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
390
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300391 /* Cleans up buffer - Usefull for testing for frame/URB loss */
392 outp = videobuf_to_vmalloc(&(*buf)->vb);
393 memset(outp, 0, (*buf)->vb.size);
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300394
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300395 dev->isoc_ctl.vid_buf = *buf;
396
397 return;
398}
399
400/*
401 * video-buf generic routine to get the next available VBI buffer
402 */
403static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
404 struct em28xx_buffer **buf)
405{
406 struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
407 char *outp;
408
409 if (list_empty(&dma_q->active)) {
410 em28xx_isocdbg("No active queue to serve\n");
411 dev->isoc_ctl.vbi_buf = NULL;
412 *buf = NULL;
413 return;
414 }
415
416 /* Get the next buffer */
417 *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
418 /* Cleans up buffer - Usefull for testing for frame/URB loss */
419 outp = videobuf_to_vmalloc(&(*buf)->vb);
420 memset(outp, 0x00, (*buf)->vb.size);
421
422 dev->isoc_ctl.vbi_buf = *buf;
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300423
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300424 return;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300425}
426
427/*
428 * Controls the isoc copy of each urb packet
429 */
Aidan Thornton579f72e2008-04-17 21:40:16 -0300430static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300431{
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300432 struct em28xx_buffer *buf;
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300433 struct em28xx_dmaqueue *dma_q = &dev->vidq;
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300434 unsigned char *outp = NULL;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300435 int i, len = 0, rc = 1;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300436 unsigned char *p;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300437
438 if (!dev)
439 return 0;
440
441 if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
442 return 0;
443
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300444 if (urb->status < 0) {
445 print_err_status(dev, -1, urb->status);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300446 if (urb->status == -ENOENT)
447 return 0;
448 }
449
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300450 buf = dev->isoc_ctl.vid_buf;
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300451 if (buf != NULL)
452 outp = videobuf_to_vmalloc(&buf->vb);
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300453
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300454 for (i = 0; i < urb->number_of_packets; i++) {
455 int status = urb->iso_frame_desc[i].status;
456
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300457 if (status < 0) {
458 print_err_status(dev, i, status);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300459 if (urb->iso_frame_desc[i].status != -EPROTO)
460 continue;
461 }
462
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300463 len = urb->iso_frame_desc[i].actual_length - 4;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300464
465 if (urb->iso_frame_desc[i].actual_length <= 0) {
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300466 /* em28xx_isocdbg("packet %d is empty",i); - spammy */
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300467 continue;
468 }
469 if (urb->iso_frame_desc[i].actual_length >
470 dev->max_pkt_size) {
471 em28xx_isocdbg("packet bigger than packet size");
472 continue;
473 }
474
475 p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300476
477 /* FIXME: incomplete buffer checks where removed to make
478 logic simpler. Impacts of those changes should be evaluated
479 */
Mauro Carvalho Chehabb4916f82008-04-13 15:09:14 -0300480 if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
481 em28xx_isocdbg("VBI HEADER!!!\n");
482 /* FIXME: Should add vbi copy */
483 continue;
484 }
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300485 if (p[0] == 0x22 && p[1] == 0x5a) {
Mauro Carvalho Chehab78bb3942008-04-13 14:56:25 -0300486 em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300487 len, (p[2] & 1) ? "odd" : "even");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300488
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -0300489 if (dev->progressive || !(p[2] & 1)) {
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300490 if (buf != NULL)
491 buffer_filled(dev, dma_q, buf);
492 get_next_buf(dma_q, &buf);
493 if (buf == NULL)
494 outp = NULL;
495 else
496 outp = videobuf_to_vmalloc(&buf->vb);
Aidan Thorntone0fadfd2008-04-13 14:56:02 -0300497 }
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300498
499 if (buf != NULL) {
500 if (p[2] & 1)
501 buf->top_field = 0;
502 else
503 buf->top_field = 1;
504 }
Mauro Carvalho Chehabb4916f82008-04-13 15:09:14 -0300505
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300506 dma_q->pos = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300507 }
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300508 if (buf != NULL)
509 em28xx_copy_video(dev, dma_q, buf, p, outp, len);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300510 }
511 return rc;
512}
513
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300514/* Version of isoc handler that takes into account a mixture of video and
515 VBI data */
516static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
517{
518 struct em28xx_buffer *buf, *vbi_buf;
519 struct em28xx_dmaqueue *dma_q = &dev->vidq;
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300520 struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300521 unsigned char *outp = NULL;
522 unsigned char *vbioutp = NULL;
523 int i, len = 0, rc = 1;
524 unsigned char *p;
525 int vbi_size;
526
527 if (!dev)
528 return 0;
529
530 if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
531 return 0;
532
533 if (urb->status < 0) {
534 print_err_status(dev, -1, urb->status);
535 if (urb->status == -ENOENT)
536 return 0;
537 }
538
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300539 buf = dev->isoc_ctl.vid_buf;
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300540 if (buf != NULL)
541 outp = videobuf_to_vmalloc(&buf->vb);
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300542
543 vbi_buf = dev->isoc_ctl.vbi_buf;
544 if (vbi_buf != NULL)
545 vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
546
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300547 for (i = 0; i < urb->number_of_packets; i++) {
548 int status = urb->iso_frame_desc[i].status;
549
550 if (status < 0) {
551 print_err_status(dev, i, status);
552 if (urb->iso_frame_desc[i].status != -EPROTO)
553 continue;
554 }
555
556 len = urb->iso_frame_desc[i].actual_length - 4;
557
558 if (urb->iso_frame_desc[i].actual_length <= 0) {
559 /* em28xx_isocdbg("packet %d is empty",i); - spammy */
560 continue;
561 }
562 if (urb->iso_frame_desc[i].actual_length >
563 dev->max_pkt_size) {
564 em28xx_isocdbg("packet bigger than packet size");
565 continue;
566 }
567
568 p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
569
570 /* capture type 0 = vbi start
571 capture type 1 = video start
572 capture type 2 = video in progress */
573 if (p[0] == 0x33 && p[1] == 0x95) {
574 dev->capture_type = 0;
575 dev->vbi_read = 0;
576 em28xx_isocdbg("VBI START HEADER!!!\n");
577 dev->cur_field = p[2];
578 }
579
580 /* FIXME: get rid of hard-coded value */
581 vbi_size = 720 * 0x0c;
582
583 if (dev->capture_type == 0) {
584 if (dev->vbi_read >= vbi_size) {
585 /* We've already read all the VBI data, so
586 treat the rest as video */
587 printk("djh c should never happen\n");
588 } else if ((dev->vbi_read + len) < vbi_size) {
589 /* This entire frame is VBI data */
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300590 if (dev->vbi_read == 0 &&
591 (!(dev->cur_field & 1))) {
592 /* Brand new frame */
593 if (vbi_buf != NULL)
594 vbi_buffer_filled(dev,
595 vbi_dma_q,
596 vbi_buf);
597 vbi_get_next_buf(vbi_dma_q, &vbi_buf);
598 if (vbi_buf == NULL)
599 vbioutp = NULL;
600 else {
601 vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
602 }
603 }
604
605 if (dev->vbi_read == 0) {
606 vbi_dma_q->pos = 0;
607 if (vbi_buf != NULL) {
608 if (dev->cur_field & 1)
609 vbi_buf->top_field = 0;
610 else
611 vbi_buf->top_field = 1;
612 }
613 }
614
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300615 dev->vbi_read += len;
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300616 em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
617 vbioutp, len);
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300618 } else {
619 /* Some of this frame is VBI data and some is
620 video data */
621 int vbi_data_len = vbi_size - dev->vbi_read;
622 dev->vbi_read += vbi_data_len;
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300623 em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
624 vbioutp, vbi_data_len);
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300625 dev->capture_type = 1;
626 p += vbi_data_len;
627 len -= vbi_data_len;
628 }
629 }
630
631 if (dev->capture_type == 1) {
632 dev->capture_type = 2;
633 em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
634 len, (p[2] & 1) ? "odd" : "even");
635
636 if (dev->progressive || !(dev->cur_field & 1)) {
637 if (buf != NULL)
638 buffer_filled(dev, dma_q, buf);
639 get_next_buf(dma_q, &buf);
640 if (buf == NULL)
641 outp = NULL;
642 else
643 outp = videobuf_to_vmalloc(&buf->vb);
644 }
645 if (buf != NULL) {
646 if (dev->cur_field & 1)
647 buf->top_field = 0;
648 else
649 buf->top_field = 1;
650 }
651
652 dma_q->pos = 0;
653 }
654 if (buf != NULL && dev->capture_type == 2)
655 em28xx_copy_video(dev, dma_q, buf, p, outp, len);
656 }
657 return rc;
658}
659
660
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300661/* ------------------------------------------------------------------
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300662 Videobuf operations
663 ------------------------------------------------------------------*/
664
665static int
666buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
667{
668 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabd2d9fbf2008-04-17 21:38:53 -0300669 struct em28xx *dev = fh->dev;
670 struct v4l2_frequency f;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300671
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -0300672 *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
673
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300674 if (0 == *count)
675 *count = EM28XX_DEF_BUF;
676
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300677 if (*count < EM28XX_MIN_BUF)
678 *count = EM28XX_MIN_BUF;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300679
Mauro Carvalho Chehab381aaba2008-12-20 07:43:34 -0300680 /* Ask tuner to go to analog or radio mode */
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300681 memset(&f, 0, sizeof(f));
Mauro Carvalho Chehabd2d9fbf2008-04-17 21:38:53 -0300682 f.frequency = dev->ctl_freq;
Mauro Carvalho Chehab381aaba2008-12-20 07:43:34 -0300683 f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
Mauro Carvalho Chehabd2d9fbf2008-04-17 21:38:53 -0300684
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300685 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
Mauro Carvalho Chehabd2d9fbf2008-04-17 21:38:53 -0300686
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300687 return 0;
688}
689
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300690/* This is called *without* dev->slock held; please keep it that way */
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300691static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
692{
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300693 struct em28xx_fh *fh = vq->priv_data;
694 struct em28xx *dev = fh->dev;
695 unsigned long flags = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300696 if (in_interrupt())
697 BUG();
698
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300699 /* We used to wait for the buffer to finish here, but this didn't work
700 because, as we were keeping the state as VIDEOBUF_QUEUED,
701 videobuf_queue_cancel marked it as finished for us.
702 (Also, it could wedge forever if the hardware was misconfigured.)
703
704 This should be safe; by the time we get here, the buffer isn't
705 queued anymore. If we ever start marking the buffers as
706 VIDEOBUF_ACTIVE, it won't be, though.
707 */
708 spin_lock_irqsave(&dev->slock, flags);
Devin Heitmueller28abf0832009-09-01 01:54:54 -0300709 if (dev->isoc_ctl.vid_buf == buf)
710 dev->isoc_ctl.vid_buf = NULL;
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300711 spin_unlock_irqrestore(&dev->slock, flags);
712
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300713 videobuf_vmalloc_free(&buf->vb);
714 buf->vb.state = VIDEOBUF_NEEDS_INIT;
715}
716
717static int
718buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
719 enum v4l2_field field)
720{
721 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300722 struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300723 struct em28xx *dev = fh->dev;
724 int rc = 0, urb_init = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300725
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -0300726 buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300727
728 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
729 return -EINVAL;
730
Brandon Philips05612972008-04-13 14:57:01 -0300731 buf->vb.width = dev->width;
732 buf->vb.height = dev->height;
733 buf->vb.field = field;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300734
735 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300736 rc = videobuf_iolock(vq, &buf->vb, NULL);
737 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300738 goto fail;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300739 }
740
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300741 if (!dev->isoc_ctl.num_bufs)
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300742 urb_init = 1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300743
744 if (urb_init) {
Devin Heitmuellerda52a552009-09-01 01:19:46 -0300745 if (em28xx_vbi_supported(dev) == 1)
746 rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
747 EM28XX_NUM_BUFS,
748 dev->max_pkt_size,
749 em28xx_isoc_copy_vbi);
750 else
751 rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
752 EM28XX_NUM_BUFS,
753 dev->max_pkt_size,
754 em28xx_isoc_copy);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300755 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300756 goto fail;
757 }
758
759 buf->vb.state = VIDEOBUF_PREPARED;
760 return 0;
761
762fail:
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300763 free_buffer(vq, buf);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300764 return rc;
765}
766
767static void
768buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
769{
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300770 struct em28xx_buffer *buf = container_of(vb,
771 struct em28xx_buffer,
772 vb);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300773 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300774 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300775 struct em28xx_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300776
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300777 buf->vb.state = VIDEOBUF_QUEUED;
778 list_add_tail(&buf->vb.queue, &vidq->active);
779
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300780}
781
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300782static void buffer_release(struct videobuf_queue *vq,
783 struct videobuf_buffer *vb)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300784{
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -0300785 struct em28xx_buffer *buf = container_of(vb,
786 struct em28xx_buffer,
787 vb);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300788 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300789 struct em28xx *dev = (struct em28xx *)fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300790
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300791 em28xx_isocdbg("em28xx: called buffer_release\n");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300792
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300793 free_buffer(vq, buf);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300794}
795
796static struct videobuf_queue_ops em28xx_video_qops = {
797 .buf_setup = buffer_setup,
798 .buf_prepare = buffer_prepare,
799 .buf_queue = buffer_queue,
800 .buf_release = buffer_release,
801};
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800802
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300803/********************* v4l2 interface **************************************/
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800804
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800805static void video_mux(struct em28xx *dev, int index)
806{
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800807 dev->ctl_input = index;
808 dev->ctl_ainput = INPUT(index)->amux;
Mauro Carvalho Chehab35ae6f02008-11-20 12:40:51 -0300809 dev->ctl_aoutput = INPUT(index)->aout;
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800810
Mauro Carvalho Chehabe879b8e2008-11-20 13:39:39 -0300811 if (!dev->ctl_aoutput)
812 dev->ctl_aoutput = EM28XX_AOUT_MASTER;
813
Hans Verkuil5325b422009-04-02 11:26:22 -0300814 v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
815 INPUT(index)->vmux, 0, 0);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800816
Mauro Carvalho Chehab505b6d02008-11-25 09:39:50 -0300817 if (dev->board.has_msp34xx) {
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300818 if (dev->i2s_speed) {
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -0300819 v4l2_device_call_all(&dev->v4l2_dev, 0, audio,
820 s_i2s_clock_freq, dev->i2s_speed);
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -0300821 }
Hans Verkuil2474ed42006-03-19 12:35:57 -0300822 /* Note: this is msp3400 specific */
Hans Verkuil5325b422009-04-02 11:26:22 -0300823 v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
824 dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800825 }
Mauro Carvalho Chehab539c96d2008-01-05 09:53:54 -0300826
Vitaly Wool2bd1d9e2009-03-04 08:27:52 -0300827 if (dev->board.adecoder != EM28XX_NOADECODER) {
Hans Verkuil5325b422009-04-02 11:26:22 -0300828 v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
829 dev->ctl_ainput, dev->ctl_aoutput, 0);
Vitaly Wool2bd1d9e2009-03-04 08:27:52 -0300830 }
831
Mauro Carvalho Chehab00b87302008-02-06 18:34:13 -0300832 em28xx_audio_analog_set(dev);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800833}
834
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300835/* Usage lock check functions */
Devin Heitmueller8c873d32009-09-03 00:23:27 -0300836static int res_get(struct em28xx_fh *fh, unsigned int bit)
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300837{
838 struct em28xx *dev = fh->dev;
839
Devin Heitmueller8c873d32009-09-03 00:23:27 -0300840 if (fh->resources & bit)
841 /* have it already allocated */
842 return 1;
843
844 /* is it free? */
845 mutex_lock(&dev->lock);
846 if (dev->resources & bit) {
847 /* no, someone else uses it */
848 mutex_unlock(&dev->lock);
849 return 0;
850 }
851 /* it's free, grab it */
852 fh->resources |= bit;
853 dev->resources |= bit;
854 em28xx_videodbg("res: get %d\n", bit);
855 mutex_unlock(&dev->lock);
856 return 1;
857}
858
859static int res_check(struct em28xx_fh *fh, unsigned int bit)
860{
861 return (fh->resources & bit);
862}
863
864static int res_locked(struct em28xx *dev, unsigned int bit)
865{
866 return (dev->resources & bit);
867}
868
869static void res_free(struct em28xx_fh *fh, unsigned int bits)
870{
871 struct em28xx *dev = fh->dev;
872
873 BUG_ON((fh->resources & bits) != bits);
874
875 mutex_lock(&dev->lock);
876 fh->resources &= ~bits;
877 dev->resources &= ~bits;
878 em28xx_videodbg("res: put %d\n", bits);
879 mutex_unlock(&dev->lock);
880}
881
882static int get_ressource(struct em28xx_fh *fh)
883{
884 switch (fh->type) {
885 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
886 return EM28XX_RESOURCE_VIDEO;
887 case V4L2_BUF_TYPE_VBI_CAPTURE:
888 return EM28XX_RESOURCE_VBI;
889 default:
890 BUG();
891 return 0;
892 }
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300893}
894
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800895/*
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300896 * ac97_queryctrl()
897 * return the ac97 supported controls
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300898 */
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300899static int ac97_queryctrl(struct v4l2_queryctrl *qc)
900{
901 int i;
902
903 for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
904 if (qc->id && qc->id == ac97_qctrl[i].id) {
905 memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
906 return 0;
907 }
908 }
909
910 /* Control is not ac97 related */
911 return 1;
912}
913
914/*
915 * ac97_get_ctrl()
916 * return the current values for ac97 mute and volume
917 */
918static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300919{
920 switch (ctrl->id) {
921 case V4L2_CID_AUDIO_MUTE:
922 ctrl->value = dev->mute;
923 return 0;
924 case V4L2_CID_AUDIO_VOLUME:
925 ctrl->value = dev->volume;
926 return 0;
927 default:
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300928 /* Control is not ac97 related */
929 return 1;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300930 }
931}
932
933/*
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300934 * ac97_set_ctrl()
935 * set values for ac97 mute and volume
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300936 */
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300937static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300938{
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300939 int i;
940
941 for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
942 if (ctrl->id == ac97_qctrl[i].id)
943 goto handle;
944
945 /* Announce that hasn't handle it */
946 return 1;
947
948handle:
949 if (ctrl->value < ac97_qctrl[i].minimum ||
950 ctrl->value > ac97_qctrl[i].maximum)
951 return -ERANGE;
952
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300953 switch (ctrl->id) {
954 case V4L2_CID_AUDIO_MUTE:
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300955 dev->mute = ctrl->value;
956 break;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300957 case V4L2_CID_AUDIO_VOLUME:
958 dev->volume = ctrl->value;
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300959 break;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300960 }
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -0300961
962 return em28xx_audio_analog_set(dev);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300963}
964
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300965static int check_dev(struct em28xx *dev)
966{
967 if (dev->state & DEV_DISCONNECTED) {
968 em28xx_errdev("v4l2 ioctl: device not present\n");
969 return -ENODEV;
970 }
971
972 if (dev->state & DEV_MISCONFIGURED) {
973 em28xx_errdev("v4l2 ioctl: device is misconfigured; "
974 "close and open it again\n");
975 return -EIO;
976 }
977 return 0;
978}
979
980static void get_scale(struct em28xx *dev,
981 unsigned int width, unsigned int height,
982 unsigned int *hscale, unsigned int *vscale)
983{
Mauro Carvalho Chehab55699962009-07-13 20:15:02 -0300984 unsigned int maxw = norm_maxw(dev);
985 unsigned int maxh = norm_maxh(dev);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300986
987 *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
988 if (*hscale >= 0x4000)
989 *hscale = 0x3fff;
990
991 *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
992 if (*vscale >= 0x4000)
993 *vscale = 0x3fff;
994}
995
996/* ------------------------------------------------------------------
997 IOCTL vidioc handling
998 ------------------------------------------------------------------*/
999
Hans Verkuil78b526a2008-05-28 12:16:41 -03001000static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001001 struct v4l2_format *f)
1002{
1003 struct em28xx_fh *fh = priv;
1004 struct em28xx *dev = fh->dev;
1005
1006 mutex_lock(&dev->lock);
1007
1008 f->fmt.pix.width = dev->width;
1009 f->fmt.pix.height = dev->height;
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -03001010 f->fmt.pix.pixelformat = dev->format->fourcc;
1011 f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -03001012 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001013 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
1014
1015 /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -03001016 if (dev->progressive)
1017 f->fmt.pix.field = V4L2_FIELD_NONE;
1018 else
1019 f->fmt.pix.field = dev->interlaced ?
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001020 V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
1021
1022 mutex_unlock(&dev->lock);
1023 return 0;
1024}
1025
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -03001026static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
1027{
1028 unsigned int i;
1029
1030 for (i = 0; i < ARRAY_SIZE(format); i++)
1031 if (format[i].fourcc == fourcc)
1032 return &format[i];
1033
1034 return NULL;
1035}
1036
Hans Verkuil78b526a2008-05-28 12:16:41 -03001037static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001038 struct v4l2_format *f)
1039{
1040 struct em28xx_fh *fh = priv;
1041 struct em28xx *dev = fh->dev;
Trent Piephoccb83402009-05-30 21:45:46 -03001042 unsigned int width = f->fmt.pix.width;
1043 unsigned int height = f->fmt.pix.height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001044 unsigned int maxw = norm_maxw(dev);
1045 unsigned int maxh = norm_maxh(dev);
1046 unsigned int hscale, vscale;
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -03001047 struct em28xx_fmt *fmt;
1048
1049 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
1050 if (!fmt) {
1051 em28xx_videodbg("Fourcc format (%08x) invalid.\n",
1052 f->fmt.pix.pixelformat);
1053 return -EINVAL;
1054 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001055
Mauro Carvalho Chehab55699962009-07-13 20:15:02 -03001056 if (dev->board.is_em2800) {
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001057 /* the em2800 can only scale down to 50% */
Trent Piephoccb83402009-05-30 21:45:46 -03001058 height = height > (3 * maxh / 4) ? maxh : maxh / 2;
1059 width = width > (3 * maxw / 4) ? maxw : maxw / 2;
1060 /* According to empiatech support the MaxPacketSize is too small
1061 * to support framesizes larger than 640x480 @ 30 fps or 640x576
1062 * @ 25 fps. As this would cut of a part of the image we prefer
1063 * 360x576 or 360x480 for now */
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001064 if (width == maxw && height == maxh)
1065 width /= 2;
Trent Piephoccb83402009-05-30 21:45:46 -03001066 } else {
1067 /* width must even because of the YUYV format
1068 height must be even because of interlacing */
1069 v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001070 }
1071
1072 get_scale(dev, width, height, &hscale, &vscale);
1073
1074 width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
1075 height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
1076
1077 f->fmt.pix.width = width;
1078 f->fmt.pix.height = height;
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -03001079 f->fmt.pix.pixelformat = fmt->fourcc;
1080 f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
1081 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001082 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -03001083 if (dev->progressive)
1084 f->fmt.pix.field = V4L2_FIELD_NONE;
1085 else
1086 f->fmt.pix.field = dev->interlaced ?
1087 V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001088
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001089 return 0;
1090}
1091
Mauro Carvalho Chehabed5f1432009-07-02 17:34:04 -03001092static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
1093 unsigned width, unsigned height)
1094{
1095 struct em28xx_fmt *fmt;
1096
Mauro Carvalho Chehabed5f1432009-07-02 17:34:04 -03001097 fmt = format_by_fourcc(fourcc);
1098 if (!fmt)
1099 return -EINVAL;
1100
1101 dev->format = fmt;
1102 dev->width = width;
1103 dev->height = height;
1104
1105 /* set new image size */
1106 get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
1107
1108 em28xx_set_alternate(dev);
1109 em28xx_resolution_set(dev);
1110
1111 return 0;
1112}
1113
Hans Verkuil78b526a2008-05-28 12:16:41 -03001114static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001115 struct v4l2_format *f)
1116{
1117 struct em28xx_fh *fh = priv;
1118 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001119 int rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001120
1121 rc = check_dev(dev);
1122 if (rc < 0)
1123 return rc;
1124
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001125 mutex_lock(&dev->lock);
1126
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001127 vidioc_try_fmt_vid_cap(file, priv, f);
1128
Brandon Philips05612972008-04-13 14:57:01 -03001129 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
1130 em28xx_errdev("%s queue busy\n", __func__);
1131 rc = -EBUSY;
1132 goto out;
1133 }
1134
Mauro Carvalho Chehabed5f1432009-07-02 17:34:04 -03001135 rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
1136 f->fmt.pix.width, f->fmt.pix.height);
Brandon Philips05612972008-04-13 14:57:01 -03001137
1138out:
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001139 mutex_unlock(&dev->lock);
Brandon Philips05612972008-04-13 14:57:01 -03001140 return rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001141}
1142
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -03001143static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001144{
1145 struct em28xx_fh *fh = priv;
1146 struct em28xx *dev = fh->dev;
1147 struct v4l2_format f;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001148 int rc;
1149
1150 rc = check_dev(dev);
1151 if (rc < 0)
1152 return rc;
1153
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001154 mutex_lock(&dev->lock);
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001155 dev->norm = *norm;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001156
1157 /* Adjusts width/height, if needed */
1158 f.fmt.pix.width = dev->width;
1159 f.fmt.pix.height = dev->height;
Hans Verkuil78b526a2008-05-28 12:16:41 -03001160 vidioc_try_fmt_vid_cap(file, priv, &f);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001161
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001162 /* set new image size */
1163 dev->width = f.fmt.pix.width;
1164 dev->height = f.fmt.pix.height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001165 get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
1166
1167 em28xx_resolution_set(dev);
Hans Verkuilf41737e2009-04-01 03:52:39 -03001168 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001169
1170 mutex_unlock(&dev->lock);
1171 return 0;
1172}
1173
Mauro Carvalho Chehabd96ecda2009-08-06 21:53:59 -03001174static int vidioc_g_parm(struct file *file, void *priv,
1175 struct v4l2_streamparm *p)
1176{
1177 struct em28xx_fh *fh = priv;
1178 struct em28xx *dev = fh->dev;
1179 int rc = 0;
1180
1181 if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1182 return -EINVAL;
1183
1184 if (dev->board.is_webcam)
1185 rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
1186 video, g_parm, p);
1187 else
1188 v4l2_video_std_frame_period(dev->norm,
1189 &p->parm.capture.timeperframe);
1190
1191 return rc;
1192}
1193
1194static int vidioc_s_parm(struct file *file, void *priv,
1195 struct v4l2_streamparm *p)
1196{
1197 struct em28xx_fh *fh = priv;
1198 struct em28xx *dev = fh->dev;
1199
1200 if (!dev->board.is_webcam)
1201 return -EINVAL;
1202
1203 if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1204 return -EINVAL;
1205
1206 return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
1207}
1208
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001209static const char *iname[] = {
1210 [EM28XX_VMUX_COMPOSITE1] = "Composite1",
1211 [EM28XX_VMUX_COMPOSITE2] = "Composite2",
1212 [EM28XX_VMUX_COMPOSITE3] = "Composite3",
1213 [EM28XX_VMUX_COMPOSITE4] = "Composite4",
1214 [EM28XX_VMUX_SVIDEO] = "S-Video",
1215 [EM28XX_VMUX_TELEVISION] = "Television",
1216 [EM28XX_VMUX_CABLE] = "Cable TV",
1217 [EM28XX_VMUX_DVB] = "DVB",
1218 [EM28XX_VMUX_DEBUG] = "for debug only",
1219};
1220
1221static int vidioc_enum_input(struct file *file, void *priv,
1222 struct v4l2_input *i)
1223{
1224 struct em28xx_fh *fh = priv;
1225 struct em28xx *dev = fh->dev;
1226 unsigned int n;
1227
1228 n = i->index;
1229 if (n >= MAX_EM28XX_INPUT)
1230 return -EINVAL;
1231 if (0 == INPUT(n)->type)
1232 return -EINVAL;
1233
1234 i->index = n;
1235 i->type = V4L2_INPUT_TYPE_CAMERA;
1236
1237 strcpy(i->name, iname[INPUT(n)->type]);
1238
1239 if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
1240 (EM28XX_VMUX_CABLE == INPUT(n)->type))
1241 i->type = V4L2_INPUT_TYPE_TUNER;
1242
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001243 i->std = dev->vdev->tvnorms;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001244
1245 return 0;
1246}
1247
1248static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
1249{
1250 struct em28xx_fh *fh = priv;
1251 struct em28xx *dev = fh->dev;
1252
1253 *i = dev->ctl_input;
1254
1255 return 0;
1256}
1257
1258static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
1259{
1260 struct em28xx_fh *fh = priv;
1261 struct em28xx *dev = fh->dev;
1262 int rc;
1263
1264 rc = check_dev(dev);
1265 if (rc < 0)
1266 return rc;
1267
1268 if (i >= MAX_EM28XX_INPUT)
1269 return -EINVAL;
1270 if (0 == INPUT(i)->type)
1271 return -EINVAL;
1272
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03001273 dev->ctl_input = i;
1274
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001275 mutex_lock(&dev->lock);
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03001276 video_mux(dev, dev->ctl_input);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001277 mutex_unlock(&dev->lock);
1278 return 0;
1279}
1280
1281static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
1282{
1283 struct em28xx_fh *fh = priv;
1284 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001285
Mauro Carvalho Chehab6c428b52009-08-04 19:52:37 -03001286 if (!dev->audio_mode.has_audio)
1287 return -EINVAL;
1288
Mauro Carvalho Chehab35ae6f02008-11-20 12:40:51 -03001289 switch (a->index) {
1290 case EM28XX_AMUX_VIDEO:
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001291 strcpy(a->name, "Television");
Mauro Carvalho Chehab35ae6f02008-11-20 12:40:51 -03001292 break;
1293 case EM28XX_AMUX_LINE_IN:
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001294 strcpy(a->name, "Line In");
Mauro Carvalho Chehab35ae6f02008-11-20 12:40:51 -03001295 break;
1296 case EM28XX_AMUX_VIDEO2:
1297 strcpy(a->name, "Television alt");
1298 break;
1299 case EM28XX_AMUX_PHONE:
1300 strcpy(a->name, "Phone");
1301 break;
1302 case EM28XX_AMUX_MIC:
1303 strcpy(a->name, "Mic");
1304 break;
1305 case EM28XX_AMUX_CD:
1306 strcpy(a->name, "CD");
1307 break;
1308 case EM28XX_AMUX_AUX:
1309 strcpy(a->name, "Aux");
1310 break;
1311 case EM28XX_AMUX_PCM_OUT:
1312 strcpy(a->name, "PCM");
1313 break;
1314 default:
1315 return -EINVAL;
1316 }
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -03001317
Mauro Carvalho Chehab35ae6f02008-11-20 12:40:51 -03001318 a->index = dev->ctl_ainput;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001319 a->capability = V4L2_AUDCAP_STEREO;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001320
1321 return 0;
1322}
1323
1324static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
1325{
1326 struct em28xx_fh *fh = priv;
1327 struct em28xx *dev = fh->dev;
1328
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03001329
Mauro Carvalho Chehab6c428b52009-08-04 19:52:37 -03001330 if (!dev->audio_mode.has_audio)
1331 return -EINVAL;
1332
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03001333 if (a->index >= MAX_EM28XX_INPUT)
1334 return -EINVAL;
1335 if (0 == INPUT(a->index)->type)
1336 return -EINVAL;
1337
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001338 mutex_lock(&dev->lock);
1339
Mauro Carvalho Chehab35ae6f02008-11-20 12:40:51 -03001340 dev->ctl_ainput = INPUT(a->index)->amux;
1341 dev->ctl_aoutput = INPUT(a->index)->aout;
Mauro Carvalho Chehabe879b8e2008-11-20 13:39:39 -03001342
1343 if (!dev->ctl_aoutput)
1344 dev->ctl_aoutput = EM28XX_AOUT_MASTER;
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001345
1346 mutex_unlock(&dev->lock);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001347 return 0;
1348}
1349
1350static int vidioc_queryctrl(struct file *file, void *priv,
1351 struct v4l2_queryctrl *qc)
1352{
1353 struct em28xx_fh *fh = priv;
1354 struct em28xx *dev = fh->dev;
1355 int id = qc->id;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001356 int rc;
1357
1358 rc = check_dev(dev);
1359 if (rc < 0)
1360 return rc;
1361
1362 memset(qc, 0, sizeof(*qc));
1363
1364 qc->id = id;
1365
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -03001366 /* enumberate AC97 controls */
1367 if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
1368 rc = ac97_queryctrl(qc);
1369 if (!rc)
1370 return 0;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001371 }
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001372
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -03001373 /* enumberate V4L2 device controls */
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001374 mutex_lock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001375 v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001376 mutex_unlock(&dev->lock);
1377
1378 if (qc->type)
1379 return 0;
1380 else
1381 return -EINVAL;
1382}
1383
1384static int vidioc_g_ctrl(struct file *file, void *priv,
1385 struct v4l2_control *ctrl)
1386{
1387 struct em28xx_fh *fh = priv;
1388 struct em28xx *dev = fh->dev;
1389 int rc;
1390
1391 rc = check_dev(dev);
1392 if (rc < 0)
1393 return rc;
Mauro Carvalho Chehabb6070f02008-12-22 06:20:32 -03001394 rc = 0;
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001395
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001396 mutex_lock(&dev->lock);
1397
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -03001398 /* Set an AC97 control */
1399 if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
1400 rc = ac97_get_ctrl(dev, ctrl);
1401 else
1402 rc = 1;
1403
1404 /* It were not an AC97 control. Sends it to the v4l2 dev interface */
1405 if (rc == 1) {
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001406 v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -03001407 rc = 0;
Hans Verkuil07f7db42009-01-21 17:06:42 -03001408 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001409
1410 mutex_unlock(&dev->lock);
1411 return rc;
1412}
1413
1414static int vidioc_s_ctrl(struct file *file, void *priv,
1415 struct v4l2_control *ctrl)
1416{
1417 struct em28xx_fh *fh = priv;
1418 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001419 int rc;
1420
1421 rc = check_dev(dev);
1422 if (rc < 0)
1423 return rc;
1424
1425 mutex_lock(&dev->lock);
1426
Mauro Carvalho Chehaba98f6af2009-07-19 10:45:49 -03001427 /* Set an AC97 control */
1428 if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
1429 rc = ac97_set_ctrl(dev, ctrl);
1430 else
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001431 rc = 1;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001432
Mauro Carvalho Chehab73c6f462009-07-29 01:42:02 -03001433 /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001434 if (rc == 1) {
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001435 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
Mauro Carvalho Chehab73c6f462009-07-29 01:42:02 -03001436
1437 /*
1438 * In the case of non-AC97 volume controls, we still need
1439 * to do some setups at em28xx, in order to mute/unmute
1440 * and to adjust audio volume. However, the value ranges
1441 * should be checked by the corresponding V4L subdriver.
1442 */
1443 switch (ctrl->id) {
1444 case V4L2_CID_AUDIO_MUTE:
1445 dev->mute = ctrl->value;
1446 rc = em28xx_audio_analog_set(dev);
1447 break;
1448 case V4L2_CID_AUDIO_VOLUME:
1449 dev->volume = ctrl->value;
1450 rc = em28xx_audio_analog_set(dev);
1451 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001452 }
1453
1454 mutex_unlock(&dev->lock);
1455 return rc;
1456}
1457
1458static int vidioc_g_tuner(struct file *file, void *priv,
1459 struct v4l2_tuner *t)
1460{
1461 struct em28xx_fh *fh = priv;
1462 struct em28xx *dev = fh->dev;
1463 int rc;
1464
1465 rc = check_dev(dev);
1466 if (rc < 0)
1467 return rc;
1468
1469 if (0 != t->index)
1470 return -EINVAL;
1471
1472 strcpy(t->name, "Tuner");
1473
1474 mutex_lock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001475 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001476 mutex_unlock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001477
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001478 return 0;
1479}
1480
1481static int vidioc_s_tuner(struct file *file, void *priv,
1482 struct v4l2_tuner *t)
1483{
1484 struct em28xx_fh *fh = priv;
1485 struct em28xx *dev = fh->dev;
1486 int rc;
1487
1488 rc = check_dev(dev);
1489 if (rc < 0)
1490 return rc;
1491
1492 if (0 != t->index)
1493 return -EINVAL;
1494
1495 mutex_lock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001496 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001497 mutex_unlock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001498
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001499 return 0;
1500}
1501
1502static int vidioc_g_frequency(struct file *file, void *priv,
1503 struct v4l2_frequency *f)
1504{
1505 struct em28xx_fh *fh = priv;
1506 struct em28xx *dev = fh->dev;
1507
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001508 mutex_lock(&dev->lock);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001509 f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001510 f->frequency = dev->ctl_freq;
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001511 mutex_unlock(&dev->lock);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001512
1513 return 0;
1514}
1515
1516static int vidioc_s_frequency(struct file *file, void *priv,
1517 struct v4l2_frequency *f)
1518{
1519 struct em28xx_fh *fh = priv;
1520 struct em28xx *dev = fh->dev;
1521 int rc;
1522
1523 rc = check_dev(dev);
1524 if (rc < 0)
1525 return rc;
1526
1527 if (0 != f->tuner)
1528 return -EINVAL;
1529
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001530 if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
1531 return -EINVAL;
1532 if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001533 return -EINVAL;
1534
1535 mutex_lock(&dev->lock);
1536
1537 dev->ctl_freq = f->frequency;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001538 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001539
1540 mutex_unlock(&dev->lock);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001541
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001542 return 0;
1543}
1544
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001545#ifdef CONFIG_VIDEO_ADV_DEBUG
1546static int em28xx_reg_len(int reg)
1547{
1548 switch (reg) {
Mauro Carvalho Chehab41facaa2008-04-17 21:44:58 -03001549 case EM28XX_R40_AC97LSB:
1550 case EM28XX_R30_HSCALELOW:
1551 case EM28XX_R32_VSCALELOW:
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001552 return 2;
1553 default:
1554 return 1;
1555 }
1556}
1557
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001558static int vidioc_g_chip_ident(struct file *file, void *priv,
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001559 struct v4l2_dbg_chip_ident *chip)
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001560{
1561 struct em28xx_fh *fh = priv;
1562 struct em28xx *dev = fh->dev;
1563
1564 chip->ident = V4L2_IDENT_NONE;
1565 chip->revision = 0;
1566
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001567 v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001568
1569 return 0;
1570}
1571
1572
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001573static int vidioc_g_register(struct file *file, void *priv,
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001574 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001575{
1576 struct em28xx_fh *fh = priv;
1577 struct em28xx *dev = fh->dev;
1578 int ret;
1579
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001580 switch (reg->match.type) {
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001581 case V4L2_CHIP_MATCH_AC97:
Mauro Carvalho Chehab531c98e2008-12-22 13:18:27 -03001582 mutex_lock(&dev->lock);
1583 ret = em28xx_read_ac97(dev, reg->reg);
1584 mutex_unlock(&dev->lock);
1585 if (ret < 0)
1586 return ret;
1587
1588 reg->val = ret;
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001589 reg->size = 1;
Mauro Carvalho Chehab531c98e2008-12-22 13:18:27 -03001590 return 0;
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001591 case V4L2_CHIP_MATCH_I2C_DRIVER:
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001592 v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001593 return 0;
1594 case V4L2_CHIP_MATCH_I2C_ADDR:
Mauro Carvalho Chehab4efa2d72009-08-09 19:39:23 -03001595 /* TODO: is this correct? */
1596 v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
1597 return 0;
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001598 default:
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001599 if (!v4l2_chip_match_host(&reg->match))
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001600 return -EINVAL;
Mauro Carvalho Chehab531c98e2008-12-22 13:18:27 -03001601 }
1602
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001603 /* Match host */
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001604 reg->size = em28xx_reg_len(reg->reg);
1605 if (reg->size == 1) {
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001606 mutex_lock(&dev->lock);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001607 ret = em28xx_read_reg(dev, reg->reg);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001608 mutex_unlock(&dev->lock);
1609
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001610 if (ret < 0)
1611 return ret;
1612
1613 reg->val = ret;
1614 } else {
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001615 __le16 val = 0;
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001616 mutex_lock(&dev->lock);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001617 ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
1618 reg->reg, (char *)&val, 2);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001619 mutex_unlock(&dev->lock);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001620 if (ret < 0)
1621 return ret;
1622
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001623 reg->val = le16_to_cpu(val);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001624 }
1625
1626 return 0;
1627}
1628
1629static int vidioc_s_register(struct file *file, void *priv,
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001630 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001631{
1632 struct em28xx_fh *fh = priv;
1633 struct em28xx *dev = fh->dev;
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001634 __le16 buf;
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001635 int rc;
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001636
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001637 switch (reg->match.type) {
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001638 case V4L2_CHIP_MATCH_AC97:
Mauro Carvalho Chehab531c98e2008-12-22 13:18:27 -03001639 mutex_lock(&dev->lock);
1640 rc = em28xx_write_ac97(dev, reg->reg, reg->val);
1641 mutex_unlock(&dev->lock);
1642
1643 return rc;
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001644 case V4L2_CHIP_MATCH_I2C_DRIVER:
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001645 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001646 return 0;
1647 case V4L2_CHIP_MATCH_I2C_ADDR:
Mauro Carvalho Chehab4efa2d72009-08-09 19:39:23 -03001648 /* TODO: is this correct? */
1649 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
1650 return 0;
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001651 default:
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001652 if (!v4l2_chip_match_host(&reg->match))
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001653 return -EINVAL;
Mauro Carvalho Chehab531c98e2008-12-22 13:18:27 -03001654 }
1655
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03001656 /* Match host */
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001657 buf = cpu_to_le16(reg->val);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001658
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001659 mutex_lock(&dev->lock);
1660 rc = em28xx_write_regs(dev, reg->reg, (char *)&buf,
1661 em28xx_reg_len(reg->reg));
1662 mutex_unlock(&dev->lock);
1663
1664 return rc;
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001665}
1666#endif
1667
1668
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001669static int vidioc_cropcap(struct file *file, void *priv,
1670 struct v4l2_cropcap *cc)
1671{
1672 struct em28xx_fh *fh = priv;
1673 struct em28xx *dev = fh->dev;
1674
1675 if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1676 return -EINVAL;
1677
1678 cc->bounds.left = 0;
1679 cc->bounds.top = 0;
1680 cc->bounds.width = dev->width;
1681 cc->bounds.height = dev->height;
1682 cc->defrect = cc->bounds;
1683 cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
1684 cc->pixelaspect.denominator = 59;
1685
1686 return 0;
1687}
1688
1689static int vidioc_streamon(struct file *file, void *priv,
1690 enum v4l2_buf_type type)
1691{
1692 struct em28xx_fh *fh = priv;
1693 struct em28xx *dev = fh->dev;
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001694 int rc = -EINVAL;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001695
1696 rc = check_dev(dev);
1697 if (rc < 0)
1698 return rc;
1699
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001700 if (unlikely(type != fh->type))
1701 return -EINVAL;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001702
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001703 em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
1704 fh, type, fh->resources, dev->resources);
Mauro Carvalho Chehab29b59412008-12-16 20:19:24 -03001705
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001706 if (unlikely(!res_get(fh,get_ressource(fh))))
1707 return -EBUSY;
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001708
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001709 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1710 rc = videobuf_streamon(&fh->vb_vidq);
1711 else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
1712 rc = videobuf_streamon(&fh->vb_vbiq);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001713
1714 return rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001715}
1716
1717static int vidioc_streamoff(struct file *file, void *priv,
1718 enum v4l2_buf_type type)
1719{
1720 struct em28xx_fh *fh = priv;
1721 struct em28xx *dev = fh->dev;
1722 int rc;
1723
1724 rc = check_dev(dev);
1725 if (rc < 0)
1726 return rc;
1727
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001728 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1729 fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001730 return -EINVAL;
1731 if (type != fh->type)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001732 return -EINVAL;
1733
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001734 em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
1735 fh, type, fh->resources, dev->resources);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001736
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001737 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001738 videobuf_streamoff(&fh->vb_vidq);
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001739 res_free(fh, EM28XX_RESOURCE_VIDEO);
1740 } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001741 videobuf_streamoff(&fh->vb_vbiq);
Devin Heitmueller8c873d32009-09-03 00:23:27 -03001742 res_free(fh, EM28XX_RESOURCE_VBI);
1743 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001744
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001745 return 0;
1746}
1747
1748static int vidioc_querycap(struct file *file, void *priv,
1749 struct v4l2_capability *cap)
1750{
1751 struct em28xx_fh *fh = priv;
1752 struct em28xx *dev = fh->dev;
1753
1754 strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
1755 strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
Thierry MERLEcb977162009-01-20 18:01:33 -03001756 usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001757
1758 cap->version = EM28XX_VERSION_CODE;
1759
1760 cap->capabilities =
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001761 V4L2_CAP_VBI_CAPTURE |
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001762 V4L2_CAP_SLICED_VBI_CAPTURE |
1763 V4L2_CAP_VIDEO_CAPTURE |
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001764 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
1765
Mauro Carvalho Chehab6c428b52009-08-04 19:52:37 -03001766 if (dev->audio_mode.has_audio)
1767 cap->capabilities |= V4L2_CAP_AUDIO;
1768
Mauro Carvalho Chehabed086312008-01-24 06:59:20 -03001769 if (dev->tuner_type != TUNER_ABSENT)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001770 cap->capabilities |= V4L2_CAP_TUNER;
1771
1772 return 0;
1773}
1774
Hans Verkuil78b526a2008-05-28 12:16:41 -03001775static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -03001776 struct v4l2_fmtdesc *f)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001777{
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -03001778 if (unlikely(f->index >= ARRAY_SIZE(format)))
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001779 return -EINVAL;
1780
Mauro Carvalho Chehabbddcf632008-12-20 09:06:37 -03001781 strlcpy(f->description, format[f->index].name, sizeof(f->description));
1782 f->pixelformat = format[f->index].fourcc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001783
1784 return 0;
1785}
1786
1787/* Sliced VBI ioctls */
Hans Verkuil78b526a2008-05-28 12:16:41 -03001788static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001789 struct v4l2_format *f)
1790{
1791 struct em28xx_fh *fh = priv;
1792 struct em28xx *dev = fh->dev;
1793 int rc;
1794
1795 rc = check_dev(dev);
1796 if (rc < 0)
1797 return rc;
1798
1799 mutex_lock(&dev->lock);
1800
1801 f->fmt.sliced.service_set = 0;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001802 v4l2_device_call_all(&dev->v4l2_dev, 0, video, g_fmt, f);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001803
1804 if (f->fmt.sliced.service_set == 0)
1805 rc = -EINVAL;
1806
1807 mutex_unlock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001808
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001809 return rc;
1810}
1811
Hans Verkuil78b526a2008-05-28 12:16:41 -03001812static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001813 struct v4l2_format *f)
1814{
1815 struct em28xx_fh *fh = priv;
1816 struct em28xx *dev = fh->dev;
1817 int rc;
1818
1819 rc = check_dev(dev);
1820 if (rc < 0)
1821 return rc;
1822
1823 mutex_lock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001824 v4l2_device_call_all(&dev->v4l2_dev, 0, video, g_fmt, f);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001825 mutex_unlock(&dev->lock);
1826
1827 if (f->fmt.sliced.service_set == 0)
1828 return -EINVAL;
1829
1830 return 0;
1831}
1832
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001833/* RAW VBI ioctls */
1834
1835static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
1836 struct v4l2_format *format)
1837{
1838 format->fmt.vbi.samples_per_line = 720;
1839 format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
1840 format->fmt.vbi.offset = 0;
1841 format->fmt.vbi.flags = 0;
1842
1843 /* Varies by video standard (NTSC, PAL, etc.) */
1844 /* FIXME: hard-coded for NTSC support */
1845 format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
1846 format->fmt.vbi.count[0] = 12;
1847 format->fmt.vbi.count[1] = 12;
1848 format->fmt.vbi.start[0] = 10;
1849 format->fmt.vbi.start[1] = 273;
1850
1851 return 0;
1852}
1853
1854static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
1855 struct v4l2_format *format)
1856{
1857 format->fmt.vbi.samples_per_line = 720;
1858 format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
1859 format->fmt.vbi.offset = 0;
1860 format->fmt.vbi.flags = 0;
1861
1862 /* Varies by video standard (NTSC, PAL, etc.) */
1863 /* FIXME: hard-coded for NTSC support */
1864 format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
1865 format->fmt.vbi.count[0] = 12;
1866 format->fmt.vbi.count[1] = 12;
1867 format->fmt.vbi.start[0] = 10;
1868 format->fmt.vbi.start[1] = 273;
1869
1870 return 0;
1871}
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001872
1873static int vidioc_reqbufs(struct file *file, void *priv,
1874 struct v4l2_requestbuffers *rb)
1875{
1876 struct em28xx_fh *fh = priv;
1877 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001878 int rc;
1879
1880 rc = check_dev(dev);
1881 if (rc < 0)
1882 return rc;
1883
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001884 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1885 return videobuf_reqbufs(&fh->vb_vidq, rb);
1886 else
1887 return videobuf_reqbufs(&fh->vb_vbiq, rb);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001888}
1889
1890static int vidioc_querybuf(struct file *file, void *priv,
1891 struct v4l2_buffer *b)
1892{
1893 struct em28xx_fh *fh = priv;
1894 struct em28xx *dev = fh->dev;
1895 int rc;
1896
1897 rc = check_dev(dev);
1898 if (rc < 0)
1899 return rc;
1900
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001901 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1902 return videobuf_querybuf(&fh->vb_vidq, b);
1903 else {
1904 /* FIXME: I'm not sure yet whether this is a bug in zvbi or
1905 the videobuf framework, but we probably shouldn't be
1906 returning a buffer larger than that which was asked for.
1907 At a minimum, it causes a crash in zvbi since it does
1908 a memcpy based on the source buffer length */
1909 int result = videobuf_querybuf(&fh->vb_vbiq, b);
1910 b->length = 17280;
1911 return result;
1912 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001913}
1914
1915static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
1916{
1917 struct em28xx_fh *fh = priv;
1918 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001919 int rc;
1920
1921 rc = check_dev(dev);
1922 if (rc < 0)
1923 return rc;
1924
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001925 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1926 return videobuf_qbuf(&fh->vb_vidq, b);
1927 else {
1928 return videobuf_qbuf(&fh->vb_vbiq, b);
1929 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001930}
1931
1932static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
1933{
1934 struct em28xx_fh *fh = priv;
1935 struct em28xx *dev = fh->dev;
1936 int rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001937
1938 rc = check_dev(dev);
1939 if (rc < 0)
1940 return rc;
1941
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001942 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1943 return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
1944 O_NONBLOCK);
1945 else
1946 return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
1947 O_NONBLOCK);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001948}
1949
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001950#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001951static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001952{
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001953 struct em28xx_fh *fh = priv;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001954
Devin Heitmueller28abf0832009-09-01 01:54:54 -03001955 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1956 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
1957 else
1958 return videobuf_cgmbuf(&fh->vb_vbiq, mbuf, 8);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001959}
1960#endif
1961
1962
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001963/* ----------------------------------------------------------- */
1964/* RADIO ESPECIFIC IOCTLS */
1965/* ----------------------------------------------------------- */
1966
1967static int radio_querycap(struct file *file, void *priv,
1968 struct v4l2_capability *cap)
1969{
1970 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1971
1972 strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
1973 strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
Thierry MERLEcb977162009-01-20 18:01:33 -03001974 usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001975
1976 cap->version = EM28XX_VERSION_CODE;
1977 cap->capabilities = V4L2_CAP_TUNER;
1978 return 0;
1979}
1980
1981static int radio_g_tuner(struct file *file, void *priv,
1982 struct v4l2_tuner *t)
1983{
1984 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1985
1986 if (unlikely(t->index > 0))
1987 return -EINVAL;
1988
1989 strcpy(t->name, "Radio");
1990 t->type = V4L2_TUNER_RADIO;
1991
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001992 mutex_lock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03001993 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03001994 mutex_unlock(&dev->lock);
1995
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001996 return 0;
1997}
1998
1999static int radio_enum_input(struct file *file, void *priv,
2000 struct v4l2_input *i)
2001{
2002 if (i->index != 0)
2003 return -EINVAL;
2004 strcpy(i->name, "Radio");
2005 i->type = V4L2_INPUT_TYPE_TUNER;
2006
2007 return 0;
2008}
2009
2010static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
2011{
2012 if (unlikely(a->index))
2013 return -EINVAL;
2014
2015 strcpy(a->name, "Radio");
2016 return 0;
2017}
2018
2019static int radio_s_tuner(struct file *file, void *priv,
2020 struct v4l2_tuner *t)
2021{
2022 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
2023
2024 if (0 != t->index)
2025 return -EINVAL;
2026
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03002027 mutex_lock(&dev->lock);
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03002028 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03002029 mutex_unlock(&dev->lock);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002030
2031 return 0;
2032}
2033
2034static int radio_s_audio(struct file *file, void *fh,
2035 struct v4l2_audio *a)
2036{
2037 return 0;
2038}
2039
2040static int radio_s_input(struct file *file, void *fh, unsigned int i)
2041{
2042 return 0;
2043}
2044
2045static int radio_queryctrl(struct file *file, void *priv,
2046 struct v4l2_queryctrl *qc)
2047{
2048 int i;
2049
2050 if (qc->id < V4L2_CID_BASE ||
2051 qc->id >= V4L2_CID_LASTP1)
2052 return -EINVAL;
2053
Mauro Carvalho Chehabed10daa2009-07-19 09:10:06 -03002054 for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
2055 if (qc->id && qc->id == ac97_qctrl[i].id) {
2056 memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002057 return 0;
2058 }
2059 }
2060
2061 return -EINVAL;
2062}
2063
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002064/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002065 * em28xx_v4l2_open()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002066 * inits the device and starts isoc transfer
2067 */
Hans Verkuilbec43662008-12-30 06:58:20 -03002068static int em28xx_v4l2_open(struct file *filp)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002069{
Hans Verkuilbec43662008-12-30 06:58:20 -03002070 int minor = video_devdata(filp)->minor;
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002071 int errCode = 0, radio;
2072 struct em28xx *dev;
2073 enum v4l2_buf_type fh_type;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002074 struct em28xx_fh *fh;
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -03002075 enum v4l2_field field;
Markus Rechberger9c755412005-11-08 21:37:52 -08002076
Hans Verkuilbec43662008-12-30 06:58:20 -03002077 dev = em28xx_get_device(minor, &fh_type, &radio);
Mauro Carvalho Chehabefc52a92008-12-16 22:04:56 -03002078
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002079 if (NULL == dev)
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002080 return -ENODEV;
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002081
2082 mutex_lock(&dev->lock);
Markus Rechberger9c755412005-11-08 21:37:52 -08002083
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002084 em28xx_videodbg("open minor=%d type=%s users=%d\n",
Aidan Thorntond7aa8022008-04-13 14:38:47 -03002085 minor, v4l2_type_names[fh_type], dev->users);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002086
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002087
Mauro Carvalho Chehabc67ec532008-04-17 21:48:00 -03002088 fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002089 if (!fh) {
2090 em28xx_errdev("em28xx-video.c: Out of memory?!\n");
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002091 mutex_unlock(&dev->lock);
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002092 return -ENOMEM;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002093 }
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002094 fh->dev = dev;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002095 fh->radio = radio;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03002096 fh->type = fh_type;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002097 filp->private_data = fh;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002098
Aidan Thorntond7aa8022008-04-13 14:38:47 -03002099 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
Mauro Carvalho Chehabc67ec532008-04-17 21:48:00 -03002100 em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
Mauro Carvalho Chehab3687e1e2008-02-08 15:44:25 -03002101 em28xx_set_alternate(dev);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002102 em28xx_resolution_set(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002103
Mauro Carvalho Chehabc67ec532008-04-17 21:48:00 -03002104 /* Needed, since GPIO might have disabled power of
2105 some i2c device
2106 */
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002107 em28xx_wake_i2c(dev);
Mauro Carvalho Chehabc67ec532008-04-17 21:48:00 -03002108
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002109 }
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002110 if (fh->radio) {
2111 em28xx_videodbg("video_open: setting radio device\n");
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03002112 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002113 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002114
2115 dev->users++;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002116
Mauro Carvalho Chehabc2a6b542009-08-08 03:14:55 -03002117 if (dev->progressive)
2118 field = V4L2_FIELD_NONE;
2119 else
2120 field = V4L2_FIELD_INTERLACED;
2121
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002122 videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
2123 NULL, &dev->slock,
2124 V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
2125 sizeof(struct em28xx_buffer), fh);
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002126
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002127 videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
2128 NULL, &dev->slock,
2129 V4L2_BUF_TYPE_VBI_CAPTURE,
2130 V4L2_FIELD_SEQ_TB,
2131 sizeof(struct em28xx_buffer), fh);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002132
Ingo Molnar3593cab2006-02-07 06:49:14 -02002133 mutex_unlock(&dev->lock);
Mauro Carvalho Chehabc67ec532008-04-17 21:48:00 -03002134
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002135 return errCode;
2136}
2137
2138/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002139 * em28xx_realease_resources()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002140 * unregisters the v4l2,i2c and usb devices
2141 * called when the device gets disconected or at module unload
2142*/
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002143void em28xx_release_analog_resources(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002144{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002145
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002146 /*FIXME: I2C IR should be disconnected */
2147
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002148 if (dev->radio_dev) {
2149 if (-1 != dev->radio_dev->minor)
2150 video_unregister_device(dev->radio_dev);
2151 else
2152 video_device_release(dev->radio_dev);
2153 dev->radio_dev = NULL;
2154 }
2155 if (dev->vbi_dev) {
Devin Heitmueller49240442008-11-12 02:05:15 -03002156 em28xx_info("V4L2 device /dev/vbi%d deregistered\n",
2157 dev->vbi_dev->num);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002158 if (-1 != dev->vbi_dev->minor)
2159 video_unregister_device(dev->vbi_dev);
2160 else
2161 video_device_release(dev->vbi_dev);
2162 dev->vbi_dev = NULL;
2163 }
2164 if (dev->vdev) {
Devin Heitmueller49240442008-11-12 02:05:15 -03002165 em28xx_info("V4L2 device /dev/video%d deregistered\n",
2166 dev->vdev->num);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002167 if (-1 != dev->vdev->minor)
2168 video_unregister_device(dev->vdev);
2169 else
2170 video_device_release(dev->vdev);
2171 dev->vdev = NULL;
2172 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002173}
2174
2175/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002176 * em28xx_v4l2_close()
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -03002177 * stops streaming and deallocates all resources allocated by the v4l2
2178 * calls and ioctls
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002179 */
Hans Verkuilbec43662008-12-30 06:58:20 -03002180static int em28xx_v4l2_close(struct file *filp)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002181{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002182 struct em28xx_fh *fh = filp->private_data;
2183 struct em28xx *dev = fh->dev;
2184 int errCode;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002185
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -08002186 em28xx_videodbg("users=%d\n", dev->users);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002187
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002188 if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002189 videobuf_stop(&fh->vb_vidq);
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002190 res_free(fh, EM28XX_RESOURCE_VIDEO);
2191 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002192
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002193 if (res_check(fh, EM28XX_RESOURCE_VBI)) {
2194 videobuf_stop(&fh->vb_vbiq);
2195 res_free(fh, EM28XX_RESOURCE_VBI);
2196 }
2197
2198 if(dev->users == 1) {
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002199 /* the device is already disconnect,
2200 free the remaining resources */
2201 if (dev->state & DEV_DISCONNECTED) {
2202 em28xx_release_resources(dev);
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002203 kfree(dev);
2204 return 0;
2205 }
2206
Mauro Carvalho Chehabeb6c9632008-12-05 10:39:12 -03002207 /* Save some power by putting tuner to sleep */
Hans Verkuil7c9fc9d2009-04-01 03:49:59 -03002208 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
Mauro Carvalho Chehabeb6c9632008-12-05 10:39:12 -03002209
Aidan Thorntond7aa8022008-04-13 14:38:47 -03002210 /* do this before setting alternate! */
2211 em28xx_uninit_isoc(dev);
Mauro Carvalho Chehab2fe3e2e2008-11-27 09:10:40 -03002212 em28xx_set_mode(dev, EM28XX_SUSPEND);
Aidan Thorntond7aa8022008-04-13 14:38:47 -03002213
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002214 /* set alternate 0 */
2215 dev->alt = 0;
2216 em28xx_videodbg("setting alternate 0\n");
2217 errCode = usb_set_interface(dev->udev, 0, 0);
2218 if (errCode < 0) {
2219 em28xx_errdev("cannot change alternate number to "
2220 "0 (error=%i)\n", errCode);
2221 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002222 }
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002223
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002224 videobuf_mmap_free(&fh->vb_vidq);
2225 videobuf_mmap_free(&fh->vb_vbiq);
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002226 kfree(fh);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002227 dev->users--;
2228 wake_up_interruptible_nr(&dev->open, 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002229 return 0;
2230}
2231
2232/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002233 * em28xx_v4l2_read()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002234 * will allocate buffers when called for the first time
2235 */
2236static ssize_t
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -03002237em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03002238 loff_t *pos)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002239{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002240 struct em28xx_fh *fh = filp->private_data;
2241 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002242 int rc;
2243
2244 rc = check_dev(dev);
2245 if (rc < 0)
2246 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002247
Mauro Carvalho Chehab9e31ced2007-11-11 01:13:49 -03002248 /* FIXME: read() is not prepared to allow changing the video
2249 resolution while streaming. Seems a bug at em28xx_set_fmt
2250 */
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03002251
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002252 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002253 if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
2254 return -EBUSY;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03002255
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002256 return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
2257 filp->f_flags & O_NONBLOCK);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002258 }
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002259
2260
2261 if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002262 if (!res_get(fh, EM28XX_RESOURCE_VBI))
2263 return -EBUSY;
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002264
2265 return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
2266 filp->f_flags & O_NONBLOCK);
2267 }
2268
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002269 return 0;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002270}
2271
2272/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002273 * em28xx_v4l2_poll()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002274 * will allocate buffers when called for the first time
2275 */
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -03002276static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002277{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002278 struct em28xx_fh *fh = filp->private_data;
2279 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002280 int rc;
2281
2282 rc = check_dev(dev);
2283 if (rc < 0)
2284 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002285
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002286 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2287 if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
2288 return POLLERR;
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002289 return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002290 } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
2291 if (!res_get(fh, EM28XX_RESOURCE_VBI))
2292 return POLLERR;
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002293 return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002294 } else {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002295 return POLLERR;
Devin Heitmueller8c873d32009-09-03 00:23:27 -03002296 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002297}
2298
2299/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002300 * em28xx_v4l2_mmap()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002301 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002302static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002303{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002304 struct em28xx_fh *fh = filp->private_data;
2305 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002306 int rc;
Markus Rechberger9c755412005-11-08 21:37:52 -08002307
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002308 rc = check_dev(dev);
2309 if (rc < 0)
2310 return rc;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002311
Devin Heitmueller91f6dce2009-09-02 22:23:23 -03002312 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
2313 rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
2314 else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
2315 rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002316
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002317 em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
2318 (unsigned long)vma->vm_start,
2319 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
2320 rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002321
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002322 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002323}
2324
Hans Verkuilbec43662008-12-30 06:58:20 -03002325static const struct v4l2_file_operations em28xx_v4l_fops = {
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002326 .owner = THIS_MODULE,
2327 .open = em28xx_v4l2_open,
2328 .release = em28xx_v4l2_close,
2329 .read = em28xx_v4l2_read,
2330 .poll = em28xx_v4l2_poll,
2331 .mmap = em28xx_v4l2_mmap,
2332 .ioctl = video_ioctl2,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002333};
2334
Hans Verkuila3998102008-07-21 02:57:38 -03002335static const struct v4l2_ioctl_ops video_ioctl_ops = {
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002336 .vidioc_querycap = vidioc_querycap,
Hans Verkuil78b526a2008-05-28 12:16:41 -03002337 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
2338 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
2339 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
2340 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002341 .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
2342 .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002343 .vidioc_g_audio = vidioc_g_audio,
2344 .vidioc_s_audio = vidioc_s_audio,
2345 .vidioc_cropcap = vidioc_cropcap,
2346
Hans Verkuil78b526a2008-05-28 12:16:41 -03002347 .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
2348 .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
2349 .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002350
2351 .vidioc_reqbufs = vidioc_reqbufs,
2352 .vidioc_querybuf = vidioc_querybuf,
2353 .vidioc_qbuf = vidioc_qbuf,
2354 .vidioc_dqbuf = vidioc_dqbuf,
2355 .vidioc_s_std = vidioc_s_std,
Mauro Carvalho Chehabd96ecda2009-08-06 21:53:59 -03002356 .vidioc_g_parm = vidioc_g_parm,
2357 .vidioc_s_parm = vidioc_s_parm,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002358 .vidioc_enum_input = vidioc_enum_input,
2359 .vidioc_g_input = vidioc_g_input,
2360 .vidioc_s_input = vidioc_s_input,
2361 .vidioc_queryctrl = vidioc_queryctrl,
2362 .vidioc_g_ctrl = vidioc_g_ctrl,
2363 .vidioc_s_ctrl = vidioc_s_ctrl,
2364 .vidioc_streamon = vidioc_streamon,
2365 .vidioc_streamoff = vidioc_streamoff,
2366 .vidioc_g_tuner = vidioc_g_tuner,
2367 .vidioc_s_tuner = vidioc_s_tuner,
2368 .vidioc_g_frequency = vidioc_g_frequency,
2369 .vidioc_s_frequency = vidioc_s_frequency,
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03002370#ifdef CONFIG_VIDEO_ADV_DEBUG
2371 .vidioc_g_register = vidioc_g_register,
2372 .vidioc_s_register = vidioc_s_register,
Mauro Carvalho Chehab14983d82008-12-22 20:58:41 -03002373 .vidioc_g_chip_ident = vidioc_g_chip_ident,
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03002374#endif
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002375#ifdef CONFIG_VIDEO_V4L1_COMPAT
2376 .vidiocgmbuf = vidiocgmbuf,
2377#endif
Hans Verkuila3998102008-07-21 02:57:38 -03002378};
2379
2380static const struct video_device em28xx_video_template = {
2381 .fops = &em28xx_v4l_fops,
2382 .release = video_device_release,
2383 .ioctl_ops = &video_ioctl_ops,
2384
2385 .minor = -1,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002386
2387 .tvnorms = V4L2_STD_ALL,
Devin Heitmueller28abf0832009-09-01 01:54:54 -03002388 /* FIXME: we need this to be NTSC for VBI to work - it should
2389 be moved to a per-board definition */
2390 .current_norm = V4L2_STD_NTSC,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002391};
2392
Hans Verkuilbec43662008-12-30 06:58:20 -03002393static const struct v4l2_file_operations radio_fops = {
Hans Verkuila3998102008-07-21 02:57:38 -03002394 .owner = THIS_MODULE,
2395 .open = em28xx_v4l2_open,
2396 .release = em28xx_v4l2_close,
2397 .ioctl = video_ioctl2,
Hans Verkuila3998102008-07-21 02:57:38 -03002398};
2399
2400static const struct v4l2_ioctl_ops radio_ioctl_ops = {
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002401 .vidioc_querycap = radio_querycap,
2402 .vidioc_g_tuner = radio_g_tuner,
2403 .vidioc_enum_input = radio_enum_input,
2404 .vidioc_g_audio = radio_g_audio,
2405 .vidioc_s_tuner = radio_s_tuner,
2406 .vidioc_s_audio = radio_s_audio,
2407 .vidioc_s_input = radio_s_input,
2408 .vidioc_queryctrl = radio_queryctrl,
2409 .vidioc_g_ctrl = vidioc_g_ctrl,
2410 .vidioc_s_ctrl = vidioc_s_ctrl,
2411 .vidioc_g_frequency = vidioc_g_frequency,
2412 .vidioc_s_frequency = vidioc_s_frequency,
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03002413#ifdef CONFIG_VIDEO_ADV_DEBUG
2414 .vidioc_g_register = vidioc_g_register,
2415 .vidioc_s_register = vidioc_s_register,
2416#endif
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002417};
2418
Hans Verkuila3998102008-07-21 02:57:38 -03002419static struct video_device em28xx_radio_template = {
2420 .name = "em28xx-radio",
Hans Verkuila3998102008-07-21 02:57:38 -03002421 .fops = &radio_fops,
2422 .ioctl_ops = &radio_ioctl_ops,
2423 .minor = -1,
2424};
2425
Douglas Schilling Landgraf6ea54d92008-04-17 21:41:10 -03002426/******************************** usb interface ******************************/
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002427
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002428
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002429
Adrian Bunk532fe652008-01-28 22:10:48 -03002430static struct video_device *em28xx_vdev_init(struct em28xx *dev,
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -03002431 const struct video_device *template,
2432 const char *type_name)
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002433{
2434 struct video_device *vfd;
2435
2436 vfd = video_device_alloc();
2437 if (NULL == vfd)
2438 return NULL;
Douglas Schilling Landgraff2cf2502009-03-31 17:10:58 -03002439
2440 *vfd = *template;
2441 vfd->minor = -1;
2442 vfd->v4l2_dev = &dev->v4l2_dev;
2443 vfd->release = video_device_release;
2444 vfd->debug = video_debug;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002445
2446 snprintf(vfd->name, sizeof(vfd->name), "%s %s",
2447 dev->name, type_name);
2448
2449 return vfd;
2450}
2451
Mauro Carvalho Chehab2e5ef2d2008-12-28 22:26:36 -03002452int em28xx_register_analog_devices(struct em28xx *dev)
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002453{
Robert Krakora6e7b9ea2009-01-18 21:59:34 -03002454 u8 val;
Mauro Carvalho Chehab2e5ef2d2008-12-28 22:26:36 -03002455 int ret;
2456
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002457 printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n",
2458 dev->name,
2459 (EM28XX_VERSION_CODE >> 16) & 0xff,
2460 (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
2461
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002462 /* set default norm */
2463 dev->norm = em28xx_video_template.current_norm;
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002464 dev->interlaced = EM28XX_INTERLACED_DEFAULT;
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03002465 dev->ctl_input = 0;
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002466
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03002467 /* Analog specific initialization */
2468 dev->format = &format[0];
Mauro Carvalho Chehabed5f1432009-07-02 17:34:04 -03002469 em28xx_set_video_format(dev, format[0].fourcc,
2470 norm_maxw(dev), norm_maxh(dev));
2471
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03002472 video_mux(dev, dev->ctl_input);
2473
2474 /* Audio defaults */
2475 dev->mute = 1;
2476 dev->volume = 0x1f;
2477
2478 /* enable vbi capturing */
2479
2480/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -03002481 val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
2482 em28xx_write_reg(dev, EM28XX_R0F_XCLK,
2483 (EM28XX_XCLK_AUDIO_UNMUTE | val));
Mauro Carvalho Chehab24c3c412009-01-07 22:49:25 -03002484 em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
2485
2486 em28xx_set_outfmt(dev);
2487 em28xx_colorlevels_set_default(dev);
2488 em28xx_compression_disable(dev);
Mauro Carvalho Chehab1a23f812008-12-28 22:18:14 -03002489
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002490 /* allocate and fill video video_device struct */
2491 dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
2492 if (!dev->vdev) {
2493 em28xx_errdev("cannot allocate video_device.\n");
2494 return -ENODEV;
2495 }
2496
2497 /* register v4l2 video video_device */
2498 ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
2499 video_nr[dev->devno]);
2500 if (ret) {
2501 em28xx_errdev("unable to register video device (error=%i).\n",
2502 ret);
2503 return ret;
2504 }
2505
2506 /* Allocate and fill vbi video_device struct */
Devin Heitmueller290c0cf2009-09-11 00:01:06 -03002507 if (em28xx_vbi_supported(dev) == 1) {
2508 dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
2509 "vbi");
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002510
Devin Heitmueller290c0cf2009-09-11 00:01:06 -03002511 /* register v4l2 vbi video_device */
2512 ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
2513 vbi_nr[dev->devno]);
2514 if (ret < 0) {
2515 em28xx_errdev("unable to register vbi device\n");
2516 return ret;
2517 }
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002518 }
2519
2520 if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
Nicola Soranzoa1a6ee72009-02-10 23:28:24 -03002521 dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
2522 "radio");
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002523 if (!dev->radio_dev) {
2524 em28xx_errdev("cannot allocate video_device.\n");
2525 return -ENODEV;
2526 }
2527 ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
2528 radio_nr[dev->devno]);
2529 if (ret < 0) {
2530 em28xx_errdev("can't register radio device\n");
2531 return ret;
2532 }
2533 em28xx_info("Registered radio device as /dev/radio%d\n",
2534 dev->radio_dev->num);
2535 }
2536
Devin Heitmueller290c0cf2009-09-11 00:01:06 -03002537 em28xx_info("V4L2 video device registered as /dev/video%d\n",
2538 dev->vdev->num);
2539
2540 if (dev->vbi_dev)
2541 em28xx_info("V4L2 VBI device registered as /dev/vbi%d\n",
2542 dev->vbi_dev->num);
Mauro Carvalho Chehab818a5572008-11-20 10:30:26 -03002543
2544 return 0;
2545}