blob: 6084f8452b2beaa6dd604c3f6c7967e8f4f68e30 [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
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -030066/* Limits minimum and default number of buffers */
67#define EM28XX_MIN_BUF 4
68#define EM28XX_DEF_BUF 8
69
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080070MODULE_AUTHOR(DRIVER_AUTHOR);
71MODULE_DESCRIPTION(DRIVER_DESC);
72MODULE_LICENSE("GPL");
73
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080074static LIST_HEAD(em28xx_devlist);
Markus Rechberger9c755412005-11-08 21:37:52 -080075
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -080076static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020077static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -030078static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
79static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
80
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080081module_param_array(card, int, NULL, 0444);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020082module_param_array(video_nr, int, NULL, 0444);
83module_param_array(vbi_nr, int, NULL, 0444);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -030084module_param_array(radio_nr, int, NULL, 0444);
85MODULE_PARM_DESC(card, "card type");
86MODULE_PARM_DESC(video_nr, "video device numbers");
87MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
88MODULE_PARM_DESC(radio_nr, "radio device numbers");
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -080089
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030090static unsigned int video_debug;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080091module_param(video_debug,int,0644);
92MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
93
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -020094/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
95static unsigned long em28xx_devused;
96
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -080097/* supported controls */
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -020098/* Common to all boards */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -080099static struct v4l2_queryctrl em28xx_qctrl[] = {
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800100 {
Mauro Carvalho Chehabc0477ad2006-01-09 15:25:14 -0200101 .id = V4L2_CID_AUDIO_VOLUME,
102 .type = V4L2_CTRL_TYPE_INTEGER,
103 .name = "Volume",
104 .minimum = 0x0,
105 .maximum = 0x1f,
106 .step = 0x1,
107 .default_value = 0x1f,
108 .flags = 0,
109 },{
110 .id = V4L2_CID_AUDIO_MUTE,
111 .type = V4L2_CTRL_TYPE_BOOLEAN,
112 .name = "Mute",
113 .minimum = 0,
114 .maximum = 1,
115 .step = 1,
116 .default_value = 1,
117 .flags = 0,
118 }
119};
120
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800121static struct usb_driver em28xx_usb_driver;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800122
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300123/* ------------------------------------------------------------------
124 DMA and thread functions
125 ------------------------------------------------------------------*/
126
127/*
128 * Announces that a buffer were filled and request the next
129 */
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300130static inline void buffer_filled(struct em28xx *dev,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300131 struct em28xx_dmaqueue *dma_q,
132 struct em28xx_buffer *buf)
133{
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300134 /* Advice that buffer was filled */
135 em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
136 buf->vb.state = VIDEOBUF_DONE;
137 buf->vb.field_count++;
138 do_gettimeofday(&buf->vb.ts);
139
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300140 dev->isoc_ctl.buf = NULL;
141
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300142 list_del(&buf->vb.queue);
143 wake_up(&buf->vb.done);
144}
145
146/*
147 * Identify the buffer header type and properly handles
148 */
149static void em28xx_copy_video(struct em28xx *dev,
150 struct em28xx_dmaqueue *dma_q,
151 struct em28xx_buffer *buf,
152 unsigned char *p,
153 unsigned char *outp, unsigned long len)
154{
155 void *fieldstart, *startwrite, *startread;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300156 int linesdone, currlinedone, offset, lencopy, remain;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300157 int bytesperline = dev->width << 1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300158
159 if (dma_q->pos + len > buf->vb.size)
160 len = buf->vb.size - dma_q->pos;
161
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300162 if (p[0] != 0x88 && p[0] != 0x22) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300163 em28xx_isocdbg("frame is not complete\n");
164 len += 4;
165 } else
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300166 p += 4;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300167
168 startread = p;
169 remain = len;
170
171 /* Interlaces frame */
172 if (buf->top_field)
173 fieldstart = outp;
174 else
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300175 fieldstart = outp + bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300176
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300177 linesdone = dma_q->pos / bytesperline;
178 currlinedone = dma_q->pos % bytesperline;
179 offset = linesdone * bytesperline * 2 + currlinedone;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300180 startwrite = fieldstart + offset;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300181 lencopy = bytesperline - currlinedone;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300182 lencopy = lencopy > remain ? remain : lencopy;
183
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300184 if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
Mauro Carvalho Chehabea8df7e2008-04-13 14:39:29 -0300185 em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300186 ((char *)startwrite + lencopy) -
187 ((char *)outp + buf->vb.size));
188 lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300189 }
Aidan Thorntone0fadfd342008-04-13 14:56:02 -0300190 if (lencopy <= 0)
191 return;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300192 memcpy(startwrite, startread, lencopy);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300193
194 remain -= lencopy;
195
196 while (remain > 0) {
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300197 startwrite += lencopy + bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300198 startread += lencopy;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300199 if (bytesperline > remain)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300200 lencopy = remain;
201 else
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300202 lencopy = bytesperline;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300203
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300204 if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
Mauro Carvalho Chehabea8df7e2008-04-13 14:39:29 -0300205 em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300206 ((char *)startwrite + lencopy) -
207 ((char *)outp + buf->vb.size));
208 lencopy = remain = (char *)outp + buf->vb.size -
209 (char *)startwrite;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300210 }
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300211 if (lencopy <= 0)
212 break;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300213
214 memcpy(startwrite, startread, lencopy);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300215
216 remain -= lencopy;
217 }
218
219 dma_q->pos += len;
220}
221
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300222static inline void print_err_status(struct em28xx *dev,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300223 int packet, int status)
224{
225 char *errmsg = "Unknown";
226
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300227 switch (status) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300228 case -ENOENT:
229 errmsg = "unlinked synchronuously";
230 break;
231 case -ECONNRESET:
232 errmsg = "unlinked asynchronuously";
233 break;
234 case -ENOSR:
235 errmsg = "Buffer error (overrun)";
236 break;
237 case -EPIPE:
238 errmsg = "Stalled (device not responding)";
239 break;
240 case -EOVERFLOW:
241 errmsg = "Babble (bad cable?)";
242 break;
243 case -EPROTO:
244 errmsg = "Bit-stuff error (bad cable?)";
245 break;
246 case -EILSEQ:
247 errmsg = "CRC/Timeout (could be anything)";
248 break;
249 case -ETIME:
250 errmsg = "Device does not respond";
251 break;
252 }
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300253 if (packet < 0) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300254 em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
255 } else {
256 em28xx_isocdbg("URB packet %d, status %d [%s].\n",
257 packet, status, errmsg);
258 }
259}
260
261/*
262 * video-buf generic routine to get the next available buffer
263 */
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300264static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300265 struct em28xx_buffer **buf)
266{
267 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300268 char *outp;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300269
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300270 if (list_empty(&dma_q->active)) {
271 em28xx_isocdbg("No active queue to serve\n");
272 dev->isoc_ctl.buf = NULL;
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300273 *buf = NULL;
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300274 return;
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300275 }
276
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300277 /* Get the next buffer */
278 *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
279
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300280 /* Cleans up buffer - Usefull for testing for frame/URB loss */
281 outp = videobuf_to_vmalloc(&(*buf)->vb);
282 memset(outp, 0, (*buf)->vb.size);
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300283
284 dev->isoc_ctl.buf = *buf;
285
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300286 return;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300287}
288
289/*
290 * Controls the isoc copy of each urb packet
291 */
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300292static inline int em28xx_isoc_copy(struct urb *urb)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300293{
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300294 struct em28xx_buffer *buf;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300295 struct em28xx_dmaqueue *dma_q = urb->context;
296 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300297 unsigned char *outp = NULL;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300298 int i, len = 0, rc = 1;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300299 unsigned char *p;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300300
301 if (!dev)
302 return 0;
303
304 if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
305 return 0;
306
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300307 if (urb->status < 0) {
308 print_err_status(dev, -1, urb->status);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300309 if (urb->status == -ENOENT)
310 return 0;
311 }
312
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300313 buf = dev->isoc_ctl.buf;
314 if (buf != NULL)
315 outp = videobuf_to_vmalloc(&buf->vb);
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300316
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300317 for (i = 0; i < urb->number_of_packets; i++) {
318 int status = urb->iso_frame_desc[i].status;
319
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300320 if (status < 0) {
321 print_err_status(dev, i, status);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300322 if (urb->iso_frame_desc[i].status != -EPROTO)
323 continue;
324 }
325
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300326 len = urb->iso_frame_desc[i].actual_length - 4;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300327
328 if (urb->iso_frame_desc[i].actual_length <= 0) {
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300329 /* em28xx_isocdbg("packet %d is empty",i); - spammy */
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300330 continue;
331 }
332 if (urb->iso_frame_desc[i].actual_length >
333 dev->max_pkt_size) {
334 em28xx_isocdbg("packet bigger than packet size");
335 continue;
336 }
337
338 p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300339
340 /* FIXME: incomplete buffer checks where removed to make
341 logic simpler. Impacts of those changes should be evaluated
342 */
Mauro Carvalho Chehabb4916f82008-04-13 15:09:14 -0300343 if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
344 em28xx_isocdbg("VBI HEADER!!!\n");
345 /* FIXME: Should add vbi copy */
346 continue;
347 }
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300348 if (p[0] == 0x22 && p[1] == 0x5a) {
Mauro Carvalho Chehab78bb3942008-04-13 14:56:25 -0300349 em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
350 len, (p[2] & 1)? "odd" : "even");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300351
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300352 if (!(p[2] & 1)) {
353 if (buf != NULL)
354 buffer_filled(dev, dma_q, buf);
355 get_next_buf(dma_q, &buf);
356 if (buf == NULL)
357 outp = NULL;
358 else
359 outp = videobuf_to_vmalloc(&buf->vb);
Aidan Thorntone0fadfd342008-04-13 14:56:02 -0300360 }
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300361
362 if (buf != NULL) {
363 if (p[2] & 1)
364 buf->top_field = 0;
365 else
366 buf->top_field = 1;
367 }
Mauro Carvalho Chehabb4916f82008-04-13 15:09:14 -0300368
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300369 dma_q->pos = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300370 }
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300371 if (buf != NULL)
372 em28xx_copy_video(dev, dma_q, buf, p, outp, len);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300373 }
374 return rc;
375}
376
377/* ------------------------------------------------------------------
378 URB control
379 ------------------------------------------------------------------*/
380
381/*
382 * IRQ callback, called by URB callback
383 */
384static void em28xx_irq_callback(struct urb *urb)
385{
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300386 struct em28xx_dmaqueue *dma_q = urb->context;
387 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300388 int rc, i;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300389
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300390 /* Copy data from URB */
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300391 spin_lock(&dev->slock);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300392 rc = em28xx_isoc_copy(urb);
Mauro Carvalho Chehabdbecb442008-04-13 15:08:55 -0300393 spin_unlock(&dev->slock);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300394
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300395 /* Reset urb buffers */
396 for (i = 0; i < urb->number_of_packets; i++) {
397 urb->iso_frame_desc[i].status = 0;
398 urb->iso_frame_desc[i].actual_length = 0;
399 }
400 urb->status = 0;
401
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300402 urb->status = usb_submit_urb(urb, GFP_ATOMIC);
403 if (urb->status) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300404 em28xx_err("urb resubmit failed (error=%i)\n",
405 urb->status);
406 }
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300407}
408
409/*
410 * Stop and Deallocate URBs
411 */
412static void em28xx_uninit_isoc(struct em28xx *dev)
413{
414 struct urb *urb;
415 int i;
416
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300417 em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
418
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300419 dev->isoc_ctl.nfields = -1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300420 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300421 urb = dev->isoc_ctl.urb[i];
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300422 if (urb) {
423 usb_kill_urb(urb);
424 usb_unlink_urb(urb);
425 if (dev->isoc_ctl.transfer_buffer[i]) {
426 usb_buffer_free(dev->udev,
427 urb->transfer_buffer_length,
428 dev->isoc_ctl.transfer_buffer[i],
429 urb->transfer_dma);
430 }
431 usb_free_urb(urb);
432 dev->isoc_ctl.urb[i] = NULL;
433 }
434 dev->isoc_ctl.transfer_buffer[i] = NULL;
435 }
436
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300437 kfree(dev->isoc_ctl.urb);
438 kfree(dev->isoc_ctl.transfer_buffer);
439 dev->isoc_ctl.urb = NULL;
440 dev->isoc_ctl.transfer_buffer = NULL;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300441
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300442 dev->isoc_ctl.num_bufs = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300443
Mauro Carvalho Chehab47625da2008-04-13 14:40:10 -0300444 em28xx_capture_start(dev, 0);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300445}
446
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300447/*
448 * Allocate URBs and start IRQ
449 */
450static int em28xx_prepare_isoc(struct em28xx *dev, int max_packets,
451 int num_bufs)
452{
453 struct em28xx_dmaqueue *dma_q = &dev->vidq;
454 int i;
455 int sb_size, pipe;
456 struct urb *urb;
457 int j, k;
458
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300459 em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
460
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300461 /* De-allocates all pending stuff */
462 em28xx_uninit_isoc(dev);
463
464 dev->isoc_ctl.num_bufs = num_bufs;
465
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300466 dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300467 if (!dev->isoc_ctl.urb) {
468 em28xx_errdev("cannot alloc memory for usb buffers\n");
469 return -ENOMEM;
470 }
471
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300472 dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300473 GFP_KERNEL);
474 if (!dev->isoc_ctl.urb) {
475 em28xx_errdev("cannot allocate memory for usbtransfer\n");
476 kfree(dev->isoc_ctl.urb);
477 return -ENOMEM;
478 }
479
480 dev->isoc_ctl.max_pkt_size = dev->max_pkt_size;
Mauro Carvalho Chehabcb784722008-04-13 15:06:52 -0300481 dev->isoc_ctl.buf = NULL;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300482
483 sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
484
485 /* allocate urbs and transfer buffers */
486 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
487 urb = usb_alloc_urb(max_packets, GFP_KERNEL);
488 if (!urb) {
489 em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
490 em28xx_uninit_isoc(dev);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300491 return -ENOMEM;
492 }
493 dev->isoc_ctl.urb[i] = urb;
494
495 dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
496 sb_size, GFP_KERNEL, &urb->transfer_dma);
497 if (!dev->isoc_ctl.transfer_buffer[i]) {
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300498 em28xx_err("unable to allocate %i bytes for transfer"
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300499 " buffer %i%s\n",
500 sb_size, i,
501 in_interrupt()?" while in int":"");
502 em28xx_uninit_isoc(dev);
503 return -ENOMEM;
504 }
505 memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
506
507 /* FIXME: this is a hack - should be
508 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
509 should also be using 'desc.bInterval'
510 */
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300511 pipe = usb_rcvisocpipe(dev->udev, 0x82);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300512 usb_fill_int_urb(urb, dev->udev, pipe,
513 dev->isoc_ctl.transfer_buffer[i], sb_size,
514 em28xx_irq_callback, dma_q, 1);
515
516 urb->number_of_packets = max_packets;
517 urb->transfer_flags = URB_ISO_ASAP;
518
519 k = 0;
520 for (j = 0; j < max_packets; j++) {
521 urb->iso_frame_desc[j].offset = k;
522 urb->iso_frame_desc[j].length =
523 dev->isoc_ctl.max_pkt_size;
524 k += dev->isoc_ctl.max_pkt_size;
525 }
526 }
527
528 return 0;
529}
530
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300531static int em28xx_start_thread(struct em28xx_dmaqueue *dma_q)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300532{
533 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300534 int i, rc = 0;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300535
536 em28xx_videodbg("Called em28xx_start_thread\n");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300537
538 init_waitqueue_head(&dma_q->wq);
539
Mauro Carvalho Chehab47625da2008-04-13 14:40:10 -0300540 em28xx_capture_start(dev, 1);
541
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300542 /* submit urbs and enables IRQ */
543 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
544 rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
545 if (rc) {
546 em28xx_err("submit of urb %i failed (error=%i)\n", i,
547 rc);
548 em28xx_uninit_isoc(dev);
549 return rc;
550 }
551 }
552
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300553 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300554 return rc;
555
556 return 0;
557}
558
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300559/* ------------------------------------------------------------------
560 Videobuf operations
561 ------------------------------------------------------------------*/
562
563static int
564buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
565{
566 struct em28xx_fh *fh = vq->priv_data;
567
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300568 *size = 16 * fh->dev->width * fh->dev->height >> 3;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300569 if (0 == *count)
570 *count = EM28XX_DEF_BUF;
571
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300572 if (*count < EM28XX_MIN_BUF)
573 *count = EM28XX_MIN_BUF;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300574
575 return 0;
576}
577
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300578/* This is called *without* dev->slock held; please keep it that way */
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300579static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
580{
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300581 struct em28xx_fh *fh = vq->priv_data;
582 struct em28xx *dev = fh->dev;
583 unsigned long flags = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300584 if (in_interrupt())
585 BUG();
586
Aidan Thornton3b5fa922008-04-13 15:09:36 -0300587 /* We used to wait for the buffer to finish here, but this didn't work
588 because, as we were keeping the state as VIDEOBUF_QUEUED,
589 videobuf_queue_cancel marked it as finished for us.
590 (Also, it could wedge forever if the hardware was misconfigured.)
591
592 This should be safe; by the time we get here, the buffer isn't
593 queued anymore. If we ever start marking the buffers as
594 VIDEOBUF_ACTIVE, it won't be, though.
595 */
596 spin_lock_irqsave(&dev->slock, flags);
597 if (dev->isoc_ctl.buf == buf)
598 dev->isoc_ctl.buf = NULL;
599 spin_unlock_irqrestore(&dev->slock, flags);
600
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300601 videobuf_vmalloc_free(&buf->vb);
602 buf->vb.state = VIDEOBUF_NEEDS_INIT;
603}
604
605static int
606buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
607 enum v4l2_field field)
608{
609 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300610 struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300611 struct em28xx *dev = fh->dev;
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300612 struct em28xx_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300613 int rc = 0, urb_init = 0;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300614
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300615 /* FIXME: It assumes depth = 16 */
616 /* The only currently supported format is 16 bits/pixel */
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300617 buf->vb.size = 16 * dev->width * dev->height >> 3;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300618
619 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
620 return -EINVAL;
621
Brandon Philips05612972008-04-13 14:57:01 -0300622 buf->vb.width = dev->width;
623 buf->vb.height = dev->height;
624 buf->vb.field = field;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300625
626 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300627 rc = videobuf_iolock(vq, &buf->vb, NULL);
628 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300629 goto fail;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300630 }
631
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300632 if (!dev->isoc_ctl.num_bufs)
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300633 urb_init = 1;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300634
635 if (urb_init) {
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300636 rc = em28xx_prepare_isoc(dev, EM28XX_NUM_PACKETS,
637 EM28XX_NUM_BUFS);
638 if (rc < 0)
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300639 goto fail;
640
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300641 rc = em28xx_start_thread(vidq);
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300642 if (rc < 0)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300643 goto fail;
644 }
645
646 buf->vb.state = VIDEOBUF_PREPARED;
647 return 0;
648
649fail:
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300650 free_buffer(vq, buf);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300651 return rc;
652}
653
654static void
655buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
656{
657 struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
658 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300659 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300660 struct em28xx_dmaqueue *vidq = &dev->vidq;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300661
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300662 buf->vb.state = VIDEOBUF_QUEUED;
663 list_add_tail(&buf->vb.queue, &vidq->active);
664
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300665}
666
667static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
668{
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300669 struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300670 struct em28xx_fh *fh = vq->priv_data;
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300671 struct em28xx *dev = (struct em28xx *)fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300672
Aidan Thorntond7aa8022008-04-13 14:38:47 -0300673 em28xx_isocdbg("em28xx: called buffer_release\n");
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300674
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -0300675 free_buffer(vq, buf);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300676}
677
678static struct videobuf_queue_ops em28xx_video_qops = {
679 .buf_setup = buffer_setup,
680 .buf_prepare = buffer_prepare,
681 .buf_queue = buffer_queue,
682 .buf_release = buffer_release,
683};
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800684
685/********************* v4l2 interface ******************************************/
686
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800687/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800688 * em28xx_config()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800689 * inits registers with sane defaults
690 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800691static int em28xx_config(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800692{
693
694 /* Sets I2C speed to 100 KHz */
Sascha Sommer2b2c93a2007-11-03 16:48:01 -0300695 if (!dev->is_em2800)
696 em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800697
698 /* enable vbi capturing */
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -0200699
Markus Rechberger9475fb12006-02-27 00:07:34 -0300700/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
701/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -0200702 em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
703
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800704 dev->mute = 1; /* maybe not the right place... */
705 dev->volume = 0x1f;
Mauro Carvalho Chehab539c96d2008-01-05 09:53:54 -0300706
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800707 em28xx_outfmt_set_yuv422(dev);
708 em28xx_colorlevels_set_default(dev);
709 em28xx_compression_disable(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800710
711 return 0;
712}
713
714/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -0800715 * em28xx_config_i2c()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800716 * configure i2c attached devices
717 */
Adrian Bunk943a4902005-12-01 00:51:35 -0800718static void em28xx_config_i2c(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800719{
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300720 struct v4l2_routing route;
721
722 route.input = INPUT(dev->ctl_input)->vmux;
723 route.output = 0;
Al Viro663d1ba2006-10-10 22:48:37 +0100724 em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300725 em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300726 em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800727}
728
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800729static void video_mux(struct em28xx *dev, int index)
730{
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300731 struct v4l2_routing route;
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800732
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300733 route.input = INPUT(index)->vmux;
734 route.output = 0;
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800735 dev->ctl_input = index;
736 dev->ctl_ainput = INPUT(index)->amux;
737
Hans Verkuilc7c0b342006-04-02 13:35:00 -0300738 em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800739
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800740 if (dev->has_msp34xx) {
Mauro Carvalho Chehab9bb13a62006-01-09 15:25:37 -0200741 if (dev->i2s_speed)
742 em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
Hans Verkuil2474ed42006-03-19 12:35:57 -0300743 route.input = dev->ctl_ainput;
Hans Verkuil07151722006-04-01 18:03:23 -0300744 route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
Hans Verkuil2474ed42006-03-19 12:35:57 -0300745 /* Note: this is msp3400 specific */
746 em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800747 }
Mauro Carvalho Chehab539c96d2008-01-05 09:53:54 -0300748
Mauro Carvalho Chehab00b87302008-02-06 18:34:13 -0300749 em28xx_audio_analog_set(dev);
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -0800750}
751
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300752/* Usage lock check functions */
753static int res_get(struct em28xx_fh *fh)
754{
755 struct em28xx *dev = fh->dev;
756 int rc = 0;
757
758 /* This instance already has stream_on */
759 if (fh->stream_on)
760 return rc;
761
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300762 if (dev->stream_on)
Mauro Carvalho Chehabe74153d2008-04-13 14:55:38 -0300763 return -EINVAL;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300764
Mauro Carvalho Chehabe74153d2008-04-13 14:55:38 -0300765 mutex_lock(&dev->lock);
766 dev->stream_on = 1;
767 fh->stream_on = 1;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -0300768 mutex_unlock(&dev->lock);
769 return rc;
770}
771
772static int res_check(struct em28xx_fh *fh)
773{
774 return (fh->stream_on);
775}
776
777static void res_free(struct em28xx_fh *fh)
778{
779 struct em28xx *dev = fh->dev;
780
781 mutex_lock(&dev->lock);
782 fh->stream_on = 0;
783 dev->stream_on = 0;
784 mutex_unlock(&dev->lock);
785}
786
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -0800787/*
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300788 * em28xx_get_ctrl()
789 * return the current saturation, brightness or contrast, mute state
790 */
791static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
792{
793 switch (ctrl->id) {
794 case V4L2_CID_AUDIO_MUTE:
795 ctrl->value = dev->mute;
796 return 0;
797 case V4L2_CID_AUDIO_VOLUME:
798 ctrl->value = dev->volume;
799 return 0;
800 default:
801 return -EINVAL;
802 }
803}
804
805/*
806 * em28xx_set_ctrl()
807 * mute or set new saturation, brightness or contrast
808 */
809static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
810{
811 switch (ctrl->id) {
812 case V4L2_CID_AUDIO_MUTE:
813 if (ctrl->value != dev->mute) {
814 dev->mute = ctrl->value;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300815 return em28xx_audio_analog_set(dev);
816 }
817 return 0;
818 case V4L2_CID_AUDIO_VOLUME:
819 dev->volume = ctrl->value;
820 return em28xx_audio_analog_set(dev);
821 default:
822 return -EINVAL;
823 }
824}
825
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300826static int check_dev(struct em28xx *dev)
827{
828 if (dev->state & DEV_DISCONNECTED) {
829 em28xx_errdev("v4l2 ioctl: device not present\n");
830 return -ENODEV;
831 }
832
833 if (dev->state & DEV_MISCONFIGURED) {
834 em28xx_errdev("v4l2 ioctl: device is misconfigured; "
835 "close and open it again\n");
836 return -EIO;
837 }
838 return 0;
839}
840
841static void get_scale(struct em28xx *dev,
842 unsigned int width, unsigned int height,
843 unsigned int *hscale, unsigned int *vscale)
844{
845 unsigned int maxw = norm_maxw(dev);
846 unsigned int maxh = norm_maxh(dev);
847
848 *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
849 if (*hscale >= 0x4000)
850 *hscale = 0x3fff;
851
852 *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
853 if (*vscale >= 0x4000)
854 *vscale = 0x3fff;
855}
856
857/* ------------------------------------------------------------------
858 IOCTL vidioc handling
859 ------------------------------------------------------------------*/
860
861static int vidioc_g_fmt_cap(struct file *file, void *priv,
862 struct v4l2_format *f)
863{
864 struct em28xx_fh *fh = priv;
865 struct em28xx *dev = fh->dev;
866
867 mutex_lock(&dev->lock);
868
869 f->fmt.pix.width = dev->width;
870 f->fmt.pix.height = dev->height;
871 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
Mauro Carvalho Chehab44dc7332008-04-13 15:11:08 -0300872 f->fmt.pix.bytesperline = dev->width * 2;
873 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300874 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
875
876 /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
877 f->fmt.pix.field = dev->interlaced ?
878 V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
879
880 mutex_unlock(&dev->lock);
881 return 0;
882}
883
884static int vidioc_try_fmt_cap(struct file *file, void *priv,
885 struct v4l2_format *f)
886{
887 struct em28xx_fh *fh = priv;
888 struct em28xx *dev = fh->dev;
889 int width = f->fmt.pix.width;
890 int height = f->fmt.pix.height;
891 unsigned int maxw = norm_maxw(dev);
892 unsigned int maxh = norm_maxh(dev);
893 unsigned int hscale, vscale;
894
895 /* width must even because of the YUYV format
896 height must be even because of interlacing */
897 height &= 0xfffe;
898 width &= 0xfffe;
899
900 if (height < 32)
901 height = 32;
902 if (height > maxh)
903 height = maxh;
904 if (width < 48)
905 width = 48;
906 if (width > maxw)
907 width = maxw;
908
909 mutex_lock(&dev->lock);
910
911 if (dev->is_em2800) {
912 /* the em2800 can only scale down to 50% */
913 if (height % (maxh / 2))
914 height = maxh;
915 if (width % (maxw / 2))
916 width = maxw;
917 /* according to empiatech support */
918 /* the MaxPacketSize is to small to support */
919 /* framesizes larger than 640x480 @ 30 fps */
920 /* or 640x576 @ 25 fps. As this would cut */
921 /* of a part of the image we prefer */
922 /* 360x576 or 360x480 for now */
923 if (width == maxw && height == maxh)
924 width /= 2;
925 }
926
927 get_scale(dev, width, height, &hscale, &vscale);
928
929 width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
930 height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
931
932 f->fmt.pix.width = width;
933 f->fmt.pix.height = height;
934 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
935 f->fmt.pix.bytesperline = width * 2;
936 f->fmt.pix.sizeimage = width * 2 * height;
937 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
938 f->fmt.pix.field = V4L2_FIELD_INTERLACED;
939
940 mutex_unlock(&dev->lock);
941 return 0;
942}
943
944static int vidioc_s_fmt_cap(struct file *file, void *priv,
945 struct v4l2_format *f)
946{
947 struct em28xx_fh *fh = priv;
948 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -0300949 int rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300950
951 rc = check_dev(dev);
952 if (rc < 0)
953 return rc;
954
955 vidioc_try_fmt_cap(file, priv, f);
956
957 mutex_lock(&dev->lock);
958
Brandon Philips05612972008-04-13 14:57:01 -0300959 if (videobuf_queue_is_busy(&fh->vb_vidq)) {
960 em28xx_errdev("%s queue busy\n", __func__);
961 rc = -EBUSY;
962 goto out;
963 }
964
Aidan Thornton0ea13e62008-04-13 15:02:24 -0300965 if (dev->stream_on && !fh->stream_on) {
966 em28xx_errdev("%s device in use by another fh\n", __func__);
967 rc = -EBUSY;
968 goto out;
969 }
970
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300971 /* set new image size */
972 dev->width = f->fmt.pix.width;
973 dev->height = f->fmt.pix.height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300974 get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
975
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300976 em28xx_set_alternate(dev);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300977 em28xx_resolution_set(dev);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300978
Brandon Philips05612972008-04-13 14:57:01 -0300979 rc = 0;
980
981out:
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300982 mutex_unlock(&dev->lock);
Brandon Philips05612972008-04-13 14:57:01 -0300983 return rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300984}
985
986static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
987{
988 struct em28xx_fh *fh = priv;
989 struct em28xx *dev = fh->dev;
990 struct v4l2_format f;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300991 int rc;
992
993 rc = check_dev(dev);
994 if (rc < 0)
995 return rc;
996
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300997 mutex_lock(&dev->lock);
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -0300998 dev->norm = *norm;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -0300999 mutex_unlock(&dev->lock);
1000
1001 /* Adjusts width/height, if needed */
1002 f.fmt.pix.width = dev->width;
1003 f.fmt.pix.height = dev->height;
1004 vidioc_try_fmt_cap(file, priv, &f);
1005
1006 mutex_lock(&dev->lock);
1007
1008 /* set new image size */
1009 dev->width = f.fmt.pix.width;
1010 dev->height = f.fmt.pix.height;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001011 get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
1012
1013 em28xx_resolution_set(dev);
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001014 em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001015
1016 mutex_unlock(&dev->lock);
1017 return 0;
1018}
1019
1020static const char *iname[] = {
1021 [EM28XX_VMUX_COMPOSITE1] = "Composite1",
1022 [EM28XX_VMUX_COMPOSITE2] = "Composite2",
1023 [EM28XX_VMUX_COMPOSITE3] = "Composite3",
1024 [EM28XX_VMUX_COMPOSITE4] = "Composite4",
1025 [EM28XX_VMUX_SVIDEO] = "S-Video",
1026 [EM28XX_VMUX_TELEVISION] = "Television",
1027 [EM28XX_VMUX_CABLE] = "Cable TV",
1028 [EM28XX_VMUX_DVB] = "DVB",
1029 [EM28XX_VMUX_DEBUG] = "for debug only",
1030};
1031
1032static int vidioc_enum_input(struct file *file, void *priv,
1033 struct v4l2_input *i)
1034{
1035 struct em28xx_fh *fh = priv;
1036 struct em28xx *dev = fh->dev;
1037 unsigned int n;
1038
1039 n = i->index;
1040 if (n >= MAX_EM28XX_INPUT)
1041 return -EINVAL;
1042 if (0 == INPUT(n)->type)
1043 return -EINVAL;
1044
1045 i->index = n;
1046 i->type = V4L2_INPUT_TYPE_CAMERA;
1047
1048 strcpy(i->name, iname[INPUT(n)->type]);
1049
1050 if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
1051 (EM28XX_VMUX_CABLE == INPUT(n)->type))
1052 i->type = V4L2_INPUT_TYPE_TUNER;
1053
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001054 i->std = dev->vdev->tvnorms;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001055
1056 return 0;
1057}
1058
1059static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
1060{
1061 struct em28xx_fh *fh = priv;
1062 struct em28xx *dev = fh->dev;
1063
1064 *i = dev->ctl_input;
1065
1066 return 0;
1067}
1068
1069static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
1070{
1071 struct em28xx_fh *fh = priv;
1072 struct em28xx *dev = fh->dev;
1073 int rc;
1074
1075 rc = check_dev(dev);
1076 if (rc < 0)
1077 return rc;
1078
1079 if (i >= MAX_EM28XX_INPUT)
1080 return -EINVAL;
1081 if (0 == INPUT(i)->type)
1082 return -EINVAL;
1083
1084 mutex_lock(&dev->lock);
1085
1086 video_mux(dev, i);
1087
1088 mutex_unlock(&dev->lock);
1089 return 0;
1090}
1091
1092static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
1093{
1094 struct em28xx_fh *fh = priv;
1095 struct em28xx *dev = fh->dev;
1096 unsigned int index = a->index;
1097
1098 if (a->index > 1)
1099 return -EINVAL;
1100
1101 index = dev->ctl_ainput;
1102
1103 if (index == 0) {
1104 strcpy(a->name, "Television");
1105 } else {
1106 strcpy(a->name, "Line In");
1107 }
1108 a->capability = V4L2_AUDCAP_STEREO;
1109 a->index = index;
1110
1111 return 0;
1112}
1113
1114static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
1115{
1116 struct em28xx_fh *fh = priv;
1117 struct em28xx *dev = fh->dev;
1118
1119 if (a->index != dev->ctl_ainput)
1120 return -EINVAL;
1121
1122 return 0;
1123}
1124
1125static int vidioc_queryctrl(struct file *file, void *priv,
1126 struct v4l2_queryctrl *qc)
1127{
1128 struct em28xx_fh *fh = priv;
1129 struct em28xx *dev = fh->dev;
1130 int id = qc->id;
1131 int i;
1132 int rc;
1133
1134 rc = check_dev(dev);
1135 if (rc < 0)
1136 return rc;
1137
1138 memset(qc, 0, sizeof(*qc));
1139
1140 qc->id = id;
1141
1142 if (!dev->has_msp34xx) {
1143 for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
1144 if (qc->id && qc->id == em28xx_qctrl[i].id) {
1145 memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
1146 return 0;
1147 }
1148 }
1149 }
1150 mutex_lock(&dev->lock);
1151 em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc);
1152 mutex_unlock(&dev->lock);
1153
1154 if (qc->type)
1155 return 0;
1156 else
1157 return -EINVAL;
1158}
1159
1160static int vidioc_g_ctrl(struct file *file, void *priv,
1161 struct v4l2_control *ctrl)
1162{
1163 struct em28xx_fh *fh = priv;
1164 struct em28xx *dev = fh->dev;
1165 int rc;
1166
1167 rc = check_dev(dev);
1168 if (rc < 0)
1169 return rc;
1170 mutex_lock(&dev->lock);
1171
1172 if (!dev->has_msp34xx)
1173 rc = em28xx_get_ctrl(dev, ctrl);
1174 else
1175 rc = -EINVAL;
1176
1177 if (rc == -EINVAL) {
1178 em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
1179 rc = 0;
1180 }
1181
1182 mutex_unlock(&dev->lock);
1183 return rc;
1184}
1185
1186static int vidioc_s_ctrl(struct file *file, void *priv,
1187 struct v4l2_control *ctrl)
1188{
1189 struct em28xx_fh *fh = priv;
1190 struct em28xx *dev = fh->dev;
1191 u8 i;
1192 int rc;
1193
1194 rc = check_dev(dev);
1195 if (rc < 0)
1196 return rc;
1197
1198 mutex_lock(&dev->lock);
1199
1200 if (dev->has_msp34xx)
1201 em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
1202 else {
1203 rc = 1;
1204 for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
1205 if (ctrl->id == em28xx_qctrl[i].id) {
1206 if (ctrl->value < em28xx_qctrl[i].minimum ||
1207 ctrl->value > em28xx_qctrl[i].maximum) {
1208 rc = -ERANGE;
1209 break;
1210 }
1211
1212 rc = em28xx_set_ctrl(dev, ctrl);
1213 break;
1214 }
1215 }
1216 }
1217
1218 /* Control not found - try to send it to the attached devices */
1219 if (rc == 1) {
1220 em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
1221 rc = 0;
1222 }
1223
1224 mutex_unlock(&dev->lock);
1225 return rc;
1226}
1227
1228static int vidioc_g_tuner(struct file *file, void *priv,
1229 struct v4l2_tuner *t)
1230{
1231 struct em28xx_fh *fh = priv;
1232 struct em28xx *dev = fh->dev;
1233 int rc;
1234
1235 rc = check_dev(dev);
1236 if (rc < 0)
1237 return rc;
1238
1239 if (0 != t->index)
1240 return -EINVAL;
1241
1242 strcpy(t->name, "Tuner");
1243
1244 mutex_lock(&dev->lock);
1245
1246 em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
1247
1248 mutex_unlock(&dev->lock);
1249 return 0;
1250}
1251
1252static int vidioc_s_tuner(struct file *file, void *priv,
1253 struct v4l2_tuner *t)
1254{
1255 struct em28xx_fh *fh = priv;
1256 struct em28xx *dev = fh->dev;
1257 int rc;
1258
1259 rc = check_dev(dev);
1260 if (rc < 0)
1261 return rc;
1262
1263 if (0 != t->index)
1264 return -EINVAL;
1265
1266 mutex_lock(&dev->lock);
1267
1268 em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
1269
1270 mutex_unlock(&dev->lock);
1271 return 0;
1272}
1273
1274static int vidioc_g_frequency(struct file *file, void *priv,
1275 struct v4l2_frequency *f)
1276{
1277 struct em28xx_fh *fh = priv;
1278 struct em28xx *dev = fh->dev;
1279
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001280 f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001281 f->frequency = dev->ctl_freq;
1282
1283 return 0;
1284}
1285
1286static int vidioc_s_frequency(struct file *file, void *priv,
1287 struct v4l2_frequency *f)
1288{
1289 struct em28xx_fh *fh = priv;
1290 struct em28xx *dev = fh->dev;
1291 int rc;
1292
1293 rc = check_dev(dev);
1294 if (rc < 0)
1295 return rc;
1296
1297 if (0 != f->tuner)
1298 return -EINVAL;
1299
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001300 if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
1301 return -EINVAL;
1302 if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001303 return -EINVAL;
1304
1305 mutex_lock(&dev->lock);
1306
1307 dev->ctl_freq = f->frequency;
1308 em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
1309
1310 mutex_unlock(&dev->lock);
1311 return 0;
1312}
1313
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001314#ifdef CONFIG_VIDEO_ADV_DEBUG
1315static int em28xx_reg_len(int reg)
1316{
1317 switch (reg) {
1318 case AC97LSB_REG:
1319 case HSCALELOW_REG:
1320 case VSCALELOW_REG:
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001321 return 2;
1322 default:
1323 return 1;
1324 }
1325}
1326
1327static int vidioc_g_register(struct file *file, void *priv,
1328 struct v4l2_register *reg)
1329{
1330 struct em28xx_fh *fh = priv;
1331 struct em28xx *dev = fh->dev;
1332 int ret;
1333
1334 if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
1335 return -EINVAL;
1336
1337 if (em28xx_reg_len(reg->reg) == 1) {
1338 ret = em28xx_read_reg(dev, reg->reg);
1339 if (ret < 0)
1340 return ret;
1341
1342 reg->val = ret;
1343 } else {
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001344 u64 val = 0;
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001345 ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
1346 reg->reg, (char *)&val, 2);
1347 if (ret < 0)
1348 return ret;
1349
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001350 reg->val = cpu_to_le64((__u64)val);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001351 }
1352
1353 return 0;
1354}
1355
1356static int vidioc_s_register(struct file *file, void *priv,
1357 struct v4l2_register *reg)
1358{
1359 struct em28xx_fh *fh = priv;
1360 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001361 u64 buf;
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001362
Mauro Carvalho Chehab0df81302008-02-06 15:56:16 -03001363 buf = le64_to_cpu((__u64)reg->val);
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001364
1365 return em28xx_write_regs(dev, reg->reg, (char *)&buf,
1366 em28xx_reg_len(reg->reg));
1367}
1368#endif
1369
1370
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001371static int vidioc_cropcap(struct file *file, void *priv,
1372 struct v4l2_cropcap *cc)
1373{
1374 struct em28xx_fh *fh = priv;
1375 struct em28xx *dev = fh->dev;
1376
1377 if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1378 return -EINVAL;
1379
1380 cc->bounds.left = 0;
1381 cc->bounds.top = 0;
1382 cc->bounds.width = dev->width;
1383 cc->bounds.height = dev->height;
1384 cc->defrect = cc->bounds;
1385 cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
1386 cc->pixelaspect.denominator = 59;
1387
1388 return 0;
1389}
1390
1391static int vidioc_streamon(struct file *file, void *priv,
1392 enum v4l2_buf_type type)
1393{
1394 struct em28xx_fh *fh = priv;
1395 struct em28xx *dev = fh->dev;
1396 int rc;
1397
1398 rc = check_dev(dev);
1399 if (rc < 0)
1400 return rc;
1401
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001402
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001403 if (unlikely(res_get(fh) < 0))
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001404 return -EBUSY;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001405
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001406 return (videobuf_streamon(&fh->vb_vidq));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001407}
1408
1409static int vidioc_streamoff(struct file *file, void *priv,
1410 enum v4l2_buf_type type)
1411{
1412 struct em28xx_fh *fh = priv;
1413 struct em28xx *dev = fh->dev;
1414 int rc;
1415
1416 rc = check_dev(dev);
1417 if (rc < 0)
1418 return rc;
1419
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001420 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1421 return -EINVAL;
1422 if (type != fh->type)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001423 return -EINVAL;
1424
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001425 videobuf_streamoff(&fh->vb_vidq);
1426 res_free(fh);
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001427
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001428 return 0;
1429}
1430
1431static int vidioc_querycap(struct file *file, void *priv,
1432 struct v4l2_capability *cap)
1433{
1434 struct em28xx_fh *fh = priv;
1435 struct em28xx *dev = fh->dev;
1436
1437 strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
1438 strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
1439 strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
1440
1441 cap->version = EM28XX_VERSION_CODE;
1442
1443 cap->capabilities =
1444 V4L2_CAP_SLICED_VBI_CAPTURE |
1445 V4L2_CAP_VIDEO_CAPTURE |
1446 V4L2_CAP_AUDIO |
1447 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
1448
Mauro Carvalho Chehabed086312008-01-24 06:59:20 -03001449 if (dev->tuner_type != TUNER_ABSENT)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001450 cap->capabilities |= V4L2_CAP_TUNER;
1451
1452 return 0;
1453}
1454
1455static int vidioc_enum_fmt_cap(struct file *file, void *priv,
1456 struct v4l2_fmtdesc *fmtd)
1457{
1458 if (fmtd->index != 0)
1459 return -EINVAL;
1460
1461 fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1462 strcpy(fmtd->description, "Packed YUY2");
1463 fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
1464 memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
1465
1466 return 0;
1467}
1468
1469/* Sliced VBI ioctls */
1470static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
1471 struct v4l2_format *f)
1472{
1473 struct em28xx_fh *fh = priv;
1474 struct em28xx *dev = fh->dev;
1475 int rc;
1476
1477 rc = check_dev(dev);
1478 if (rc < 0)
1479 return rc;
1480
1481 mutex_lock(&dev->lock);
1482
1483 f->fmt.sliced.service_set = 0;
1484
1485 em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
1486
1487 if (f->fmt.sliced.service_set == 0)
1488 rc = -EINVAL;
1489
1490 mutex_unlock(&dev->lock);
1491 return rc;
1492}
1493
1494static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
1495 struct v4l2_format *f)
1496{
1497 struct em28xx_fh *fh = priv;
1498 struct em28xx *dev = fh->dev;
1499 int rc;
1500
1501 rc = check_dev(dev);
1502 if (rc < 0)
1503 return rc;
1504
1505 mutex_lock(&dev->lock);
1506 em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
1507 mutex_unlock(&dev->lock);
1508
1509 if (f->fmt.sliced.service_set == 0)
1510 return -EINVAL;
1511
1512 return 0;
1513}
1514
1515
1516static int vidioc_reqbufs(struct file *file, void *priv,
1517 struct v4l2_requestbuffers *rb)
1518{
1519 struct em28xx_fh *fh = priv;
1520 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001521 int rc;
1522
1523 rc = check_dev(dev);
1524 if (rc < 0)
1525 return rc;
1526
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001527 return (videobuf_reqbufs(&fh->vb_vidq, rb));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001528}
1529
1530static int vidioc_querybuf(struct file *file, void *priv,
1531 struct v4l2_buffer *b)
1532{
1533 struct em28xx_fh *fh = priv;
1534 struct em28xx *dev = fh->dev;
1535 int rc;
1536
1537 rc = check_dev(dev);
1538 if (rc < 0)
1539 return rc;
1540
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001541 return (videobuf_querybuf(&fh->vb_vidq, b));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001542}
1543
1544static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
1545{
1546 struct em28xx_fh *fh = priv;
1547 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001548 int rc;
1549
1550 rc = check_dev(dev);
1551 if (rc < 0)
1552 return rc;
1553
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001554 return (videobuf_qbuf(&fh->vb_vidq, b));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001555}
1556
1557static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
1558{
1559 struct em28xx_fh *fh = priv;
1560 struct em28xx *dev = fh->dev;
1561 int rc;
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001562
1563 rc = check_dev(dev);
1564 if (rc < 0)
1565 return rc;
1566
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001567 return (videobuf_dqbuf(&fh->vb_vidq, b,
1568 file->f_flags & O_NONBLOCK));
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001569}
1570
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001571#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001572static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001573{
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001574 struct em28xx_fh *fh = priv;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001575
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001576 return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001577}
1578#endif
1579
1580
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001581/* ----------------------------------------------------------- */
1582/* RADIO ESPECIFIC IOCTLS */
1583/* ----------------------------------------------------------- */
1584
1585static int radio_querycap(struct file *file, void *priv,
1586 struct v4l2_capability *cap)
1587{
1588 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1589
1590 strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
1591 strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
1592 strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
1593
1594 cap->version = EM28XX_VERSION_CODE;
1595 cap->capabilities = V4L2_CAP_TUNER;
1596 return 0;
1597}
1598
1599static int radio_g_tuner(struct file *file, void *priv,
1600 struct v4l2_tuner *t)
1601{
1602 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1603
1604 if (unlikely(t->index > 0))
1605 return -EINVAL;
1606
1607 strcpy(t->name, "Radio");
1608 t->type = V4L2_TUNER_RADIO;
1609
1610 em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
1611 return 0;
1612}
1613
1614static int radio_enum_input(struct file *file, void *priv,
1615 struct v4l2_input *i)
1616{
1617 if (i->index != 0)
1618 return -EINVAL;
1619 strcpy(i->name, "Radio");
1620 i->type = V4L2_INPUT_TYPE_TUNER;
1621
1622 return 0;
1623}
1624
1625static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
1626{
1627 if (unlikely(a->index))
1628 return -EINVAL;
1629
1630 strcpy(a->name, "Radio");
1631 return 0;
1632}
1633
1634static int radio_s_tuner(struct file *file, void *priv,
1635 struct v4l2_tuner *t)
1636{
1637 struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
1638
1639 if (0 != t->index)
1640 return -EINVAL;
1641
1642 em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
1643
1644 return 0;
1645}
1646
1647static int radio_s_audio(struct file *file, void *fh,
1648 struct v4l2_audio *a)
1649{
1650 return 0;
1651}
1652
1653static int radio_s_input(struct file *file, void *fh, unsigned int i)
1654{
1655 return 0;
1656}
1657
1658static int radio_queryctrl(struct file *file, void *priv,
1659 struct v4l2_queryctrl *qc)
1660{
1661 int i;
1662
1663 if (qc->id < V4L2_CID_BASE ||
1664 qc->id >= V4L2_CID_LASTP1)
1665 return -EINVAL;
1666
1667 for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
1668 if (qc->id && qc->id == em28xx_qctrl[i].id) {
1669 memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
1670 return 0;
1671 }
1672 }
1673
1674 return -EINVAL;
1675}
1676
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001677/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001678 * em28xx_v4l2_open()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001679 * inits the device and starts isoc transfer
1680 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001681static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001682{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001683 int minor = iminor(inode);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001684 int errCode = 0, radio = 0;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001685 struct em28xx *h,*dev = NULL;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001686 struct em28xx_fh *fh;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001687 enum v4l2_buf_type fh_type = 0;
Markus Rechberger9c755412005-11-08 21:37:52 -08001688
Trent Piephoa991f442007-10-10 05:37:43 -03001689 list_for_each_entry(h, &em28xx_devlist, devlist) {
Markus Rechberger9c755412005-11-08 21:37:52 -08001690 if (h->vdev->minor == minor) {
1691 dev = h;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001692 fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001693 }
1694 if (h->vbi_dev->minor == minor) {
1695 dev = h;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001696 fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
Markus Rechberger9c755412005-11-08 21:37:52 -08001697 }
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001698 if (h->radio_dev &&
1699 h->radio_dev->minor == minor) {
1700 radio = 1;
1701 dev = h;
1702 }
Markus Rechberger9c755412005-11-08 21:37:52 -08001703 }
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001704 if (NULL == dev)
1705 return -ENODEV;
Markus Rechberger9c755412005-11-08 21:37:52 -08001706
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001707 em28xx_videodbg("open minor=%d type=%s users=%d\n",
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001708 minor, v4l2_type_names[fh_type], dev->users);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001709
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001710 fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001711
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001712 if (!fh) {
1713 em28xx_errdev("em28xx-video.c: Out of memory?!\n");
1714 return -ENOMEM;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001715 }
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001716 mutex_lock(&dev->lock);
1717 fh->dev = dev;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001718 fh->radio = radio;
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001719 fh->type = fh_type;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001720 filp->private_data = fh;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001721
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001722 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001723 dev->width = norm_maxw(dev);
1724 dev->height = norm_maxh(dev);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001725 dev->hscale = 0;
1726 dev->vscale = 0;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001727
Mauro Carvalho Chehab3687e1e2008-02-08 15:44:25 -03001728 em28xx_set_alternate(dev);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001729 em28xx_resolution_set(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001730
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001731 }
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001732 if (fh->radio) {
1733 em28xx_videodbg("video_open: setting radio device\n");
1734 em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL);
1735 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001736
1737 dev->users++;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001738
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001739 videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
1740 NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
1741 sizeof(struct em28xx_buffer), fh);
1742
Ingo Molnar3593cab2006-02-07 06:49:14 -02001743 mutex_unlock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001744 return errCode;
1745}
1746
1747/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001748 * em28xx_realease_resources()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001749 * unregisters the v4l2,i2c and usb devices
1750 * called when the device gets disconected or at module unload
1751*/
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001752static void em28xx_release_resources(struct em28xx *dev)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001753{
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001754
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001755 /*FIXME: I2C IR should be disconnected */
1756
1757 em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
1758 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
1759 dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
Markus Rechberger9c755412005-11-08 21:37:52 -08001760 list_del(&dev->devlist);
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001761 if (dev->radio_dev) {
1762 if (-1 != dev->radio_dev->minor)
1763 video_unregister_device(dev->radio_dev);
1764 else
1765 video_device_release(dev->radio_dev);
1766 dev->radio_dev = NULL;
1767 }
1768 if (dev->vbi_dev) {
1769 if (-1 != dev->vbi_dev->minor)
1770 video_unregister_device(dev->vbi_dev);
1771 else
1772 video_device_release(dev->vbi_dev);
1773 dev->vbi_dev = NULL;
1774 }
1775 if (dev->vdev) {
1776 if (-1 != dev->vdev->minor)
1777 video_unregister_device(dev->vdev);
1778 else
1779 video_device_release(dev->vdev);
1780 dev->vdev = NULL;
1781 }
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001782 em28xx_i2c_unregister(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001783 usb_put_dev(dev->udev);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001784
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001785 /* Mark device as unused */
1786 em28xx_devused&=~(1<<dev->devno);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001787}
1788
1789/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001790 * em28xx_v4l2_close()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001791 * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
1792 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001793static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001794{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001795 struct em28xx_fh *fh = filp->private_data;
1796 struct em28xx *dev = fh->dev;
1797 int errCode;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001798
Mauro Carvalho Chehabeac94352005-11-08 21:38:43 -08001799 em28xx_videodbg("users=%d\n", dev->users);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001800
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001801
1802 if (res_check(fh))
1803 res_free(fh);
1804
Ingo Molnar3593cab2006-02-07 06:49:14 -02001805 mutex_lock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001806
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001807 if (dev->users == 1) {
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001808 videobuf_stop(&fh->vb_vidq);
1809 videobuf_mmap_free(&fh->vb_vidq);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001810
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001811 /* the device is already disconnect,
1812 free the remaining resources */
1813 if (dev->state & DEV_DISCONNECTED) {
1814 em28xx_release_resources(dev);
1815 mutex_unlock(&dev->lock);
1816 kfree(dev);
1817 return 0;
1818 }
1819
Aidan Thorntond7aa8022008-04-13 14:38:47 -03001820 /* do this before setting alternate! */
1821 em28xx_uninit_isoc(dev);
1822
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001823 /* set alternate 0 */
1824 dev->alt = 0;
1825 em28xx_videodbg("setting alternate 0\n");
1826 errCode = usb_set_interface(dev->udev, 0, 0);
1827 if (errCode < 0) {
1828 em28xx_errdev("cannot change alternate number to "
1829 "0 (error=%i)\n", errCode);
1830 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001831 }
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001832 kfree(fh);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001833 dev->users--;
1834 wake_up_interruptible_nr(&dev->open, 1);
Ingo Molnar3593cab2006-02-07 06:49:14 -02001835 mutex_unlock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001836 return 0;
1837}
1838
1839/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001840 * em28xx_v4l2_read()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001841 * will allocate buffers when called for the first time
1842 */
1843static ssize_t
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001844em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
Mauro Carvalho Chehabf245e542008-04-13 14:41:23 -03001845 loff_t *pos)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001846{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001847 struct em28xx_fh *fh = filp->private_data;
1848 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001849 int rc;
1850
1851 rc = check_dev(dev);
1852 if (rc < 0)
1853 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001854
Mauro Carvalho Chehab9e31ced2007-11-11 01:13:49 -03001855 /* FIXME: read() is not prepared to allow changing the video
1856 resolution while streaming. Seems a bug at em28xx_set_fmt
1857 */
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001858
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001859 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1860 if (unlikely(res_get(fh)))
1861 return -EBUSY;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001862
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001863 return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
1864 filp->f_flags & O_NONBLOCK);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02001865 }
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001866 return 0;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001867}
1868
1869/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001870 * em28xx_v4l2_poll()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001871 * will allocate buffers when called for the first time
1872 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001873static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001874{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001875 struct em28xx_fh *fh = filp->private_data;
1876 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001877 int rc;
1878
1879 rc = check_dev(dev);
1880 if (rc < 0)
1881 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001882
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001883 if (unlikely(res_get(fh) < 0))
1884 return POLLERR;
1885
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001886 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1887 return POLLERR;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001888
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001889 return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001890}
1891
1892/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001893 * em28xx_v4l2_mmap()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001894 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08001895static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001896{
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001897 struct em28xx_fh *fh = filp->private_data;
1898 struct em28xx *dev = fh->dev;
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001899 int rc;
Markus Rechberger9c755412005-11-08 21:37:52 -08001900
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001901 if (unlikely(res_get(fh) < 0))
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001902 return -EBUSY;
Mauro Carvalho Chehaba2254522007-11-11 01:08:26 -03001903
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001904 rc = check_dev(dev);
1905 if (rc < 0)
1906 return rc;
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03001907
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001908 rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001909
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001910 em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
1911 (unsigned long)vma->vm_start,
1912 (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
1913 rc);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001914
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001915 return rc;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001916}
1917
Arjan van de Venfa027c22007-02-12 00:55:33 -08001918static const struct file_operations em28xx_v4l_fops = {
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001919 .owner = THIS_MODULE,
1920 .open = em28xx_v4l2_open,
1921 .release = em28xx_v4l2_close,
1922 .read = em28xx_v4l2_read,
1923 .poll = em28xx_v4l2_poll,
1924 .mmap = em28xx_v4l2_mmap,
1925 .ioctl = video_ioctl2,
1926 .llseek = no_llseek,
1927 .compat_ioctl = v4l_compat_ioctl32,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08001928};
1929
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001930static const struct file_operations radio_fops = {
1931 .owner = THIS_MODULE,
1932 .open = em28xx_v4l2_open,
1933 .release = em28xx_v4l2_close,
1934 .ioctl = video_ioctl2,
1935 .compat_ioctl = v4l_compat_ioctl32,
1936 .llseek = no_llseek,
1937};
1938
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001939static const struct video_device em28xx_video_template = {
1940 .fops = &em28xx_v4l_fops,
1941 .release = video_device_release,
1942
1943 .minor = -1,
1944 .vidioc_querycap = vidioc_querycap,
1945 .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
1946 .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
1947 .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
1948 .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
1949 .vidioc_g_audio = vidioc_g_audio,
1950 .vidioc_s_audio = vidioc_s_audio,
1951 .vidioc_cropcap = vidioc_cropcap,
1952
1953 .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture,
1954 .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
1955 .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture,
1956
1957 .vidioc_reqbufs = vidioc_reqbufs,
1958 .vidioc_querybuf = vidioc_querybuf,
1959 .vidioc_qbuf = vidioc_qbuf,
1960 .vidioc_dqbuf = vidioc_dqbuf,
1961 .vidioc_s_std = vidioc_s_std,
1962 .vidioc_enum_input = vidioc_enum_input,
1963 .vidioc_g_input = vidioc_g_input,
1964 .vidioc_s_input = vidioc_s_input,
1965 .vidioc_queryctrl = vidioc_queryctrl,
1966 .vidioc_g_ctrl = vidioc_g_ctrl,
1967 .vidioc_s_ctrl = vidioc_s_ctrl,
1968 .vidioc_streamon = vidioc_streamon,
1969 .vidioc_streamoff = vidioc_streamoff,
1970 .vidioc_g_tuner = vidioc_g_tuner,
1971 .vidioc_s_tuner = vidioc_s_tuner,
1972 .vidioc_g_frequency = vidioc_g_frequency,
1973 .vidioc_s_frequency = vidioc_s_frequency,
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03001974#ifdef CONFIG_VIDEO_ADV_DEBUG
1975 .vidioc_g_register = vidioc_g_register,
1976 .vidioc_s_register = vidioc_s_register,
1977#endif
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03001978#ifdef CONFIG_VIDEO_V4L1_COMPAT
1979 .vidiocgmbuf = vidiocgmbuf,
1980#endif
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001981
1982 .tvnorms = V4L2_STD_ALL,
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03001983 .current_norm = V4L2_STD_PAL,
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03001984};
1985
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03001986static struct video_device em28xx_radio_template = {
1987 .name = "em28xx-radio",
1988 .type = VID_TYPE_TUNER,
1989 .fops = &radio_fops,
1990 .minor = -1,
1991 .vidioc_querycap = radio_querycap,
1992 .vidioc_g_tuner = radio_g_tuner,
1993 .vidioc_enum_input = radio_enum_input,
1994 .vidioc_g_audio = radio_g_audio,
1995 .vidioc_s_tuner = radio_s_tuner,
1996 .vidioc_s_audio = radio_s_audio,
1997 .vidioc_s_input = radio_s_input,
1998 .vidioc_queryctrl = radio_queryctrl,
1999 .vidioc_g_ctrl = vidioc_g_ctrl,
2000 .vidioc_s_ctrl = vidioc_s_ctrl,
2001 .vidioc_g_frequency = vidioc_g_frequency,
2002 .vidioc_s_frequency = vidioc_s_frequency,
Mauro Carvalho Chehab1e7ad562008-02-06 09:00:41 -03002003#ifdef CONFIG_VIDEO_ADV_DEBUG
2004 .vidioc_g_register = vidioc_g_register,
2005 .vidioc_s_register = vidioc_s_register,
2006#endif
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002007};
2008
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002009/******************************** usb interface *****************************************/
2010
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002011
2012static LIST_HEAD(em28xx_extension_devlist);
2013static DEFINE_MUTEX(em28xx_extension_devlist_lock);
2014
2015int em28xx_register_extension(struct em28xx_ops *ops)
2016{
2017 struct em28xx *h, *dev = NULL;
2018
2019 list_for_each_entry(h, &em28xx_devlist, devlist)
2020 dev = h;
2021
2022 mutex_lock(&em28xx_extension_devlist_lock);
2023 list_add_tail(&ops->next, &em28xx_extension_devlist);
2024 if (dev)
2025 ops->init(dev);
2026
2027 printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
2028 mutex_unlock(&em28xx_extension_devlist_lock);
2029
2030 return 0;
2031}
2032EXPORT_SYMBOL(em28xx_register_extension);
2033
2034void em28xx_unregister_extension(struct em28xx_ops *ops)
2035{
2036 struct em28xx *h, *dev = NULL;
2037
2038 list_for_each_entry(h, &em28xx_devlist, devlist)
2039 dev = h;
2040
2041 if (dev)
2042 ops->fini(dev);
2043
2044 mutex_lock(&em28xx_extension_devlist_lock);
2045 printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
2046 list_del(&ops->next);
2047 mutex_unlock(&em28xx_extension_devlist_lock);
2048}
2049EXPORT_SYMBOL(em28xx_unregister_extension);
2050
Adrian Bunk532fe652008-01-28 22:10:48 -03002051static struct video_device *em28xx_vdev_init(struct em28xx *dev,
2052 const struct video_device *template,
2053 const int type,
2054 const char *type_name)
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002055{
2056 struct video_device *vfd;
2057
2058 vfd = video_device_alloc();
2059 if (NULL == vfd)
2060 return NULL;
2061 *vfd = *template;
2062 vfd->minor = -1;
2063 vfd->dev = &dev->udev->dev;
2064 vfd->release = video_device_release;
2065 vfd->type = type;
Mauro Carvalho Chehabe9e60402008-04-13 15:05:47 -03002066 vfd->debug = video_debug;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002067
2068 snprintf(vfd->name, sizeof(vfd->name), "%s %s",
2069 dev->name, type_name);
2070
2071 return vfd;
2072}
2073
2074
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002075/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002076 * em28xx_init_dev()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002077 * allocates and inits the device structs, registers i2c bus and v4l device
2078 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002079static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002080 int minor)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002081{
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002082 struct em28xx_ops *ops = NULL;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002083 struct em28xx *dev = *devhandle;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002084 int retval = -ENOMEM;
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03002085 int errCode;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002086 unsigned int maxh, maxw;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002087
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002088 dev->udev = udev;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002089 mutex_init(&dev->lock);
Aidan Thorntond7aa8022008-04-13 14:38:47 -03002090 spin_lock_init(&dev->slock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002091 init_waitqueue_head(&dev->open);
Mauro Carvalho Chehaba3a048c2007-11-10 22:21:01 -03002092 init_waitqueue_head(&dev->wait_frame);
2093 init_waitqueue_head(&dev->wait_stream);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002094
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002095 dev->em28xx_write_regs = em28xx_write_regs;
2096 dev->em28xx_read_reg = em28xx_read_reg;
2097 dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
2098 dev->em28xx_write_regs_req = em28xx_write_regs_req;
2099 dev->em28xx_read_reg_req = em28xx_read_reg_req;
Sascha Sommerfad7b952007-11-04 08:06:48 -03002100 dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002101
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002102 errCode = em28xx_read_reg(dev, CHIPID_REG);
2103 if (errCode >= 0)
2104 em28xx_info("em28xx chip ID = %d\n", errCode);
2105
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002106 em28xx_pre_card_setup(dev);
2107
2108 errCode = em28xx_config(dev);
2109 if (errCode) {
2110 em28xx_errdev("error configuring device\n");
2111 em28xx_devused &= ~(1<<dev->devno);
2112 kfree(dev);
2113 return -ENOMEM;
2114 }
2115
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002116 /* register i2c bus */
2117 em28xx_i2c_register(dev);
2118
2119 /* Do board specific init and eeprom reading */
2120 em28xx_card_setup(dev);
2121
Mauro Carvalho Chehab3abee532008-01-05 17:01:41 -03002122 /* Configure audio */
2123 em28xx_audio_analog_set(dev);
2124
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002125 /* configure the device */
2126 em28xx_config_i2c(dev);
2127
Mauro Carvalho Chehab7d497f82007-11-11 14:15:34 -03002128 /* set default norm */
2129 dev->norm = em28xx_video_template.current_norm;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002130
2131 maxw = norm_maxw(dev);
2132 maxh = norm_maxh(dev);
2133
2134 /* set default image size */
2135 dev->width = maxw;
2136 dev->height = maxh;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002137 dev->interlaced = EM28XX_INTERLACED_DEFAULT;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002138 dev->hscale = 0;
2139 dev->vscale = 0;
2140 dev->ctl_input = 2;
2141
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002142 errCode = em28xx_config(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002143
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002144 list_add_tail(&dev->devlist, &em28xx_devlist);
2145
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002146 /* allocate and fill video video_device struct */
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002147 dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template,
2148 VID_TYPE_CAPTURE, "video");
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002149 if (NULL == dev->vdev) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002150 em28xx_errdev("cannot allocate video_device.\n");
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002151 goto fail_unreg;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002152 }
Mauro Carvalho Chehabed086312008-01-24 06:59:20 -03002153 if (dev->tuner_type != TUNER_ABSENT)
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002154 dev->vdev->type |= VID_TYPE_TUNER;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002155
2156 /* register v4l2 video video_device */
2157 retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
2158 video_nr[dev->devno]);
2159 if (retval) {
2160 em28xx_errdev("unable to register video device (error=%i).\n",
2161 retval);
2162 goto fail_unreg;
2163 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002164
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002165 /* Allocate and fill vbi video_device struct */
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002166 dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
2167 VFL_TYPE_VBI, "vbi");
2168 /* register v4l2 vbi video_device */
2169 if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
2170 vbi_nr[dev->devno]) < 0) {
2171 em28xx_errdev("unable to register vbi device\n");
2172 retval = -ENODEV;
2173 goto fail_unreg;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002174 }
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002175
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002176 if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
2177 dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
2178 VFL_TYPE_RADIO, "radio");
2179 if (NULL == dev->radio_dev) {
2180 em28xx_errdev("cannot allocate video_device.\n");
2181 goto fail_unreg;
2182 }
2183 retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
2184 radio_nr[dev->devno]);
2185 if (retval < 0) {
2186 em28xx_errdev("can't register radio device\n");
2187 goto fail_unreg;
2188 }
2189 em28xx_info("Registered radio device as /dev/radio%d\n",
2190 dev->radio_dev->minor & 0x1f);
2191 }
2192
Mauro Carvalho Chehabad0ebb92008-04-13 14:37:52 -03002193 /* init video dma queues */
2194 INIT_LIST_HEAD(&dev->vidq.active);
2195 INIT_LIST_HEAD(&dev->vidq.queued);
2196
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002197
Sascha Sommer5a804152007-11-03 21:22:38 -03002198 if (dev->has_msp34xx) {
2199 /* Send a reset to other chips via gpio */
2200 em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
2201 msleep(3);
2202 em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
2203 msleep(3);
Sascha Sommer5a804152007-11-03 21:22:38 -03002204 }
Mauro Carvalho Chehab195a4ef2007-11-11 13:17:17 -03002205
Sascha Sommer5a804152007-11-03 21:22:38 -03002206 video_mux(dev, 0);
2207
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002208 em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
2209 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
2210 dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002211
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002212 mutex_lock(&em28xx_extension_devlist_lock);
2213 if (!list_empty(&em28xx_extension_devlist)) {
2214 list_for_each_entry(ops, &em28xx_extension_devlist, next) {
2215 if (ops->id)
2216 ops->init(dev);
2217 }
2218 }
2219 mutex_unlock(&em28xx_extension_devlist_lock);
2220
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002221 return 0;
Mauro Carvalho Chehab0be43752008-01-05 17:22:01 -03002222
2223fail_unreg:
2224 em28xx_release_resources(dev);
2225 mutex_unlock(&dev->lock);
2226 kfree(dev);
2227 return retval;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002228}
2229
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002230#if defined(CONFIG_MODULES) && defined(MODULE)
2231static void request_module_async(struct work_struct *work)
2232{
2233 struct em28xx *dev = container_of(work,
2234 struct em28xx, request_module_wk);
2235
Mauro Carvalho Chehab3f4dfe22008-01-06 09:54:17 -03002236 if (dev->has_audio_class)
2237 request_module("snd-usb-audio");
2238 else
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002239 request_module("em28xx-alsa");
2240}
2241
2242static void request_modules(struct em28xx *dev)
2243{
2244 INIT_WORK(&dev->request_module_wk, request_module_async);
2245 schedule_work(&dev->request_module_wk);
2246}
2247#else
2248#define request_modules(dev)
2249#endif /* CONFIG_MODULES */
2250
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002251/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002252 * em28xx_usb_probe()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002253 * checks for supported devices
2254 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002255static int em28xx_usb_probe(struct usb_interface *interface,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002256 const struct usb_device_id *id)
2257{
2258 const struct usb_endpoint_descriptor *endpoint;
2259 struct usb_device *udev;
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002260 struct usb_interface *uif;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002261 struct em28xx *dev = NULL;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002262 int retval = -ENODEV;
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002263 int i, nr, ifnum;
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002264
2265 udev = usb_get_dev(interface_to_usbdev(interface));
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -08002266 ifnum = interface->altsetting[0].desc.bInterfaceNumber;
2267
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002268 /* Check to see next free device and mark as used */
2269 nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
2270 em28xx_devused|=1<<nr;
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -08002271
2272 /* Don't register audio interfaces */
2273 if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002274 em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -08002275 udev->descriptor.idVendor,udev->descriptor.idProduct,
2276 ifnum,
2277 interface->altsetting[0].desc.bInterfaceClass);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002278
2279 em28xx_devused&=~(1<<nr);
Mauro Carvalho Chehab91cad0f2005-11-08 21:38:13 -08002280 return -ENODEV;
2281 }
2282
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002283 em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -08002284 udev->descriptor.idVendor,udev->descriptor.idProduct,
2285 ifnum,
2286 interface->altsetting[0].desc.bInterfaceClass);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002287
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -08002288 endpoint = &interface->cur_altsetting->endpoint[1].desc;
2289
Michael Opdenacker59c51592007-05-09 08:57:56 +02002290 /* check if the device has the iso in endpoint at the correct place */
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002291 if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
2292 USB_ENDPOINT_XFER_ISOC) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002293 em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002294 em28xx_devused&=~(1<<nr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002295 return -ENODEV;
2296 }
2297 if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002298 em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002299 em28xx_devused&=~(1<<nr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002300 return -ENODEV;
2301 }
2302
Mauro Carvalho Chehab19478842006-03-14 17:24:57 -03002303 if (nr >= EM28XX_MAXBOARDS) {
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002304 printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002305 em28xx_devused&=~(1<<nr);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002306 return -ENOMEM;
2307 }
2308
2309 /* allocate memory for our device state and initialize it */
Panagiotis Issaris74081872006-01-11 19:40:56 -02002310 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002311 if (dev == NULL) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002312 em28xx_err(DRIVER_NAME ": out of memory!\n");
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002313 em28xx_devused&=~(1<<nr);
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002314 return -ENOMEM;
2315 }
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002316
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002317 snprintf(dev->name, 29, "em28xx #%d", nr);
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002318 dev->devno = nr;
2319 dev->model = id->driver_info;
Mauro Carvalho Chehab3687e1e2008-02-08 15:44:25 -03002320 dev->alt = -1;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002321
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002322 /* Checks if audio is provided by some interface */
2323 for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
2324 uif = udev->config->interface[i];
2325 if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
2326 dev->has_audio_class = 1;
2327 break;
2328 }
2329 }
2330
2331 printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
2332 dev->has_audio_class ? "Has" : "Doesn't have");
2333
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002334 /* compute alternate max packet sizes */
2335 uif = udev->actconfig->interface[0];
2336
2337 dev->num_alt=uif->num_altsetting;
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002338 em28xx_info("Alternate settings: %i\n",dev->num_alt);
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002339// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
2340 dev->alt_max_pkt_size = kmalloc(32*
2341 dev->num_alt,GFP_KERNEL);
2342 if (dev->alt_max_pkt_size == NULL) {
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002343 em28xx_errdev("out of memory!\n");
2344 em28xx_devused&=~(1<<nr);
Jesper Juhl1207cf842007-08-09 23:02:36 +02002345 kfree(dev);
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002346 return -ENOMEM;
2347 }
2348
2349 for (i = 0; i < dev->num_alt ; i++) {
2350 u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
2351 wMaxPacketSize);
2352 dev->alt_max_pkt_size[i] =
2353 (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002354 em28xx_info("Alternate setting %i, max size= %i\n",i,
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002355 dev->alt_max_pkt_size[i]);
2356 }
2357
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002358 if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002359 dev->model = card[nr];
Mauro Carvalho Chehab596d92d2005-11-08 21:37:24 -08002360
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002361 /* allocate device struct */
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002362 retval = em28xx_init_dev(&dev, udev, nr);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002363 if (retval)
2364 return retval;
2365
Mauro Carvalho Chehab03910cc2007-11-03 21:20:59 -03002366 em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002367
2368 /* save our data pointer in this interface device */
2369 usb_set_intfdata(interface, dev);
Mauro Carvalho Chehabd7448a82008-01-05 09:59:03 -03002370
2371 request_modules(dev);
2372
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002373 return 0;
2374}
2375
2376/*
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002377 * em28xx_usb_disconnect()
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002378 * called when the device gets diconencted
2379 * video device will be unregistered on v4l2_close in case it is still open
2380 */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002381static void em28xx_usb_disconnect(struct usb_interface *interface)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002382{
Sascha Sommer5a804152007-11-03 21:22:38 -03002383 struct em28xx *dev;
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002384 struct em28xx_ops *ops = NULL;
Sascha Sommer5a804152007-11-03 21:22:38 -03002385
2386 dev = usb_get_intfdata(interface);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002387 usb_set_intfdata(interface, NULL);
2388
2389 if (!dev)
2390 return;
2391
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002392 em28xx_info("disconnecting %s\n", dev->vdev->name);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002393
Sascha Sommer5a804152007-11-03 21:22:38 -03002394 /* wait until all current v4l2 io is finished then deallocate resources */
2395 mutex_lock(&dev->lock);
2396
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002397 wake_up_interruptible_all(&dev->open);
2398
2399 if (dev->users) {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002400 em28xx_warn
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002401 ("device /dev/video%d is open! Deregistration and memory "
Mauro Carvalho Chehabe5589be2006-01-23 17:11:08 -02002402 "deallocation are deferred on close.\n",
2403 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
2404
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002405 dev->state |= DEV_MISCONFIGURED;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002406 em28xx_uninit_isoc(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002407 dev->state |= DEV_DISCONNECTED;
2408 wake_up_interruptible(&dev->wait_frame);
2409 wake_up_interruptible(&dev->wait_stream);
2410 } else {
2411 dev->state |= DEV_DISCONNECTED;
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002412 em28xx_release_resources(dev);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002413 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002414 mutex_unlock(&dev->lock);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002415
Mauro Carvalho Chehab6d794682008-01-05 09:57:31 -03002416 mutex_lock(&em28xx_extension_devlist_lock);
2417 if (!list_empty(&em28xx_extension_devlist)) {
2418 list_for_each_entry(ops, &em28xx_extension_devlist, next) {
2419 ops->fini(dev);
2420 }
2421 }
2422 mutex_unlock(&em28xx_extension_devlist_lock);
2423
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002424 if (!dev->users) {
2425 kfree(dev->alt_max_pkt_size);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002426 kfree(dev);
Mauro Carvalho Chehab9d4d9c02005-11-08 21:38:52 -08002427 }
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002428}
2429
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002430static struct usb_driver em28xx_usb_driver = {
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002431 .name = "em28xx",
2432 .probe = em28xx_usb_probe,
2433 .disconnect = em28xx_usb_disconnect,
2434 .id_table = em28xx_id_table,
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002435};
2436
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002437static int __init em28xx_module_init(void)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002438{
2439 int result;
2440
2441 printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002442 (EM28XX_VERSION_CODE >> 16) & 0xff,
2443 (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002444#ifdef SNAPSHOT
2445 printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
2446 SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
2447#endif
2448
2449 /* register this driver with the USB subsystem */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002450 result = usb_register(&em28xx_usb_driver);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002451 if (result)
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002452 em28xx_err(DRIVER_NAME
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002453 " usb_register failed. Error number %d.\n", result);
2454
2455 return result;
2456}
2457
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002458static void __exit em28xx_module_exit(void)
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002459{
2460 /* deregister this driver with the USB subsystem */
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002461 usb_deregister(&em28xx_usb_driver);
akpm@osdl.orga6c2ba22005-11-08 21:37:07 -08002462}
2463
Mauro Carvalho Chehab3acf2802005-11-08 21:38:27 -08002464module_init(em28xx_module_init);
2465module_exit(em28xx_module_exit);