blob: 362251838d4b0f7f4a76f44fc139f9759f5f3162 [file] [log] [blame]
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001/*
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08002 em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08003
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08004 Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
5 Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab2e7c6dc2006-04-03 07:53:40 -03006 Mauro Carvalho Chehab <mchehab@infradead.org>
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -08007 Sascha Sommer <saschasommer@freenet.de>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08008
Mauro Carvalho Chehab439090d2006-01-23 17:10:54 -02009 Some parts based on SN9C10x PC Camera Controllers GPL driver made
10 by Luca Risolia <luca.risolia@studio.unibo.it>
11
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080012 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#include <linux/init.h>
28#include <linux/list.h>
29#include <linux/module.h>
30#include <linux/kernel.h>
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020031#include <linux/bitmap.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080032#include <linux/usb.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080033#include <linux/i2c.h>
Mauro Carvalho Chehabb296fc62005-11-08 21:38:37 -080034#include <linux/version.h>
Trent Piepho6d35c8f2007-11-01 01:16:09 -030035#include <linux/mm.h>
Ingo Molnar1e4baed2006-01-15 07:52:23 -020036#include <linux/mutex.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080037
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080038#include "em28xx.h"
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -020039#include <media/v4l2-common.h>
Hans Verkuil2474ed42006-03-19 12:35:57 -030040#include <media/msp3400.h>
Mauro Carvalho Chehabed086312008-01-24 06:59:20 -030041#include <media/tuner.h>
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080042
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080043#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
44 "Markus Rechberger <mrechberger@gmail.com>, " \
Mauro Carvalho Chehab2e7c6dc2006-04-03 07:53:40 -030045 "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080046 "Sascha Sommer <saschasommer@freenet.de>"
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080047
Mauro Carvalho Chehabf7abcd32005-11-08 21:38:25 -080048#define DRIVER_NAME "em28xx"
49#define DRIVER_DESC "Empia em28xx based USB video device driver"
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -030050#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080051
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080052#define em28xx_videodbg(fmt, arg...) do {\
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080053 if (video_debug) \
54 printk(KERN_INFO "%s %s :"fmt, \
Harvey Harrisond80e1342008-04-08 23:20:00 -030055 dev->name, __func__ , ##arg); } while (0)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080056
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030057static unsigned int isoc_debug;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -030058module_param(isoc_debug, int, 0644);
59MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030060
61#define em28xx_isocdbg(fmt, arg...) do {\
62 if (isoc_debug) \
63 printk(KERN_INFO "%s %s :"fmt, \
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -030064 dev->name, __func__ , ##arg); } while (0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030065
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080066MODULE_AUTHOR(DRIVER_AUTHOR);
67MODULE_DESCRIPTION(DRIVER_DESC);
68MODULE_LICENSE("GPL");
69
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080070static LIST_HEAD(em28xx_devlist);
Markus Rechberger9c755412005-11-08 21:37:52 -080071
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -080072static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020073static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -030074static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
75static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
76
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080077module_param_array(card, int, NULL, 0444);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020078module_param_array(video_nr, int, NULL, 0444);
79module_param_array(vbi_nr, int, NULL, 0444);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -030080module_param_array(radio_nr, int, NULL, 0444);
81MODULE_PARM_DESC(card, "card type");
82MODULE_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;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080087module_param(video_debug,int,0644);
88MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
89
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020090/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
91static unsigned long em28xx_devused;
92
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080093/* supported controls */
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -020094/* Common to all boards */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080095static struct v4l2_queryctrl em28xx_qctrl[] = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080096 {
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -020097 .id = V4L2_CID_AUDIO_VOLUME,
98 .type = V4L2_CTRL_TYPE_INTEGER,
99 .name = "Volume",
100 .minimum = 0x0,
101 .maximum = 0x1f,
102 .step = 0x1,
103 .default_value = 0x1f,
104 .flags = 0,
105 },{
106 .id = V4L2_CID_AUDIO_MUTE,
107 .type = V4L2_CTRL_TYPE_BOOLEAN,
108 .name = "Mute",
109 .minimum = 0,
110 .maximum = 1,
111 .step = 1,
112 .default_value = 1,
113 .flags = 0,
114 }
115};
116
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800117static struct usb_driver em28xx_usb_driver;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800118
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300119/* ------------------------------------------------------------------
120 DMA and thread functions
121 ------------------------------------------------------------------*/
122
123/*
124 * Announces that a buffer were filled and request the next
125 */
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300126static inline void buffer_filled(struct em28xx *dev,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300127 struct em28xx_dmaqueue *dma_q,
128 struct em28xx_buffer *buf)
129{
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300130 /* Advice that buffer was filled */
131 em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
132 buf->vb.state = VIDEOBUF_DONE;
133 buf->vb.field_count++;
134 do_gettimeofday(&buf->vb.ts);
135
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300136 dev->isoc_ctl.buf = NULL;
137
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300138 list_del(&buf->vb.queue);
139 wake_up(&buf->vb.done);
140}
141
142/*
143 * Identify the buffer header type and properly handles
144 */
145static void em28xx_copy_video(struct em28xx *dev,
146 struct em28xx_dmaqueue *dma_q,
147 struct em28xx_buffer *buf,
148 unsigned char *p,
149 unsigned char *outp, unsigned long len)
150{
151 void *fieldstart, *startwrite, *startread;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300152 int linesdone, currlinedone, offset, lencopy, remain;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300153 int bytesperline = dev->width << 1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300154
155 if (dma_q->pos + len > buf->vb.size)
156 len = buf->vb.size - dma_q->pos;
157
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300158 if (p[0] != 0x88 && p[0] != 0x22) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300159 em28xx_isocdbg("frame is not complete\n");
160 len += 4;
161 } else
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300162 p += 4;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300163
164 startread = p;
165 remain = len;
166
167 /* Interlaces frame */
168 if (buf->top_field)
169 fieldstart = outp;
170 else
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300171 fieldstart = outp + bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300172
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300173 linesdone = dma_q->pos / bytesperline;
174 currlinedone = dma_q->pos % bytesperline;
175 offset = linesdone * bytesperline * 2 + currlinedone;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300176 startwrite = fieldstart + offset;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300177 lencopy = bytesperline - currlinedone;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300178 lencopy = lencopy > remain ? remain : lencopy;
179
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300180 if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
Mauro Carvalho Chehabea8df7e2008-04-13 14:39:29 -0300181 em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300182 ((char *)startwrite + lencopy) -
183 ((char *)outp + buf->vb.size));
184 lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300185 }
Aidan Thorntone0fadfd342008-04-13 14:56:02 -0300186 if (lencopy <= 0)
187 return;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300188 memcpy(startwrite, startread, lencopy);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300189
190 remain -= lencopy;
191
192 while (remain > 0) {
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300193 startwrite += lencopy + bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300194 startread += lencopy;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300195 if (bytesperline > remain)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300196 lencopy = remain;
197 else
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300198 lencopy = bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300199
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300200 if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
Mauro Carvalho Chehabea8df7e2008-04-13 14:39:29 -0300201 em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300202 ((char *)startwrite + lencopy) -
203 ((char *)outp + buf->vb.size));
204 lencopy = remain = (char *)outp + buf->vb.size -
205 (char *)startwrite;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300206 }
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300207 if (lencopy <= 0)
208 break;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300209
210 memcpy(startwrite, startread, lencopy);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300211
212 remain -= lencopy;
213 }
214
215 dma_q->pos += len;
216}
217
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300218static inline void print_err_status(struct em28xx *dev,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300219 int packet, int status)
220{
221 char *errmsg = "Unknown";
222
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300223 switch (status) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300224 case -ENOENT:
225 errmsg = "unlinked synchronuously";
226 break;
227 case -ECONNRESET:
228 errmsg = "unlinked asynchronuously";
229 break;
230 case -ENOSR:
231 errmsg = "Buffer error (overrun)";
232 break;
233 case -EPIPE:
234 errmsg = "Stalled (device not responding)";
235 break;
236 case -EOVERFLOW:
237 errmsg = "Babble (bad cable?)";
238 break;
239 case -EPROTO:
240 errmsg = "Bit-stuff error (bad cable?)";
241 break;
242 case -EILSEQ:
243 errmsg = "CRC/Timeout (could be anything)";
244 break;
245 case -ETIME:
246 errmsg = "Device does not respond";
247 break;
248 }
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300249 if (packet < 0) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300250 em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
251 } else {
252 em28xx_isocdbg("URB packet %d, status %d [%s].\n",
253 packet, status, errmsg);
254 }
255}
256
257/*
258 * video-buf generic routine to get the next available buffer
259 */
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300260static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300261 struct em28xx_buffer **buf)
262{
263 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300264 char *outp;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300265
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300266 if (list_empty(&dma_q->active)) {
267 em28xx_isocdbg("No active queue to serve\n");
268 dev->isoc_ctl.buf = NULL;
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300269 *buf = NULL;
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300270 return;
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300271 }
272
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300273 /* Get the next buffer */
274 *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
275
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300276 /* Cleans up buffer - Usefull for testing for frame/URB loss */
277 outp = videobuf_to_vmalloc(&(*buf)->vb);
278 memset(outp, 0, (*buf)->vb.size);
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300279
280 dev->isoc_ctl.buf = *buf;
281
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300282 return;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300283}
284
285/*
286 * Controls the isoc copy of each urb packet
287 */
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300288static inline int em28xx_isoc_copy(struct urb *urb)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300289{
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300290 struct em28xx_buffer *buf;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300291 struct em28xx_dmaqueue *dma_q = urb->context;
292 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300293 unsigned char *outp = NULL;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300294 int i, len = 0, rc = 1;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300295 unsigned char *p;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300296
297 if (!dev)
298 return 0;
299
300 if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
301 return 0;
302
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300303 if (urb->status < 0) {
304 print_err_status(dev, -1, urb->status);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300305 if (urb->status == -ENOENT)
306 return 0;
307 }
308
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300309 buf = dev->isoc_ctl.buf;
310 if (buf != NULL)
311 outp = videobuf_to_vmalloc(&buf->vb);
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300312
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300313 for (i = 0; i < urb->number_of_packets; i++) {
314 int status = urb->iso_frame_desc[i].status;
315
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300316 if (status < 0) {
317 print_err_status(dev, i, status);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300318 if (urb->iso_frame_desc[i].status != -EPROTO)
319 continue;
320 }
321
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300322 len = urb->iso_frame_desc[i].actual_length - 4;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300323
324 if (urb->iso_frame_desc[i].actual_length <= 0) {
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300325 /* em28xx_isocdbg("packet %d is empty",i); - spammy */
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300326 continue;
327 }
328 if (urb->iso_frame_desc[i].actual_length >
329 dev->max_pkt_size) {
330 em28xx_isocdbg("packet bigger than packet size");
331 continue;
332 }
333
334 p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300335
336 /* FIXME: incomplete buffer checks where removed to make
337 logic simpler. Impacts of those changes should be evaluated
338 */
Mauro Carvalho Chehabb4916f82008-04-13 15:09:14 -0300339 if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
340 em28xx_isocdbg("VBI HEADER!!!\n");
341 /* FIXME: Should add vbi copy */
342 continue;
343 }
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300344 if (p[0] == 0x22 && p[1] == 0x5a) {
Mauro Carvalho Chehab78bb3942008-04-13 14:56:25 -0300345 em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
346 len, (p[2] & 1)? "odd" : "even");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300347
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300348 if (!(p[2] & 1)) {
349 if (buf != NULL)
350 buffer_filled(dev, dma_q, buf);
351 get_next_buf(dma_q, &buf);
352 if (buf == NULL)
353 outp = NULL;
354 else
355 outp = videobuf_to_vmalloc(&buf->vb);
Aidan Thorntone0fadfd342008-04-13 14:56:02 -0300356 }
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300357
358 if (buf != NULL) {
359 if (p[2] & 1)
360 buf->top_field = 0;
361 else
362 buf->top_field = 1;
363 }
Mauro Carvalho Chehabb4916f82008-04-13 15:09:14 -0300364
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300365 dma_q->pos = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300366 }
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300367 if (buf != NULL)
368 em28xx_copy_video(dev, dma_q, buf, p, outp, len);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300369 }
370 return rc;
371}
372
373/* ------------------------------------------------------------------
374 URB control
375 ------------------------------------------------------------------*/
376
377/*
378 * IRQ callback, called by URB callback
379 */
380static void em28xx_irq_callback(struct urb *urb)
381{
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300382 struct em28xx_dmaqueue *dma_q = urb->context;
383 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300384 int rc, i;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300385
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300386 /* Copy data from URB */
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300387 spin_lock(&dev->slock);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300388 rc = em28xx_isoc_copy(urb);
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300389 spin_unlock(&dev->slock);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300390
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300391 /* Reset urb buffers */
392 for (i = 0; i < urb->number_of_packets; i++) {
393 urb->iso_frame_desc[i].status = 0;
394 urb->iso_frame_desc[i].actual_length = 0;
395 }
396 urb->status = 0;
397
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300398 urb->status = usb_submit_urb(urb, GFP_ATOMIC);
399 if (urb->status) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300400 em28xx_err("urb resubmit failed (error=%i)\n",
401 urb->status);
402 }
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300403}
404
405/*
406 * Stop and Deallocate URBs
407 */
408static void em28xx_uninit_isoc(struct em28xx *dev)
409{
410 struct urb *urb;
411 int i;
412
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300413 em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
414
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300415 dev->isoc_ctl.nfields = -1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300416 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300417 urb = dev->isoc_ctl.urb[i];
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300418 if (urb) {
419 usb_kill_urb(urb);
420 usb_unlink_urb(urb);
421 if (dev->isoc_ctl.transfer_buffer[i]) {
422 usb_buffer_free(dev->udev,
423 urb->transfer_buffer_length,
424 dev->isoc_ctl.transfer_buffer[i],
425 urb->transfer_dma);
426 }
427 usb_free_urb(urb);
428 dev->isoc_ctl.urb[i] = NULL;
429 }
430 dev->isoc_ctl.transfer_buffer[i] = NULL;
431 }
432
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300433 kfree(dev->isoc_ctl.urb);
434 kfree(dev->isoc_ctl.transfer_buffer);
435 dev->isoc_ctl.urb = NULL;
436 dev->isoc_ctl.transfer_buffer = NULL;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300437
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300438 dev->isoc_ctl.num_bufs = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300439
Mauro Carvalho Chehab47625da2008-04-13 14:40:10 -0300440 em28xx_capture_start(dev, 0);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300441}
442
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300443/*
444 * Allocate URBs and start IRQ
445 */
446static int em28xx_prepare_isoc(struct em28xx *dev, int max_packets,
447 int num_bufs)
448{
449 struct em28xx_dmaqueue *dma_q = &dev->vidq;
450 int i;
451 int sb_size, pipe;
452 struct urb *urb;
453 int j, k;
454
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300455 em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
456
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300457 /* De-allocates all pending stuff */
458 em28xx_uninit_isoc(dev);
459
460 dev->isoc_ctl.num_bufs = num_bufs;
461
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300462 dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300463 if (!dev->isoc_ctl.urb) {
464 em28xx_errdev("cannot alloc memory for usb buffers\n");
465 return -ENOMEM;
466 }
467
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300468 dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300469 GFP_KERNEL);
470 if (!dev->isoc_ctl.urb) {
471 em28xx_errdev("cannot allocate memory for usbtransfer\n");
472 kfree(dev->isoc_ctl.urb);
473 return -ENOMEM;
474 }
475
476 dev->isoc_ctl.max_pkt_size = dev->max_pkt_size;
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300477 dev->isoc_ctl.buf = NULL;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300478
479 sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
480
481 /* allocate urbs and transfer buffers */
482 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
483 urb = usb_alloc_urb(max_packets, GFP_KERNEL);
484 if (!urb) {
485 em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
486 em28xx_uninit_isoc(dev);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300487 return -ENOMEM;
488 }
489 dev->isoc_ctl.urb[i] = urb;
490
491 dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
492 sb_size, GFP_KERNEL, &urb->transfer_dma);
493 if (!dev->isoc_ctl.transfer_buffer[i]) {
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300494 em28xx_err("unable to allocate %i bytes for transfer"
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300495 " buffer %i%s\n",
496 sb_size, i,
497 in_interrupt()?" while in int":"");
498 em28xx_uninit_isoc(dev);
499 return -ENOMEM;
500 }
501 memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
502
503 /* FIXME: this is a hack - should be
504 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
505 should also be using 'desc.bInterval'
506 */
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300507 pipe = usb_rcvisocpipe(dev->udev, 0x82);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300508 usb_fill_int_urb(urb, dev->udev, pipe,
509 dev->isoc_ctl.transfer_buffer[i], sb_size,
510 em28xx_irq_callback, dma_q, 1);
511
512 urb->number_of_packets = max_packets;
513 urb->transfer_flags = URB_ISO_ASAP;
514
515 k = 0;
516 for (j = 0; j < max_packets; j++) {
517 urb->iso_frame_desc[j].offset = k;
518 urb->iso_frame_desc[j].length =
519 dev->isoc_ctl.max_pkt_size;
520 k += dev->isoc_ctl.max_pkt_size;
521 }
522 }
523
524 return 0;
525}
526
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300527static int em28xx_start_thread(struct em28xx_dmaqueue *dma_q)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300528{
529 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300530 int i, rc = 0;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300531
532 em28xx_videodbg("Called em28xx_start_thread\n");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300533
534 init_waitqueue_head(&dma_q->wq);
535
Mauro Carvalho Chehab47625da2008-04-13 14:40:10 -0300536 em28xx_capture_start(dev, 1);
537
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300538 /* submit urbs and enables IRQ */
539 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
540 rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
541 if (rc) {
542 em28xx_err("submit of urb %i failed (error=%i)\n", i,
543 rc);
544 em28xx_uninit_isoc(dev);
545 return rc;
546 }
547 }
548
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300549 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300550 return rc;
551
552 return 0;
553}
554
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300555/* ------------------------------------------------------------------
556 Videobuf operations
557 ------------------------------------------------------------------*/
558
559static int
560buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
561{
562 struct em28xx_fh *fh = vq->priv_data;
563
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300564 *size = 16 * fh->dev->width * fh->dev->height >> 3;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300565 if (0 == *count)
566 *count = EM28XX_DEF_BUF;
567
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300568 if (*count < EM28XX_MIN_BUF)
569 *count = EM28XX_MIN_BUF;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300570
571 return 0;
572}
573
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300574/* This is called *without* dev->slock held; please keep it that way */
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300575static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
576{
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300577 struct em28xx_fh *fh = vq->priv_data;
578 struct em28xx *dev = fh->dev;
579 unsigned long flags = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300580 if (in_interrupt())
581 BUG();
582
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300583 /* We used to wait for the buffer to finish here, but this didn't work
584 because, as we were keeping the state as VIDEOBUF_QUEUED,
585 videobuf_queue_cancel marked it as finished for us.
586 (Also, it could wedge forever if the hardware was misconfigured.)
587
588 This should be safe; by the time we get here, the buffer isn't
589 queued anymore. If we ever start marking the buffers as
590 VIDEOBUF_ACTIVE, it won't be, though.
591 */
592 spin_lock_irqsave(&dev->slock, flags);
593 if (dev->isoc_ctl.buf == buf)
594 dev->isoc_ctl.buf = NULL;
595 spin_unlock_irqrestore(&dev->slock, flags);
596
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300597 videobuf_vmalloc_free(&buf->vb);
598 buf->vb.state = VIDEOBUF_NEEDS_INIT;
599}
600
601static int
602buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
603 enum v4l2_field field)
604{
605 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300606 struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300607 struct em28xx *dev = fh->dev;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300608 struct em28xx_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300609 int rc = 0, urb_init = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300610
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300611 /* FIXME: It assumes depth = 16 */
612 /* The only currently supported format is 16 bits/pixel */
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300613 buf->vb.size = 16 * dev->width * dev->height >> 3;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300614
615 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
616 return -EINVAL;
617
Brandon Philips05612972008-04-13 14:57:01 -0300618 buf->vb.width = dev->width;
619 buf->vb.height = dev->height;
620 buf->vb.field = field;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300621
622 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300623 rc = videobuf_iolock(vq, &buf->vb, NULL);
624 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300625 goto fail;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300626 }
627
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300628 if (!dev->isoc_ctl.num_bufs)
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300629 urb_init = 1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300630
631 if (urb_init) {
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300632 rc = em28xx_prepare_isoc(dev, EM28XX_NUM_PACKETS,
633 EM28XX_NUM_BUFS);
634 if (rc < 0)
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300635 goto fail;
636
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300637 rc = em28xx_start_thread(vidq);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300638 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300639 goto fail;
640 }
641
642 buf->vb.state = VIDEOBUF_PREPARED;
643 return 0;
644
645fail:
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300646 free_buffer(vq, buf);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300647 return rc;
648}
649
650static void
651buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
652{
653 struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
654 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300655 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300656 struct em28xx_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300657
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300658 buf->vb.state = VIDEOBUF_QUEUED;
659 list_add_tail(&buf->vb.queue, &vidq->active);
660
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300661}
662
663static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
664{
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300665 struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300666 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300667 struct em28xx *dev = (struct em28xx *)fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300668
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300669 em28xx_isocdbg("em28xx: called buffer_release\n");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300670
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300671 free_buffer(vq, buf);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300672}
673
674static struct videobuf_queue_ops em28xx_video_qops = {
675 .buf_setup = buffer_setup,
676 .buf_prepare = buffer_prepare,
677 .buf_queue = buffer_queue,
678 .buf_release = buffer_release,
679};
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800680
681/********************* v4l2 interface ******************************************/
682
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800683/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800684 * em28xx_config()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800685 * inits registers with sane defaults
686 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800687static int em28xx_config(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800688{
689
690 /* Sets I2C speed to 100 KHz */
Sascha Sommer2b2c93a2007-11-03 16:48:01 -0300691 if (!dev->is_em2800)
692 em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800693
694 /* enable vbi capturing */
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -0200695
Markus Rechberger9475fb12006-02-27 00:07:34 -0300696/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
697/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -0200698 em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
699
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800700 dev->mute = 1; /* maybe not the right place... */
701 dev->volume = 0x1f;
Mauro Carvalho Chehab539c96d2008-01-05 09:53:54 -0300702
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800703 em28xx_outfmt_set_yuv422(dev);
704 em28xx_colorlevels_set_default(dev);
705 em28xx_compression_disable(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800706
707 return 0;
708}
709
710/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800711 * em28xx_config_i2c()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800712 * configure i2c attached devices
713 */
Adrian Bunk943a4902005-12-01 00:51:35 -0800714static void em28xx_config_i2c(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800715{
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300716 struct v4l2_routing route;
717
718 route.input = INPUT(dev->ctl_input)->vmux;
719 route.output = 0;
Al Viro663d1ba2006-10-10 22:48:37 +0100720 em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300721 em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300722 em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800723}
724
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800725static void video_mux(struct em28xx *dev, int index)
726{
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300727 struct v4l2_routing route;
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800728
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300729 route.input = INPUT(index)->vmux;
730 route.output = 0;
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800731 dev->ctl_input = index;
732 dev->ctl_ainput = INPUT(index)->amux;
733
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300734 em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800735
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800736 if (dev->has_msp34xx) {
Mauro Carvalho Chehab9bb13a62006-01-09 15:25:37 -0200737 if (dev->i2s_speed)
738 em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
Hans Verkuil2474ed42006-03-19 12:35:57 -0300739 route.input = dev->ctl_ainput;
Hans Verkuil07151722006-04-01 18:03:23 -0300740 route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
Hans Verkuil2474ed42006-03-19 12:35:57 -0300741 /* Note: this is msp3400 specific */
742 em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800743 }
Mauro Carvalho Chehab539c96d2008-01-05 09:53:54 -0300744
Mauro Carvalho Chehab00b87302008-02-06 18:34:13 -0300745 em28xx_audio_analog_set(dev);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800746}
747
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300748/* Usage lock check functions */
749static int res_get(struct em28xx_fh *fh)
750{
751 struct em28xx *dev = fh->dev;
752 int rc = 0;
753
754 /* This instance already has stream_on */
755 if (fh->stream_on)
756 return rc;
757
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300758 if (dev->stream_on)
Mauro Carvalho Chehabe74153d2008-04-13 14:55:38 -0300759 return -EINVAL;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300760
Mauro Carvalho Chehabe74153d2008-04-13 14:55:38 -0300761 mutex_lock(&dev->lock);
762 dev->stream_on = 1;
763 fh->stream_on = 1;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300764 mutex_unlock(&dev->lock);
765 return rc;
766}
767
768static int res_check(struct em28xx_fh *fh)
769{
770 return (fh->stream_on);
771}
772
773static void res_free(struct em28xx_fh *fh)
774{
775 struct em28xx *dev = fh->dev;
776
777 mutex_lock(&dev->lock);
778 fh->stream_on = 0;
779 dev->stream_on = 0;
780 mutex_unlock(&dev->lock);
781}
782
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800783/*
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300784 * em28xx_get_ctrl()
785 * return the current saturation, brightness or contrast, mute state
786 */
787static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
788{
789 switch (ctrl->id) {
790 case V4L2_CID_AUDIO_MUTE:
791 ctrl->value = dev->mute;
792 return 0;
793 case V4L2_CID_AUDIO_VOLUME:
794 ctrl->value = dev->volume;
795 return 0;
796 default:
797 return -EINVAL;
798 }
799}
800
801/*
802 * em28xx_set_ctrl()
803 * mute or set new saturation, brightness or contrast
804 */
805static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
806{
807 switch (ctrl->id) {
808 case V4L2_CID_AUDIO_MUTE:
809 if (ctrl->value != dev->mute) {
810 dev->mute = ctrl->value;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300811 return em28xx_audio_analog_set(dev);
812 }
813 return 0;
814 case V4L2_CID_AUDIO_VOLUME:
815 dev->volume = ctrl->value;
816 return em28xx_audio_analog_set(dev);
817 default:
818 return -EINVAL;
819 }
820}
821
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300822static int check_dev(struct em28xx *dev)
823{
824 if (dev->state & DEV_DISCONNECTED) {
825 em28xx_errdev("v4l2 ioctl: device not present\n");
826 return -ENODEV;
827 }
828
829 if (dev->state & DEV_MISCONFIGURED) {
830 em28xx_errdev("v4l2 ioctl: device is misconfigured; "
831 "close and open it again\n");
832 return -EIO;
833 }
834 return 0;
835}
836
837static void get_scale(struct em28xx *dev,
838 unsigned int width, unsigned int height,
839 unsigned int *hscale, unsigned int *vscale)
840{
841 unsigned int maxw = norm_maxw(dev);
842 unsigned int maxh = norm_maxh(dev);
843
844 *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
845 if (*hscale >= 0x4000)
846 *hscale = 0x3fff;
847
848 *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
849 if (*vscale >= 0x4000)
850 *vscale = 0x3fff;
851}
852
853/* ------------------------------------------------------------------
854 IOCTL vidioc handling
855 ------------------------------------------------------------------*/
856
857static int vidioc_g_fmt_cap(struct file *file, void *priv,
858 struct v4l2_format *f)
859{
860 struct em28xx_fh *fh = priv;
861 struct em28xx *dev = fh->dev;
862
863 mutex_lock(&dev->lock);
864
865 f->fmt.pix.width = dev->width;
866 f->fmt.pix.height = dev->height;
867 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300868 f->fmt.pix.bytesperline = dev->width * 2;
869 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300870 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
871
872 /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
873 f->fmt.pix.field = dev->interlaced ?
874 V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
875
876 mutex_unlock(&dev->lock);
877 return 0;
878}
879
880static int vidioc_try_fmt_cap(struct file *file, void *priv,
881 struct v4l2_format *f)
882{
883 struct em28xx_fh *fh = priv;
884 struct em28xx *dev = fh->dev;
885 int width = f->fmt.pix.width;
886 int height = f->fmt.pix.height;
887 unsigned int maxw = norm_maxw(dev);
888 unsigned int maxh = norm_maxh(dev);
889 unsigned int hscale, vscale;
890
891 /* width must even because of the YUYV format
892 height must be even because of interlacing */
893 height &= 0xfffe;
894 width &= 0xfffe;
895
896 if (height < 32)
897 height = 32;
898 if (height > maxh)
899 height = maxh;
900 if (width < 48)
901 width = 48;
902 if (width > maxw)
903 width = maxw;
904
905 mutex_lock(&dev->lock);
906
907 if (dev->is_em2800) {
908 /* the em2800 can only scale down to 50% */
909 if (height % (maxh / 2))
910 height = maxh;
911 if (width % (maxw / 2))
912 width = maxw;
913 /* according to empiatech support */
914 /* the MaxPacketSize is to small to support */
915 /* framesizes larger than 640x480 @ 30 fps */
916 /* or 640x576 @ 25 fps. As this would cut */
917 /* of a part of the image we prefer */
918 /* 360x576 or 360x480 for now */
919 if (width == maxw && height == maxh)
920 width /= 2;
921 }
922
923 get_scale(dev, width, height, &hscale, &vscale);
924
925 width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
926 height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
927
928 f->fmt.pix.width = width;
929 f->fmt.pix.height = height;
930 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
931 f->fmt.pix.bytesperline = width * 2;
932 f->fmt.pix.sizeimage = width * 2 * height;
933 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
934 f->fmt.pix.field = V4L2_FIELD_INTERLACED;
935
936 mutex_unlock(&dev->lock);
937 return 0;
938}
939
940static int vidioc_s_fmt_cap(struct file *file, void *priv,
941 struct v4l2_format *f)
942{
943 struct em28xx_fh *fh = priv;
944 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300945 int rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300946
947 rc = check_dev(dev);
948 if (rc < 0)
949 return rc;
950
951 vidioc_try_fmt_cap(file, priv, f);
952
953 mutex_lock(&dev->lock);
954
Brandon Philips05612972008-04-13 14:57:01 -0300955 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
956 em28xx_errdev("%s queue busy\n", __func__);
957 rc = -EBUSY;
958 goto out;
959 }
960
Aidan Thornton0ea13e62008-04-13 15:02:24 -0300961 if (dev->stream_on && !fh->stream_on) {
962 em28xx_errdev("%s device in use by another fh\n", __func__);
963 rc = -EBUSY;
964 goto out;
965 }
966
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300967 /* set new image size */
968 dev->width = f->fmt.pix.width;
969 dev->height = f->fmt.pix.height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300970 get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
971
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300972 em28xx_set_alternate(dev);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300973 em28xx_resolution_set(dev);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300974
Brandon Philips05612972008-04-13 14:57:01 -0300975 rc = 0;
976
977out:
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300978 mutex_unlock(&dev->lock);
Brandon Philips05612972008-04-13 14:57:01 -0300979 return rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300980}
981
982static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
983{
984 struct em28xx_fh *fh = priv;
985 struct em28xx *dev = fh->dev;
986 struct v4l2_format f;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300987 int rc;
988
989 rc = check_dev(dev);
990 if (rc < 0)
991 return rc;
992
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300993 mutex_lock(&dev->lock);
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -0300994 dev->norm = *norm;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300995 mutex_unlock(&dev->lock);
996
997 /* Adjusts width/height, if needed */
998 f.fmt.pix.width = dev->width;
999 f.fmt.pix.height = dev->height;
1000 vidioc_try_fmt_cap(file, priv, &f);
1001
1002 mutex_lock(&dev->lock);
1003
1004 /* set new image size */
1005 dev->width = f.fmt.pix.width;
1006 dev->height = f.fmt.pix.height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001007 get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
1008
1009 em28xx_resolution_set(dev);
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001010 em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001011
1012 mutex_unlock(&dev->lock);
1013 return 0;
1014}
1015
1016static const char *iname[] = {
1017 [EM28XX_VMUX_COMPOSITE1] = "Composite1",
1018 [EM28XX_VMUX_COMPOSITE2] = "Composite2",
1019 [EM28XX_VMUX_COMPOSITE3] = "Composite3",
1020 [EM28XX_VMUX_COMPOSITE4] = "Composite4",
1021 [EM28XX_VMUX_SVIDEO] = "S-Video",
1022 [EM28XX_VMUX_TELEVISION] = "Television",
1023 [EM28XX_VMUX_CABLE] = "Cable TV",
1024 [EM28XX_VMUX_DVB] = "DVB",
1025 [EM28XX_VMUX_DEBUG] = "for debug only",
1026};
1027
1028static int vidioc_enum_input(struct file *file, void *priv,
1029 struct v4l2_input *i)
1030{
1031 struct em28xx_fh *fh = priv;
1032 struct em28xx *dev = fh->dev;
1033 unsigned int n;
1034
1035 n = i->index;
1036 if (n >= MAX_EM28XX_INPUT)
1037 return -EINVAL;
1038 if (0 == INPUT(n)->type)
1039 return -EINVAL;
1040
1041 i->index = n;
1042 i->type = V4L2_INPUT_TYPE_CAMERA;
1043
1044 strcpy(i->name, iname[INPUT(n)->type]);
1045
1046 if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
1047 (EM28XX_VMUX_CABLE == INPUT(n)->type))
1048 i->type = V4L2_INPUT_TYPE_TUNER;
1049
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001050 i->std = dev->vdev->tvnorms;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001051
1052 return 0;
1053}
1054
1055static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
1056{
1057 struct em28xx_fh *fh = priv;
1058 struct em28xx *dev = fh->dev;
1059
1060 *i = dev->ctl_input;
1061
1062 return 0;
1063}
1064
1065static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
1066{
1067 struct em28xx_fh *fh = priv;
1068 struct em28xx *dev = fh->dev;
1069 int rc;
1070
1071 rc = check_dev(dev);
1072 if (rc < 0)
1073 return rc;
1074
1075 if (i >= MAX_EM28XX_INPUT)
1076 return -EINVAL;
1077 if (0 == INPUT(i)->type)
1078 return -EINVAL;
1079
1080 mutex_lock(&dev->lock);
1081
1082 video_mux(dev, i);
1083
1084 mutex_unlock(&dev->lock);
1085 return 0;
1086}
1087
1088static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
1089{
1090 struct em28xx_fh *fh = priv;
1091 struct em28xx *dev = fh->dev;
1092 unsigned int index = a->index;
1093
1094 if (a->index > 1)
1095 return -EINVAL;
1096
1097 index = dev->ctl_ainput;
1098
1099 if (index == 0) {
1100 strcpy(a->name, "Television");
1101 } else {
1102 strcpy(a->name, "Line In");
1103 }
1104 a->capability = V4L2_AUDCAP_STEREO;
1105 a->index = index;
1106
1107 return 0;
1108}
1109
1110static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
1111{
1112 struct em28xx_fh *fh = priv;
1113 struct em28xx *dev = fh->dev;
1114
1115 if (a->index != dev->ctl_ainput)
1116 return -EINVAL;
1117
1118 return 0;
1119}
1120
1121static int vidioc_queryctrl(struct file *file, void *priv,
1122 struct v4l2_queryctrl *qc)
1123{
1124 struct em28xx_fh *fh = priv;
1125 struct em28xx *dev = fh->dev;
1126 int id = qc->id;
1127 int i;
1128 int rc;
1129
1130 rc = check_dev(dev);
1131 if (rc < 0)
1132 return rc;
1133
1134 memset(qc, 0, sizeof(*qc));
1135
1136 qc->id = id;
1137
1138 if (!dev->has_msp34xx) {
1139 for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
1140 if (qc->id && qc->id == em28xx_qctrl[i].id) {
1141 memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
1142 return 0;
1143 }
1144 }
1145 }
1146 mutex_lock(&dev->lock);
1147 em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc);
1148 mutex_unlock(&dev->lock);
1149
1150 if (qc->type)
1151 return 0;
1152 else
1153 return -EINVAL;
1154}
1155
1156static int vidioc_g_ctrl(struct file *file, void *priv,
1157 struct v4l2_control *ctrl)
1158{
1159 struct em28xx_fh *fh = priv;
1160 struct em28xx *dev = fh->dev;
1161 int rc;
1162
1163 rc = check_dev(dev);
1164 if (rc < 0)
1165 return rc;
1166 mutex_lock(&dev->lock);
1167
1168 if (!dev->has_msp34xx)
1169 rc = em28xx_get_ctrl(dev, ctrl);
1170 else
1171 rc = -EINVAL;
1172
1173 if (rc == -EINVAL) {
1174 em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
1175 rc = 0;
1176 }
1177
1178 mutex_unlock(&dev->lock);
1179 return rc;
1180}
1181
1182static int vidioc_s_ctrl(struct file *file, void *priv,
1183 struct v4l2_control *ctrl)
1184{
1185 struct em28xx_fh *fh = priv;
1186 struct em28xx *dev = fh->dev;
1187 u8 i;
1188 int rc;
1189
1190 rc = check_dev(dev);
1191 if (rc < 0)
1192 return rc;
1193
1194 mutex_lock(&dev->lock);
1195
1196 if (dev->has_msp34xx)
1197 em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
1198 else {
1199 rc = 1;
1200 for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
1201 if (ctrl->id == em28xx_qctrl[i].id) {
1202 if (ctrl->value < em28xx_qctrl[i].minimum ||
1203 ctrl->value > em28xx_qctrl[i].maximum) {
1204 rc = -ERANGE;
1205 break;
1206 }
1207
1208 rc = em28xx_set_ctrl(dev, ctrl);
1209 break;
1210 }
1211 }
1212 }
1213
1214 /* Control not found - try to send it to the attached devices */
1215 if (rc == 1) {
1216 em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
1217 rc = 0;
1218 }
1219
1220 mutex_unlock(&dev->lock);
1221 return rc;
1222}
1223
1224static int vidioc_g_tuner(struct file *file, void *priv,
1225 struct v4l2_tuner *t)
1226{
1227 struct em28xx_fh *fh = priv;
1228 struct em28xx *dev = fh->dev;
1229 int rc;
1230
1231 rc = check_dev(dev);
1232 if (rc < 0)
1233 return rc;
1234
1235 if (0 != t->index)
1236 return -EINVAL;
1237
1238 strcpy(t->name, "Tuner");
1239
1240 mutex_lock(&dev->lock);
1241
1242 em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
1243
1244 mutex_unlock(&dev->lock);
1245 return 0;
1246}
1247
1248static int vidioc_s_tuner(struct file *file, void *priv,
1249 struct v4l2_tuner *t)
1250{
1251 struct em28xx_fh *fh = priv;
1252 struct em28xx *dev = fh->dev;
1253 int rc;
1254
1255 rc = check_dev(dev);
1256 if (rc < 0)
1257 return rc;
1258
1259 if (0 != t->index)
1260 return -EINVAL;
1261
1262 mutex_lock(&dev->lock);
1263
1264 em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
1265
1266 mutex_unlock(&dev->lock);
1267 return 0;
1268}
1269
1270static int vidioc_g_frequency(struct file *file, void *priv,
1271 struct v4l2_frequency *f)
1272{
1273 struct em28xx_fh *fh = priv;
1274 struct em28xx *dev = fh->dev;
1275
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001276 f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001277 f->frequency = dev->ctl_freq;
1278
1279 return 0;
1280}
1281
1282static int vidioc_s_frequency(struct file *file, void *priv,
1283 struct v4l2_frequency *f)
1284{
1285 struct em28xx_fh *fh = priv;
1286 struct em28xx *dev = fh->dev;
1287 int rc;
1288
1289 rc = check_dev(dev);
1290 if (rc < 0)
1291 return rc;
1292
1293 if (0 != f->tuner)
1294 return -EINVAL;
1295
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001296 if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
1297 return -EINVAL;
1298 if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001299 return -EINVAL;
1300
1301 mutex_lock(&dev->lock);
1302
1303 dev->ctl_freq = f->frequency;
1304 em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
1305
1306 mutex_unlock(&dev->lock);
1307 return 0;
1308}
1309
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001310#ifdef CONFIG_VIDEO_ADV_DEBUG
1311static int em28xx_reg_len(int reg)
1312{
1313 switch (reg) {
1314 case AC97LSB_REG:
1315 case HSCALELOW_REG:
1316 case VSCALELOW_REG:
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001317 return 2;
1318 default:
1319 return 1;
1320 }
1321}
1322
1323static int vidioc_g_register(struct file *file, void *priv,
1324 struct v4l2_register *reg)
1325{
1326 struct em28xx_fh *fh = priv;
1327 struct em28xx *dev = fh->dev;
1328 int ret;
1329
1330 if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
1331 return -EINVAL;
1332
1333 if (em28xx_reg_len(reg->reg) == 1) {
1334 ret = em28xx_read_reg(dev, reg->reg);
1335 if (ret < 0)
1336 return ret;
1337
1338 reg->val = ret;
1339 } else {
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001340 u64 val = 0;
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001341 ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
1342 reg->reg, (char *)&val, 2);
1343 if (ret < 0)
1344 return ret;
1345
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001346 reg->val = cpu_to_le64((__u64)val);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001347 }
1348
1349 return 0;
1350}
1351
1352static int vidioc_s_register(struct file *file, void *priv,
1353 struct v4l2_register *reg)
1354{
1355 struct em28xx_fh *fh = priv;
1356 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001357 u64 buf;
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001358
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001359 buf = le64_to_cpu((__u64)reg->val);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001360
1361 return em28xx_write_regs(dev, reg->reg, (char *)&buf,
1362 em28xx_reg_len(reg->reg));
1363}
1364#endif
1365
1366
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001367static int vidioc_cropcap(struct file *file, void *priv,
1368 struct v4l2_cropcap *cc)
1369{
1370 struct em28xx_fh *fh = priv;
1371 struct em28xx *dev = fh->dev;
1372
1373 if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1374 return -EINVAL;
1375
1376 cc->bounds.left = 0;
1377 cc->bounds.top = 0;
1378 cc->bounds.width = dev->width;
1379 cc->bounds.height = dev->height;
1380 cc->defrect = cc->bounds;
1381 cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
1382 cc->pixelaspect.denominator = 59;
1383
1384 return 0;
1385}
1386
1387static int vidioc_streamon(struct file *file, void *priv,
1388 enum v4l2_buf_type type)
1389{
1390 struct em28xx_fh *fh = priv;
1391 struct em28xx *dev = fh->dev;
1392 int rc;
1393
1394 rc = check_dev(dev);
1395 if (rc < 0)
1396 return rc;
1397
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001398
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001399 if (unlikely(res_get(fh) < 0))
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001400 return -EBUSY;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001401
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001402 return (videobuf_streamon(&fh->vb_vidq));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001403}
1404
1405static int vidioc_streamoff(struct file *file, void *priv,
1406 enum v4l2_buf_type type)
1407{
1408 struct em28xx_fh *fh = priv;
1409 struct em28xx *dev = fh->dev;
1410 int rc;
1411
1412 rc = check_dev(dev);
1413 if (rc < 0)
1414 return rc;
1415
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001416 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1417 return -EINVAL;
1418 if (type != fh->type)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001419 return -EINVAL;
1420
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001421 videobuf_streamoff(&fh->vb_vidq);
1422 res_free(fh);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001423
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001424 return 0;
1425}
1426
1427static int vidioc_querycap(struct file *file, void *priv,
1428 struct v4l2_capability *cap)
1429{
1430 struct em28xx_fh *fh = priv;
1431 struct em28xx *dev = fh->dev;
1432
1433 strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
1434 strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
1435 strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
1436
1437 cap->version = EM28XX_VERSION_CODE;
1438
1439 cap->capabilities =
1440 V4L2_CAP_SLICED_VBI_CAPTURE |
1441 V4L2_CAP_VIDEO_CAPTURE |
1442 V4L2_CAP_AUDIO |
1443 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
1444
Mauro Carvalho Chehabed086312008-01-24 06:59:20 -03001445 if (dev->tuner_type != TUNER_ABSENT)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001446 cap->capabilities |= V4L2_CAP_TUNER;
1447
1448 return 0;
1449}
1450
1451static int vidioc_enum_fmt_cap(struct file *file, void *priv,
1452 struct v4l2_fmtdesc *fmtd)
1453{
1454 if (fmtd->index != 0)
1455 return -EINVAL;
1456
1457 fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1458 strcpy(fmtd->description, "Packed YUY2");
1459 fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
1460 memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
1461
1462 return 0;
1463}
1464
1465/* Sliced VBI ioctls */
1466static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
1467 struct v4l2_format *f)
1468{
1469 struct em28xx_fh *fh = priv;
1470 struct em28xx *dev = fh->dev;
1471 int rc;
1472
1473 rc = check_dev(dev);
1474 if (rc < 0)
1475 return rc;
1476
1477 mutex_lock(&dev->lock);
1478
1479 f->fmt.sliced.service_set = 0;
1480
1481 em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
1482
1483 if (f->fmt.sliced.service_set == 0)
1484 rc = -EINVAL;
1485
1486 mutex_unlock(&dev->lock);
1487 return rc;
1488}
1489
1490static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
1491 struct v4l2_format *f)
1492{
1493 struct em28xx_fh *fh = priv;
1494 struct em28xx *dev = fh->dev;
1495 int rc;
1496
1497 rc = check_dev(dev);
1498 if (rc < 0)
1499 return rc;
1500
1501 mutex_lock(&dev->lock);
1502 em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
1503 mutex_unlock(&dev->lock);
1504
1505 if (f->fmt.sliced.service_set == 0)
1506 return -EINVAL;
1507
1508 return 0;
1509}
1510
1511
1512static int vidioc_reqbufs(struct file *file, void *priv,
1513 struct v4l2_requestbuffers *rb)
1514{
1515 struct em28xx_fh *fh = priv;
1516 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001517 int rc;
1518
1519 rc = check_dev(dev);
1520 if (rc < 0)
1521 return rc;
1522
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001523 return (videobuf_reqbufs(&fh->vb_vidq, rb));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001524}
1525
1526static int vidioc_querybuf(struct file *file, void *priv,
1527 struct v4l2_buffer *b)
1528{
1529 struct em28xx_fh *fh = priv;
1530 struct em28xx *dev = fh->dev;
1531 int rc;
1532
1533 rc = check_dev(dev);
1534 if (rc < 0)
1535 return rc;
1536
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001537 return (videobuf_querybuf(&fh->vb_vidq, b));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001538}
1539
1540static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
1541{
1542 struct em28xx_fh *fh = priv;
1543 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001544 int rc;
1545
1546 rc = check_dev(dev);
1547 if (rc < 0)
1548 return rc;
1549
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001550 return (videobuf_qbuf(&fh->vb_vidq, b));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001551}
1552
1553static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
1554{
1555 struct em28xx_fh *fh = priv;
1556 struct em28xx *dev = fh->dev;
1557 int rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001558
1559 rc = check_dev(dev);
1560 if (rc < 0)
1561 return rc;
1562
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001563 return (videobuf_dqbuf(&fh->vb_vidq, b,
1564 file->f_flags & O_NONBLOCK));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001565}
1566
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001567#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001568static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001569{
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001570 struct em28xx_fh *fh = priv;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001571
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001572 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001573}
1574#endif
1575
1576
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001577/* ----------------------------------------------------------- */
1578/* RADIO ESPECIFIC IOCTLS */
1579/* ----------------------------------------------------------- */
1580
1581static int radio_querycap(struct file *file, void *priv,
1582 struct v4l2_capability *cap)
1583{
1584 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1585
1586 strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
1587 strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
1588 strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
1589
1590 cap->version = EM28XX_VERSION_CODE;
1591 cap->capabilities = V4L2_CAP_TUNER;
1592 return 0;
1593}
1594
1595static int radio_g_tuner(struct file *file, void *priv,
1596 struct v4l2_tuner *t)
1597{
1598 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1599
1600 if (unlikely(t->index > 0))
1601 return -EINVAL;
1602
1603 strcpy(t->name, "Radio");
1604 t->type = V4L2_TUNER_RADIO;
1605
1606 em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
1607 return 0;
1608}
1609
1610static int radio_enum_input(struct file *file, void *priv,
1611 struct v4l2_input *i)
1612{
1613 if (i->index != 0)
1614 return -EINVAL;
1615 strcpy(i->name, "Radio");
1616 i->type = V4L2_INPUT_TYPE_TUNER;
1617
1618 return 0;
1619}
1620
1621static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
1622{
1623 if (unlikely(a->index))
1624 return -EINVAL;
1625
1626 strcpy(a->name, "Radio");
1627 return 0;
1628}
1629
1630static int radio_s_tuner(struct file *file, void *priv,
1631 struct v4l2_tuner *t)
1632{
1633 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1634
1635 if (0 != t->index)
1636 return -EINVAL;
1637
1638 em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
1639
1640 return 0;
1641}
1642
1643static int radio_s_audio(struct file *file, void *fh,
1644 struct v4l2_audio *a)
1645{
1646 return 0;
1647}
1648
1649static int radio_s_input(struct file *file, void *fh, unsigned int i)
1650{
1651 return 0;
1652}
1653
1654static int radio_queryctrl(struct file *file, void *priv,
1655 struct v4l2_queryctrl *qc)
1656{
1657 int i;
1658
1659 if (qc->id < V4L2_CID_BASE ||
1660 qc->id >= V4L2_CID_LASTP1)
1661 return -EINVAL;
1662
1663 for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
1664 if (qc->id && qc->id == em28xx_qctrl[i].id) {
1665 memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
1666 return 0;
1667 }
1668 }
1669
1670 return -EINVAL;
1671}
1672
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001673/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001674 * em28xx_v4l2_open()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001675 * inits the device and starts isoc transfer
1676 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001677static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001678{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001679 int minor = iminor(inode);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001680 int errCode = 0, radio = 0;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001681 struct em28xx *h,*dev = NULL;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001682 struct em28xx_fh *fh;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001683 enum v4l2_buf_type fh_type = 0;
Markus Rechberger9c755412005-11-08 21:37:52 -08001684
Trent Piephoa991f442007-10-10 05:37:43 -03001685 list_for_each_entry(h, &em28xx_devlist, devlist) {
Markus Rechberger9c755412005-11-08 21:37:52 -08001686 if (h->vdev->minor == minor) {
1687 dev = h;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001688 fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001689 }
1690 if (h->vbi_dev->minor == minor) {
1691 dev = h;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001692 fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
Markus Rechberger9c755412005-11-08 21:37:52 -08001693 }
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001694 if (h->radio_dev &&
1695 h->radio_dev->minor == minor) {
1696 radio = 1;
1697 dev = h;
1698 }
Markus Rechberger9c755412005-11-08 21:37:52 -08001699 }
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001700 if (NULL == dev)
1701 return -ENODEV;
Markus Rechberger9c755412005-11-08 21:37:52 -08001702
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001703 em28xx_videodbg("open minor=%d type=%s users=%d\n",
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001704 minor, v4l2_type_names[fh_type], dev->users);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001705
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001706 fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001707
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001708 if (!fh) {
1709 em28xx_errdev("em28xx-video.c: Out of memory?!\n");
1710 return -ENOMEM;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001711 }
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001712 mutex_lock(&dev->lock);
1713 fh->dev = dev;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001714 fh->radio = radio;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001715 fh->type = fh_type;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001716 filp->private_data = fh;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001717
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001718 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001719 dev->width = norm_maxw(dev);
1720 dev->height = norm_maxh(dev);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001721 dev->hscale = 0;
1722 dev->vscale = 0;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001723
Mauro Carvalho Chehab3687e1e2008-02-08 15:44:25 -03001724 em28xx_set_alternate(dev);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001725 em28xx_resolution_set(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001726
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001727 }
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001728 if (fh->radio) {
1729 em28xx_videodbg("video_open: setting radio device\n");
1730 em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL);
1731 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001732
1733 dev->users++;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001734
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001735 videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
1736 NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
1737 sizeof(struct em28xx_buffer), fh);
1738
Ingo Molnar3593cab2006-02-07 06:49:14 -02001739 mutex_unlock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001740 return errCode;
1741}
1742
1743/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001744 * em28xx_realease_resources()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001745 * unregisters the v4l2,i2c and usb devices
1746 * called when the device gets disconected or at module unload
1747*/
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001748static void em28xx_release_resources(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001749{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001750
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001751 /*FIXME: I2C IR should be disconnected */
1752
1753 em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
1754 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
1755 dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
Markus Rechberger9c755412005-11-08 21:37:52 -08001756 list_del(&dev->devlist);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001757 if (dev->radio_dev) {
1758 if (-1 != dev->radio_dev->minor)
1759 video_unregister_device(dev->radio_dev);
1760 else
1761 video_device_release(dev->radio_dev);
1762 dev->radio_dev = NULL;
1763 }
1764 if (dev->vbi_dev) {
1765 if (-1 != dev->vbi_dev->minor)
1766 video_unregister_device(dev->vbi_dev);
1767 else
1768 video_device_release(dev->vbi_dev);
1769 dev->vbi_dev = NULL;
1770 }
1771 if (dev->vdev) {
1772 if (-1 != dev->vdev->minor)
1773 video_unregister_device(dev->vdev);
1774 else
1775 video_device_release(dev->vdev);
1776 dev->vdev = NULL;
1777 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001778 em28xx_i2c_unregister(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001779 usb_put_dev(dev->udev);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001780
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001781 /* Mark device as unused */
1782 em28xx_devused&=~(1<<dev->devno);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001783}
1784
1785/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001786 * em28xx_v4l2_close()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001787 * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
1788 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001789static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001790{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001791 struct em28xx_fh *fh = filp->private_data;
1792 struct em28xx *dev = fh->dev;
1793 int errCode;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001794
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -08001795 em28xx_videodbg("users=%d\n", dev->users);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001796
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001797
1798 if (res_check(fh))
1799 res_free(fh);
1800
Ingo Molnar3593cab2006-02-07 06:49:14 -02001801 mutex_lock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001802
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001803 if (dev->users == 1) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001804 videobuf_stop(&fh->vb_vidq);
1805 videobuf_mmap_free(&fh->vb_vidq);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001806
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001807 /* the device is already disconnect,
1808 free the remaining resources */
1809 if (dev->state & DEV_DISCONNECTED) {
1810 em28xx_release_resources(dev);
1811 mutex_unlock(&dev->lock);
1812 kfree(dev);
1813 return 0;
1814 }
1815
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001816 /* do this before setting alternate! */
1817 em28xx_uninit_isoc(dev);
1818
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001819 /* set alternate 0 */
1820 dev->alt = 0;
1821 em28xx_videodbg("setting alternate 0\n");
1822 errCode = usb_set_interface(dev->udev, 0, 0);
1823 if (errCode < 0) {
1824 em28xx_errdev("cannot change alternate number to "
1825 "0 (error=%i)\n", errCode);
1826 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001827 }
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001828 kfree(fh);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001829 dev->users--;
1830 wake_up_interruptible_nr(&dev->open, 1);
Ingo Molnar3593cab2006-02-07 06:49:14 -02001831 mutex_unlock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001832 return 0;
1833}
1834
1835/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001836 * em28xx_v4l2_read()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001837 * will allocate buffers when called for the first time
1838 */
1839static ssize_t
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001840em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001841 loff_t *pos)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001842{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001843 struct em28xx_fh *fh = filp->private_data;
1844 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001845 int rc;
1846
1847 rc = check_dev(dev);
1848 if (rc < 0)
1849 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001850
Mauro Carvalho Chehab9e31ced2007-11-11 01:13:49 -03001851 /* FIXME: read() is not prepared to allow changing the video
1852 resolution while streaming. Seems a bug at em28xx_set_fmt
1853 */
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001854
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001855 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1856 if (unlikely(res_get(fh)))
1857 return -EBUSY;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001858
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001859 return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
1860 filp->f_flags & O_NONBLOCK);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001861 }
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001862 return 0;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001863}
1864
1865/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001866 * em28xx_v4l2_poll()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001867 * will allocate buffers when called for the first time
1868 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001869static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001870{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001871 struct em28xx_fh *fh = filp->private_data;
1872 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001873 int rc;
1874
1875 rc = check_dev(dev);
1876 if (rc < 0)
1877 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001878
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001879 if (unlikely(res_get(fh) < 0))
1880 return POLLERR;
1881
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001882 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1883 return POLLERR;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001884
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001885 return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001886}
1887
1888/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001889 * em28xx_v4l2_mmap()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001890 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001891static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001892{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001893 struct em28xx_fh *fh = filp->private_data;
1894 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001895 int rc;
Markus Rechberger9c755412005-11-08 21:37:52 -08001896
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001897 if (unlikely(res_get(fh) < 0))
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001898 return -EBUSY;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001899
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001900 rc = check_dev(dev);
1901 if (rc < 0)
1902 return rc;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001903
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001904 rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001905
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001906 em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
1907 (unsigned long)vma->vm_start,
1908 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
1909 rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001910
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001911 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001912}
1913
Arjan van de Venfa027c22007-02-12 00:55:33 -08001914static const struct file_operations em28xx_v4l_fops = {
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001915 .owner = THIS_MODULE,
1916 .open = em28xx_v4l2_open,
1917 .release = em28xx_v4l2_close,
1918 .read = em28xx_v4l2_read,
1919 .poll = em28xx_v4l2_poll,
1920 .mmap = em28xx_v4l2_mmap,
1921 .ioctl = video_ioctl2,
1922 .llseek = no_llseek,
1923 .compat_ioctl = v4l_compat_ioctl32,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001924};
1925
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001926static const struct file_operations radio_fops = {
1927 .owner = THIS_MODULE,
1928 .open = em28xx_v4l2_open,
1929 .release = em28xx_v4l2_close,
1930 .ioctl = video_ioctl2,
1931 .compat_ioctl = v4l_compat_ioctl32,
1932 .llseek = no_llseek,
1933};
1934
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001935static const struct video_device em28xx_video_template = {
1936 .fops = &em28xx_v4l_fops,
1937 .release = video_device_release,
1938
1939 .minor = -1,
1940 .vidioc_querycap = vidioc_querycap,
1941 .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
1942 .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
1943 .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
1944 .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
1945 .vidioc_g_audio = vidioc_g_audio,
1946 .vidioc_s_audio = vidioc_s_audio,
1947 .vidioc_cropcap = vidioc_cropcap,
1948
1949 .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture,
1950 .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
1951 .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture,
1952
1953 .vidioc_reqbufs = vidioc_reqbufs,
1954 .vidioc_querybuf = vidioc_querybuf,
1955 .vidioc_qbuf = vidioc_qbuf,
1956 .vidioc_dqbuf = vidioc_dqbuf,
1957 .vidioc_s_std = vidioc_s_std,
1958 .vidioc_enum_input = vidioc_enum_input,
1959 .vidioc_g_input = vidioc_g_input,
1960 .vidioc_s_input = vidioc_s_input,
1961 .vidioc_queryctrl = vidioc_queryctrl,
1962 .vidioc_g_ctrl = vidioc_g_ctrl,
1963 .vidioc_s_ctrl = vidioc_s_ctrl,
1964 .vidioc_streamon = vidioc_streamon,
1965 .vidioc_streamoff = vidioc_streamoff,
1966 .vidioc_g_tuner = vidioc_g_tuner,
1967 .vidioc_s_tuner = vidioc_s_tuner,
1968 .vidioc_g_frequency = vidioc_g_frequency,
1969 .vidioc_s_frequency = vidioc_s_frequency,
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001970#ifdef CONFIG_VIDEO_ADV_DEBUG
1971 .vidioc_g_register = vidioc_g_register,
1972 .vidioc_s_register = vidioc_s_register,
1973#endif
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001974#ifdef CONFIG_VIDEO_V4L1_COMPAT
1975 .vidiocgmbuf = vidiocgmbuf,
1976#endif
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001977
1978 .tvnorms = V4L2_STD_ALL,
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001979 .current_norm = V4L2_STD_PAL,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001980};
1981
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001982static struct video_device em28xx_radio_template = {
1983 .name = "em28xx-radio",
1984 .type = VID_TYPE_TUNER,
1985 .fops = &radio_fops,
1986 .minor = -1,
1987 .vidioc_querycap = radio_querycap,
1988 .vidioc_g_tuner = radio_g_tuner,
1989 .vidioc_enum_input = radio_enum_input,
1990 .vidioc_g_audio = radio_g_audio,
1991 .vidioc_s_tuner = radio_s_tuner,
1992 .vidioc_s_audio = radio_s_audio,
1993 .vidioc_s_input = radio_s_input,
1994 .vidioc_queryctrl = radio_queryctrl,
1995 .vidioc_g_ctrl = vidioc_g_ctrl,
1996 .vidioc_s_ctrl = vidioc_s_ctrl,
1997 .vidioc_g_frequency = vidioc_g_frequency,
1998 .vidioc_s_frequency = vidioc_s_frequency,
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001999#ifdef CONFIG_VIDEO_ADV_DEBUG
2000 .vidioc_g_register = vidioc_g_register,
2001 .vidioc_s_register = vidioc_s_register,
2002#endif
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002003};
2004
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002005/******************************** usb interface *****************************************/
2006
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002007
2008static LIST_HEAD(em28xx_extension_devlist);
2009static DEFINE_MUTEX(em28xx_extension_devlist_lock);
2010
2011int em28xx_register_extension(struct em28xx_ops *ops)
2012{
2013 struct em28xx *h, *dev = NULL;
2014
2015 list_for_each_entry(h, &em28xx_devlist, devlist)
2016 dev = h;
2017
2018 mutex_lock(&em28xx_extension_devlist_lock);
2019 list_add_tail(&ops->next, &em28xx_extension_devlist);
2020 if (dev)
2021 ops->init(dev);
2022
2023 printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
2024 mutex_unlock(&em28xx_extension_devlist_lock);
2025
2026 return 0;
2027}
2028EXPORT_SYMBOL(em28xx_register_extension);
2029
2030void em28xx_unregister_extension(struct em28xx_ops *ops)
2031{
2032 struct em28xx *h, *dev = NULL;
2033
2034 list_for_each_entry(h, &em28xx_devlist, devlist)
2035 dev = h;
2036
2037 if (dev)
2038 ops->fini(dev);
2039
2040 mutex_lock(&em28xx_extension_devlist_lock);
2041 printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
2042 list_del(&ops->next);
2043 mutex_unlock(&em28xx_extension_devlist_lock);
2044}
2045EXPORT_SYMBOL(em28xx_unregister_extension);
2046
Adrian Bunk532fe652008-01-28 22:10:48 -03002047static struct video_device *em28xx_vdev_init(struct em28xx *dev,
2048 const struct video_device *template,
2049 const int type,
2050 const char *type_name)
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002051{
2052 struct video_device *vfd;
2053
2054 vfd = video_device_alloc();
2055 if (NULL == vfd)
2056 return NULL;
2057 *vfd = *template;
2058 vfd->minor = -1;
2059 vfd->dev = &dev->udev->dev;
2060 vfd->release = video_device_release;
2061 vfd->type = type;
Mauro Carvalho Chehabe9e60402008-04-13 15:05:47 -03002062 vfd->debug = video_debug;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002063
2064 snprintf(vfd->name, sizeof(vfd->name), "%s %s",
2065 dev->name, type_name);
2066
2067 return vfd;
2068}
2069
2070
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002071/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002072 * em28xx_init_dev()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002073 * allocates and inits the device structs, registers i2c bus and v4l device
2074 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002075static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002076 int minor)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002077{
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002078 struct em28xx_ops *ops = NULL;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002079 struct em28xx *dev = *devhandle;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002080 int retval = -ENOMEM;
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03002081 int errCode;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002082 unsigned int maxh, maxw;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002083
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002084 dev->udev = udev;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002085 mutex_init(&dev->lock);
Aidan Thorntond7aa8022008-04-13 14:38:47 -03002086 spin_lock_init(&dev->slock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002087 init_waitqueue_head(&dev->open);
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002088 init_waitqueue_head(&dev->wait_frame);
2089 init_waitqueue_head(&dev->wait_stream);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002090
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002091 dev->em28xx_write_regs = em28xx_write_regs;
2092 dev->em28xx_read_reg = em28xx_read_reg;
2093 dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
2094 dev->em28xx_write_regs_req = em28xx_write_regs_req;
2095 dev->em28xx_read_reg_req = em28xx_read_reg_req;
Sascha Sommerfad7b952007-11-04 08:06:48 -03002096 dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002097
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002098 errCode = em28xx_read_reg(dev, CHIPID_REG);
2099 if (errCode >= 0)
2100 em28xx_info("em28xx chip ID = %d\n", errCode);
2101
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002102 em28xx_pre_card_setup(dev);
2103
2104 errCode = em28xx_config(dev);
2105 if (errCode) {
2106 em28xx_errdev("error configuring device\n");
2107 em28xx_devused &= ~(1<<dev->devno);
2108 kfree(dev);
2109 return -ENOMEM;
2110 }
2111
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002112 /* register i2c bus */
2113 em28xx_i2c_register(dev);
2114
2115 /* Do board specific init and eeprom reading */
2116 em28xx_card_setup(dev);
2117
Mauro Carvalho Chehab3abee532008-01-05 17:01:41 -03002118 /* Configure audio */
2119 em28xx_audio_analog_set(dev);
2120
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002121 /* configure the device */
2122 em28xx_config_i2c(dev);
2123
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03002124 /* set default norm */
2125 dev->norm = em28xx_video_template.current_norm;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002126
2127 maxw = norm_maxw(dev);
2128 maxh = norm_maxh(dev);
2129
2130 /* set default image size */
2131 dev->width = maxw;
2132 dev->height = maxh;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002133 dev->interlaced = EM28XX_INTERLACED_DEFAULT;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002134 dev->hscale = 0;
2135 dev->vscale = 0;
2136 dev->ctl_input = 2;
2137
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002138 errCode = em28xx_config(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002139
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002140 list_add_tail(&dev->devlist, &em28xx_devlist);
2141
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002142 /* allocate and fill video video_device struct */
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002143 dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template,
2144 VID_TYPE_CAPTURE, "video");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002145 if (NULL == dev->vdev) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002146 em28xx_errdev("cannot allocate video_device.\n");
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002147 goto fail_unreg;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002148 }
Mauro Carvalho Chehabed086312008-01-24 06:59:20 -03002149 if (dev->tuner_type != TUNER_ABSENT)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002150 dev->vdev->type |= VID_TYPE_TUNER;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002151
2152 /* register v4l2 video video_device */
2153 retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
2154 video_nr[dev->devno]);
2155 if (retval) {
2156 em28xx_errdev("unable to register video device (error=%i).\n",
2157 retval);
2158 goto fail_unreg;
2159 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002160
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002161 /* Allocate and fill vbi video_device struct */
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002162 dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
2163 VFL_TYPE_VBI, "vbi");
2164 /* register v4l2 vbi video_device */
2165 if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
2166 vbi_nr[dev->devno]) < 0) {
2167 em28xx_errdev("unable to register vbi device\n");
2168 retval = -ENODEV;
2169 goto fail_unreg;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002170 }
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002171
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002172 if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
2173 dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
2174 VFL_TYPE_RADIO, "radio");
2175 if (NULL == dev->radio_dev) {
2176 em28xx_errdev("cannot allocate video_device.\n");
2177 goto fail_unreg;
2178 }
2179 retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
2180 radio_nr[dev->devno]);
2181 if (retval < 0) {
2182 em28xx_errdev("can't register radio device\n");
2183 goto fail_unreg;
2184 }
2185 em28xx_info("Registered radio device as /dev/radio%d\n",
2186 dev->radio_dev->minor & 0x1f);
2187 }
2188
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002189 /* init video dma queues */
2190 INIT_LIST_HEAD(&dev->vidq.active);
2191 INIT_LIST_HEAD(&dev->vidq.queued);
2192
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002193
Sascha Sommer5a804152007-11-03 21:22:38 -03002194 if (dev->has_msp34xx) {
2195 /* Send a reset to other chips via gpio */
2196 em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
2197 msleep(3);
2198 em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
2199 msleep(3);
Sascha Sommer5a804152007-11-03 21:22:38 -03002200 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002201
Sascha Sommer5a804152007-11-03 21:22:38 -03002202 video_mux(dev, 0);
2203
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002204 em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
2205 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
2206 dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002207
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002208 mutex_lock(&em28xx_extension_devlist_lock);
2209 if (!list_empty(&em28xx_extension_devlist)) {
2210 list_for_each_entry(ops, &em28xx_extension_devlist, next) {
2211 if (ops->id)
2212 ops->init(dev);
2213 }
2214 }
2215 mutex_unlock(&em28xx_extension_devlist_lock);
2216
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002217 return 0;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002218
2219fail_unreg:
2220 em28xx_release_resources(dev);
2221 mutex_unlock(&dev->lock);
2222 kfree(dev);
2223 return retval;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002224}
2225
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002226#if defined(CONFIG_MODULES) && defined(MODULE)
2227static void request_module_async(struct work_struct *work)
2228{
2229 struct em28xx *dev = container_of(work,
2230 struct em28xx, request_module_wk);
2231
Mauro Carvalho Chehab3f4dfe22008-01-06 09:54:17 -03002232 if (dev->has_audio_class)
2233 request_module("snd-usb-audio");
2234 else
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002235 request_module("em28xx-alsa");
Mauro Carvalho Chehab3aefb792008-04-17 21:36:41 -03002236
2237 if (dev->has_dvb)
2238 request_module("em28xx-dvb");
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002239}
2240
2241static void request_modules(struct em28xx *dev)
2242{
2243 INIT_WORK(&dev->request_module_wk, request_module_async);
2244 schedule_work(&dev->request_module_wk);
2245}
2246#else
2247#define request_modules(dev)
2248#endif /* CONFIG_MODULES */
2249
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002250/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002251 * em28xx_usb_probe()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002252 * checks for supported devices
2253 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002254static int em28xx_usb_probe(struct usb_interface *interface,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002255 const struct usb_device_id *id)
2256{
2257 const struct usb_endpoint_descriptor *endpoint;
2258 struct usb_device *udev;
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002259 struct usb_interface *uif;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002260 struct em28xx *dev = NULL;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002261 int retval = -ENODEV;
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002262 int i, nr, ifnum;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002263
2264 udev = usb_get_dev(interface_to_usbdev(interface));
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -08002265 ifnum = interface->altsetting[0].desc.bInterfaceNumber;
2266
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002267 /* Check to see next free device and mark as used */
2268 nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
2269 em28xx_devused|=1<<nr;
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -08002270
2271 /* Don't register audio interfaces */
2272 if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002273 em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -08002274 udev->descriptor.idVendor,udev->descriptor.idProduct,
2275 ifnum,
2276 interface->altsetting[0].desc.bInterfaceClass);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002277
2278 em28xx_devused&=~(1<<nr);
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -08002279 return -ENODEV;
2280 }
2281
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002282 em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -08002283 udev->descriptor.idVendor,udev->descriptor.idProduct,
2284 ifnum,
2285 interface->altsetting[0].desc.bInterfaceClass);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002286
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -08002287 endpoint = &interface->cur_altsetting->endpoint[1].desc;
2288
Michael Opdenacker59c51592007-05-09 08:57:56 +02002289 /* check if the device has the iso in endpoint at the correct place */
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002290 if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
2291 USB_ENDPOINT_XFER_ISOC) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002292 em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002293 em28xx_devused&=~(1<<nr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002294 return -ENODEV;
2295 }
2296 if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002297 em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002298 em28xx_devused&=~(1<<nr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002299 return -ENODEV;
2300 }
2301
Mauro Carvalho Chehab19478842006-03-14 17:24:57 -03002302 if (nr >= EM28XX_MAXBOARDS) {
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002303 printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002304 em28xx_devused&=~(1<<nr);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002305 return -ENOMEM;
2306 }
2307
2308 /* allocate memory for our device state and initialize it */
Panagiotis Issaris74081872006-01-11 19:40:56 -02002309 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002310 if (dev == NULL) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002311 em28xx_err(DRIVER_NAME ": out of memory!\n");
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002312 em28xx_devused&=~(1<<nr);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002313 return -ENOMEM;
2314 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002315
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002316 snprintf(dev->name, 29, "em28xx #%d", nr);
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002317 dev->devno = nr;
2318 dev->model = id->driver_info;
Mauro Carvalho Chehab3687e1e2008-02-08 15:44:25 -03002319 dev->alt = -1;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002320
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002321 /* Checks if audio is provided by some interface */
2322 for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
2323 uif = udev->config->interface[i];
2324 if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
2325 dev->has_audio_class = 1;
2326 break;
2327 }
2328 }
2329
2330 printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
2331 dev->has_audio_class ? "Has" : "Doesn't have");
2332
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002333 /* compute alternate max packet sizes */
2334 uif = udev->actconfig->interface[0];
2335
2336 dev->num_alt=uif->num_altsetting;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002337 em28xx_info("Alternate settings: %i\n",dev->num_alt);
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002338// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
2339 dev->alt_max_pkt_size = kmalloc(32*
2340 dev->num_alt,GFP_KERNEL);
2341 if (dev->alt_max_pkt_size == NULL) {
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002342 em28xx_errdev("out of memory!\n");
2343 em28xx_devused&=~(1<<nr);
Jesper Juhl1207cf842007-08-09 23:02:36 +02002344 kfree(dev);
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002345 return -ENOMEM;
2346 }
2347
2348 for (i = 0; i < dev->num_alt ; i++) {
2349 u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
2350 wMaxPacketSize);
2351 dev->alt_max_pkt_size[i] =
2352 (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002353 em28xx_info("Alternate setting %i, max size= %i\n",i,
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002354 dev->alt_max_pkt_size[i]);
2355 }
2356
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002357 if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002358 dev->model = card[nr];
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002359
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002360 /* allocate device struct */
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002361 retval = em28xx_init_dev(&dev, udev, nr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002362 if (retval)
2363 return retval;
2364
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002365 em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002366
2367 /* save our data pointer in this interface device */
2368 usb_set_intfdata(interface, dev);
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002369
Mauro Carvalho Chehab3aefb792008-04-17 21:36:41 -03002370#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
2371 dev->qops = kmalloc(sizeof(em28xx_video_qops), GFP_KERNEL);
2372 memcpy(dev->qops, &em28xx_video_qops, sizeof(em28xx_video_qops));
2373#endif
2374
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002375 request_modules(dev);
2376
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002377 return 0;
2378}
2379
2380/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002381 * em28xx_usb_disconnect()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002382 * called when the device gets diconencted
2383 * video device will be unregistered on v4l2_close in case it is still open
2384 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002385static void em28xx_usb_disconnect(struct usb_interface *interface)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002386{
Sascha Sommer5a804152007-11-03 21:22:38 -03002387 struct em28xx *dev;
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002388 struct em28xx_ops *ops = NULL;
Sascha Sommer5a804152007-11-03 21:22:38 -03002389
2390 dev = usb_get_intfdata(interface);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002391 usb_set_intfdata(interface, NULL);
2392
2393 if (!dev)
2394 return;
2395
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002396 em28xx_info("disconnecting %s\n", dev->vdev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002397
Sascha Sommer5a804152007-11-03 21:22:38 -03002398 /* wait until all current v4l2 io is finished then deallocate resources */
2399 mutex_lock(&dev->lock);
2400
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002401 wake_up_interruptible_all(&dev->open);
2402
2403 if (dev->users) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002404 em28xx_warn
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002405 ("device /dev/video%d is open! Deregistration and memory "
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002406 "deallocation are deferred on close.\n",
2407 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
2408
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002409 dev->state |= DEV_MISCONFIGURED;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002410 em28xx_uninit_isoc(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002411 dev->state |= DEV_DISCONNECTED;
2412 wake_up_interruptible(&dev->wait_frame);
2413 wake_up_interruptible(&dev->wait_stream);
2414 } else {
2415 dev->state |= DEV_DISCONNECTED;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002416 em28xx_release_resources(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002417 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002418 mutex_unlock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002419
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002420 mutex_lock(&em28xx_extension_devlist_lock);
2421 if (!list_empty(&em28xx_extension_devlist)) {
2422 list_for_each_entry(ops, &em28xx_extension_devlist, next) {
2423 ops->fini(dev);
2424 }
2425 }
2426 mutex_unlock(&em28xx_extension_devlist_lock);
2427
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002428 if (!dev->users) {
2429 kfree(dev->alt_max_pkt_size);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002430 kfree(dev);
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002431 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002432}
2433
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002434static struct usb_driver em28xx_usb_driver = {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002435 .name = "em28xx",
2436 .probe = em28xx_usb_probe,
2437 .disconnect = em28xx_usb_disconnect,
2438 .id_table = em28xx_id_table,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002439};
2440
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002441static int __init em28xx_module_init(void)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002442{
2443 int result;
2444
2445 printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002446 (EM28XX_VERSION_CODE >> 16) & 0xff,
2447 (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002448#ifdef SNAPSHOT
2449 printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
2450 SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
2451#endif
2452
2453 /* register this driver with the USB subsystem */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002454 result = usb_register(&em28xx_usb_driver);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002455 if (result)
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002456 em28xx_err(DRIVER_NAME
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002457 " usb_register failed. Error number %d.\n", result);
2458
2459 return result;
2460}
2461
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002462static void __exit em28xx_module_exit(void)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002463{
2464 /* deregister this driver with the USB subsystem */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002465 usb_deregister(&em28xx_usb_driver);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002466}
2467
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002468module_init(em28xx_module_init);
2469module_exit(em28xx_module_exit);