2
Copyright (C) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
4
The GNU C Library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Lesser General Public
6
License as published by the Free Software Foundation; either
7
version 2.1 of the License, or (at your option) any later version.
9
The GNU C Library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Lesser General Public License for more details.
22
#include <sys/ioctl.h>
25
#include <sys/types.h>
29
#include "v4l2_driver.h"
31
/****************************************************************************
33
****************************************************************************/
34
static int xioctl (int fd, unsigned long int request, void *arg)
38
do r = ioctl (fd, request, arg);
39
while (-1 == r && EINTR == errno);
44
static void free_list(struct drv_list **list_ptr)
46
struct drv_list *prev,*cur;
58
free (prev->curr); // Free data
59
free (prev); // Free list
66
/****************************************************************************
67
Auxiliary Arrays to aid debug messages
68
****************************************************************************/
69
char *v4l2_field_names[] = {
70
[V4L2_FIELD_ANY] = "any",
71
[V4L2_FIELD_NONE] = "none",
72
[V4L2_FIELD_TOP] = "top",
73
[V4L2_FIELD_BOTTOM] = "bottom",
74
[V4L2_FIELD_INTERLACED] = "interlaced",
75
[V4L2_FIELD_SEQ_TB] = "seq-tb",
76
[V4L2_FIELD_SEQ_BT] = "seq-bt",
77
[V4L2_FIELD_ALTERNATE] = "alternate",
80
char *v4l2_type_names[] = {
81
[V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
82
[V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
83
[V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
84
[V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
85
[V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
86
[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
87
[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out",
90
static char *v4l2_memory_names[] = {
91
[V4L2_MEMORY_MMAP] = "mmap",
92
[V4L2_MEMORY_USERPTR] = "userptr",
93
[V4L2_MEMORY_OVERLAY] = "overlay",
96
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*arr))
97
#define prt_names(a,arr) (((a)<ARRAY_SIZE(arr))?arr[a]:"unknown")
99
static char *prt_caps(uint32_t caps)
101
static char s[4096]="";
103
if (V4L2_CAP_VIDEO_CAPTURE & caps)
104
strcat (s,"CAPTURE ");
105
if (V4L2_CAP_VIDEO_OUTPUT & caps)
106
strcat (s,"OUTPUT ");
107
if (V4L2_CAP_VIDEO_OVERLAY & caps)
108
strcat (s,"OVERLAY ");
109
if (V4L2_CAP_VBI_CAPTURE & caps)
110
strcat (s,"VBI_CAPTURE ");
111
if (V4L2_CAP_VBI_OUTPUT & caps)
112
strcat (s,"VBI_OUTPUT ");
113
if (V4L2_CAP_SLICED_VBI_CAPTURE & caps)
114
strcat (s,"SLICED_VBI_CAPTURE ");
115
if (V4L2_CAP_SLICED_VBI_OUTPUT & caps)
116
strcat (s,"SLICED_VBI_OUTPUT ");
117
if (V4L2_CAP_RDS_CAPTURE & caps)
118
strcat (s,"RDS_CAPTURE ");
119
if (V4L2_CAP_TUNER & caps)
121
if (V4L2_CAP_AUDIO & caps)
123
if (V4L2_CAP_RADIO & caps)
125
if (V4L2_CAP_READWRITE & caps)
126
strcat (s,"READWRITE ");
127
if (V4L2_CAP_ASYNCIO & caps)
128
strcat (s,"ASYNCIO ");
129
if (V4L2_CAP_STREAMING & caps)
130
strcat (s,"STREAMING ");
135
static void prt_buf_info(char *name,struct v4l2_buffer *p)
137
struct v4l2_timecode *tc=&p->timecode;
139
printf ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
140
"bytesused=%d, flags=0x%08x, "
141
"field=%s, sequence=%d, memory=%s, offset=0x%08x, length=%d\n",
142
name, (p->timestamp.tv_sec/3600),
143
(int)(p->timestamp.tv_sec/60)%60,
144
(int)(p->timestamp.tv_sec%60),
145
p->timestamp.tv_usec,
147
prt_names(p->type,v4l2_type_names),
148
p->bytesused,p->flags,
149
prt_names(p->field,v4l2_field_names),
151
prt_names(p->memory,v4l2_memory_names),
155
printf ("\tTIMECODE: %02d:%02d:%02d type=%d, "
156
"flags=0x%08x, frames=%d, userbits=0x%08x\n",
157
tc->hours,tc->minutes,tc->seconds,
158
tc->type, tc->flags, tc->frames, *(uint32_t *) tc->userbits);
161
/****************************************************************************
163
****************************************************************************/
164
int v4l2_open (char *device, int debug, struct v4l2_driver *drv)
168
memset(drv,0,sizeof(*drv));
172
if ((drv->fd = open(device, O_RDWR )) < 0) {
176
ret=xioctl(drv->fd,VIDIOC_QUERYCAP,(void *) &drv->cap);
177
if (!ret && drv->debug) {
178
printf ("driver=%s, card=%s, bus=%s, version=%d.%d.%d, "
180
drv->cap.driver,drv->cap.card,drv->cap.bus_info,
181
(drv->cap.version >> 16) & 0xff,
182
(drv->cap.version >> 8) & 0xff,
183
drv->cap.version & 0xff,
184
prt_caps(drv->cap.capabilities));
192
/****************************************************************************
194
****************************************************************************/
195
int v4l2_enum_stds (struct v4l2_driver *drv)
197
struct v4l2_standard *p=NULL;
198
struct drv_list *list;
202
free_list(&drv->stds);
204
list=drv->stds=calloc(1,sizeof(*drv->stds));
207
for (i=0; ok==0; i++) {
208
p=calloc(1,sizeof(*p));
212
ok=xioctl(drv->fd,VIDIOC_ENUMSTD,p);
219
printf ("STANDARD: index=%d, id=0x%08x, name=%s, fps=%.3f, "
220
"framelines=%d\n", p->index,
221
(unsigned int)p->id, p->name,
222
1.*p->frameperiod.denominator/p->frameperiod.numerator,
226
list->next=calloc(1,sizeof(*list->next));
232
if (i>0 && ok==-EINVAL)
238
int v4l2_enum_input (struct v4l2_driver *drv)
240
struct v4l2_input *p=NULL;
241
struct drv_list *list;
245
free_list(&drv->inputs);
247
list=drv->inputs=calloc(1,sizeof(*drv->inputs));
250
for (i=0; ok==0; i++) {
251
p=calloc(1,sizeof(*p));
254
ok=xioctl(drv->fd,VIDIOC_ENUMINPUT,p);
261
printf ("INPUT: index=%d, name=%s, type=%d, audioset=%d, "
262
"tuner=%d, std=%08x, status=%d\n",
263
p->index,p->name,p->type,p->audioset, p->tuner,
264
(unsigned int)p->std, p->status);
267
list->next=calloc(1,sizeof(*list->next));
273
if (i>0 && ok==-EINVAL)
278
int v4l2_enum_fmt (struct v4l2_driver *drv, enum v4l2_buf_type type)
280
struct v4l2_fmtdesc *p=NULL;
281
struct v4l2_format fmt;
282
struct drv_list *list;
286
free_list(&drv->fmt_caps);
288
list=drv->fmt_caps=calloc(1,sizeof(*drv->fmt_caps));
291
for (i=0; ok==0; i++) {
292
p=calloc(1,sizeof(*p));
298
ok=xioctl(drv->fd,VIDIOC_ENUM_FMT,p);
305
printf ("FORMAT: index=%d, type=%d, flags=%d, description='%s'\n\t"
307
p->index, p->type, p->flags,p->description,
308
p->pixelformat & 0xff,
309
(p->pixelformat >> 8) & 0xff,
310
(p->pixelformat >> 16) & 0xff,
311
(p->pixelformat >> 24) & 0xff
315
list->next=calloc(1,sizeof(*list->next));
321
if (i>0 && ok==-EINVAL)
326
/****************************************************************************
327
Set routines - currently, it also checks results with Get
328
****************************************************************************/
329
int v4l2_setget_std (struct v4l2_driver *drv, enum v4l2_direction dir, v4l2_std_id *id)
331
v4l2_std_id s_id=*id;
335
if (dir & V4L2_SET) {
336
ret=xioctl(drv->fd,VIDIOC_S_STD,&s_id);
340
sprintf (s,"while trying to set STD to %08x",
346
if (dir & V4L2_GET) {
347
ret=xioctl(drv->fd,VIDIOC_G_STD,&s_id);
350
perror ("while trying to get STD id");
354
if (dir == V4L2_SET_GET) {
357
printf ("Warning: Received a std subset (%08x"
358
" std) while trying to adjust to %08x\n",
359
(unsigned int) s_id,(unsigned int) *id);
362
fprintf (stderr,"Error: Received %08x std while trying"
363
" to adjust to %08x\n",
364
(unsigned int) s_id,(unsigned int) *id);
370
int v4l2_setget_input (struct v4l2_driver *drv, enum v4l2_direction dir, struct v4l2_input *input)
373
unsigned int inp=input->index;
376
if (dir & V4L2_SET) {
377
ret=xioctl(drv->fd,VIDIOC_S_INPUT,input);
380
sprintf (s,"while trying to set INPUT to %d\n", inp);
385
if (dir & V4L2_GET) {
386
ret=xioctl(drv->fd,VIDIOC_G_INPUT,input);
388
perror ("while trying to get INPUT id\n");
392
if (dir & V4L2_SET_GET) {
393
if (input->index != inp) {
394
printf ("Input is different than expected (received %i, set %i)\n",
402
int v4l2_gettryset_fmt_cap (struct v4l2_driver *drv, enum v4l2_direction dir,
403
struct v4l2_format *fmt,uint32_t width, uint32_t height,
404
uint32_t pixelformat, enum v4l2_field field)
406
struct v4l2_pix_format *pix=&(fmt->fmt.pix);
409
fmt->type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
410
if (dir == V4L2_GET) {
411
ret=xioctl(drv->fd,VIDIOC_G_FMT,fmt);
414
perror("VIDIOC_G_FMT failed\n");
417
} else if (dir & (~(V4L2_TRY|V4L2_SET)) ) {
418
perror ("Invalid direction\n");
422
if (dir & (V4L2_TRY|V4L2_SET)) {
424
pix->height = height;
425
pix->pixelformat = pixelformat;
428
enum v4l2_colorspace colorspace;
431
if (dir & V4L2_TRY) {
432
ret=xioctl(drv->fd,VIDIOC_TRY_FMT,fmt);
434
perror("VIDIOC_TRY_FMT failed\n");
438
if (dir & V4L2_SET) {
439
ret=xioctl(drv->fd,VIDIOC_S_FMT,fmt);
441
perror("VIDIOC_S_FMT failed\n");
443
drv->sizeimage=pix->sizeimage;
446
if (pix->pixelformat != pixelformat) {
447
fprintf(stderr,"Error: asked for format %d, received %d",pixelformat,
451
if (pix->width != width) {
452
fprintf(stderr,"Error: asked for format %d, received %d\n",width,
456
if (pix->height != height) {
457
fprintf(stderr,"Error: asked for format %d, received %d\n",height,
461
if (pix->bytesperline == 0 ) {
462
fprintf(stderr,"Error: bytesperline = 0\n");
465
if (pix->sizeimage == 0 ) {
466
fprintf(stderr,"Error: sizeimage = 0\n");
471
printf( "FMT SET: %dx%d, fourcc=%c%c%c%c, %d bytes/line,"
472
" %d bytes/frame, colorspace=0x%08x\n",
473
pix->width,pix->height,
474
pix->pixelformat & 0xff,
475
(pix->pixelformat >> 8) & 0xff,
476
(pix->pixelformat >> 16) & 0xff,
477
(pix->pixelformat >> 24) & 0xff,
485
/****************************************************************************
487
****************************************************************************/
488
int v4l2_get_parm (struct v4l2_driver *drv)
491
struct v4l2_captureparm *c;
493
drv->parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
494
if ((ret=xioctl(drv->fd,VIDIOC_G_PARM,&drv->parm))>=0) {
495
c=&drv->parm.parm.capture;
496
printf ("PARM: capability=%d, capturemode=%d, %.3f fps "
497
"ext=%x, readbuf=%d\n",
500
c->timeperframe.denominator*1./c->timeperframe.numerator,
501
c->extendedmode, c->readbuffers);
505
perror ("VIDIOC_G_PARM");
511
/****************************************************************************
512
Queue and stream control
513
****************************************************************************/
515
int v4l2_free_bufs(struct v4l2_driver *drv)
522
/* Requests the driver to free all buffers */
523
drv->reqbuf.count = 0;
524
drv->reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
525
drv->reqbuf.memory = V4L2_MEMORY_MMAP;
528
if (xioctl(drv->fd,VIDIOC_STREAMOFF,&drv->reqbuf.type)<0)
531
sleep (1); // FIXME: Should check if all buffers are stopped
533
/* V4L2 API says REQBUFS with count=0 should be used to release buffer.
534
However, video-buf.c doesn't implement it.
537
if (xioctl(drv->fd,VIDIOC_REQBUFS,&drv->reqbuf)<0) {
538
perror("reqbufs while freeing buffers");
543
if (drv->reqbuf.count != 0) {
544
fprintf(stderr,"REQBUFS returned %d buffers while asking for freeing it!\n",
548
for (i = 0; i < drv->n_bufs; i++) {
549
if (drv->bufs[i].length)
550
munmap(drv->bufs[i].start, drv->bufs[i].length);
551
if (drv->v4l2_bufs[i])
552
free (drv->v4l2_bufs[i]);
555
free(drv->v4l2_bufs);
565
int v4l2_mmap_bufs(struct v4l2_driver *drv, unsigned int num_buffers)
567
/* Frees previous allocations, if required */
570
if (drv->sizeimage==0) {
571
fprintf(stderr,"Image size is zero! Can't proceed\n");
574
/* Requests the specified number of buffers */
575
drv->reqbuf.count = num_buffers;
576
drv->reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
577
drv->reqbuf.memory = V4L2_MEMORY_MMAP;
579
if (xioctl(drv->fd,VIDIOC_REQBUFS,&drv->reqbuf)<0) {
585
printf ("REQBUFS: count=%d, type=%s, memory=%s\n",
587
prt_names(drv->reqbuf.type,v4l2_type_names),
588
prt_names(drv->reqbuf.memory,v4l2_memory_names));
590
/* Allocates the required number of buffers */
591
drv->v4l2_bufs=calloc(drv->reqbuf.count, sizeof(*drv->v4l2_bufs));
592
assert(drv->v4l2_bufs!=NULL);
593
drv->bufs=calloc(drv->reqbuf.count, sizeof(*drv->bufs));
594
assert(drv->bufs!=NULL);
596
for (drv->n_bufs = 0; drv->n_bufs < drv->reqbuf.count; drv->n_bufs++) {
597
struct v4l2_buffer *p;
598
struct v4l2_timecode *tc;
600
/* Requests kernel buffers to be mmapped */
601
p=drv->v4l2_bufs[drv->n_bufs]=calloc(1,sizeof(*p));
603
p->index = drv->n_bufs;
604
p->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
605
p->memory = V4L2_MEMORY_MMAP;
606
if (xioctl(drv->fd,VIDIOC_QUERYBUF,p)<0) {
610
free (drv->v4l2_bufs[drv->n_bufs]);
617
prt_buf_info("QUERYBUF",p);
619
if (drv->sizeimage != p->length) {
620
if (drv->sizeimage < p->length) {
621
fprintf (stderr, "QUERYBUF: ERROR: VIDIOC_S_FMT said buffer should have %d size, but received %d from QUERYBUF!\n",
622
drv->sizeimage, p->length);
624
fprintf (stderr, "QUERYBUF: Expecting %d size, received %d buff length\n",
625
drv->sizeimage, p->length);
629
drv->bufs[drv->n_bufs].length = p->length;
630
drv->bufs[drv->n_bufs].start = mmap (NULL, /* start anywhere */
632
PROT_READ | PROT_WRITE, /* required */
633
MAP_SHARED, /* recommended */
634
drv->fd, p->m.offset);
637
if (MAP_FAILED == drv->bufs[drv->n_bufs].start) {
640
free (drv->v4l2_bufs[drv->n_bufs]);
649
/* Returns <0, if error, 0 if nothing to read and <size>, if something
652
int v4l2_rcvbuf(struct v4l2_driver *drv, v4l2_recebe_buffer *rec_buf)
656
struct v4l2_buffer buf;
657
memset (&buf, 0, sizeof(buf));
659
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
660
buf.memory = V4L2_MEMORY_MMAP;
662
if (-1 == xioctl (drv->fd, VIDIOC_DQBUF, &buf)) {
668
/* Could ignore EIO, see spec. */
677
prt_buf_info("DQBUF",&buf);
679
assert (buf.index < drv->n_bufs);
681
ret = rec_buf (&buf,&drv->bufs[buf.index]);
688
if (-1 == xioctl (drv->fd, VIDIOC_QBUF, &buf)) {
695
int v4l2_start_streaming(struct v4l2_driver *drv)
698
struct v4l2_buffer buf;
701
printf("Activating %d queues\n", drv->n_bufs);
702
for (i = 0; i < drv->n_bufs; i++) {
705
memset(&buf, 0, sizeof(buf));
706
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
707
buf.memory = V4L2_MEMORY_MMAP;
710
res = xioctl (drv->fd, VIDIOC_QBUF, &buf);
713
prt_buf_info("QBUF",&buf);
720
/* Activates stream */
722
printf("Enabling streaming\n");
724
if (xioctl(drv->fd,VIDIOC_STREAMON,&drv->reqbuf.type)<0)
730
int v4l2_stop_streaming(struct v4l2_driver *drv)
737
/****************************************************************************
738
Close V4L2, disallocating all structs
739
****************************************************************************/
740
int v4l2_close (struct v4l2_driver *drv)
744
free_list(&drv->stds);
745
free_list(&drv->inputs);
746
free_list(&drv->fmt_caps);
748
return (close(drv->fd));
751
/****************************************************************************
753
****************************************************************************/
755
int v4l2_getset_freq (struct v4l2_driver *drv, enum v4l2_direction dir,
758
struct v4l2_tuner tun;
759
struct v4l2_frequency frq;
761
unsigned int counter;
763
memset(&tun, 0, sizeof(tun));
765
if (-1 == xioctl (drv->fd, VIDIOC_G_TUNER, &tun)) {
767
printf("Assuming 62.5 kHz step\n");
769
if (tun.capability & V4L2_TUNER_CAP_LOW)
774
if (tun.capability & V4L2_TUNER_CAP_LOW)
775
printf("62.5 Hz step\n");
777
printf("62.5 kHz step\n");
780
memset(&frq, 0, sizeof(frq));
782
frq.type = V4L2_TUNER_ANALOG_TV;
784
if (dir & V4L2_GET) {
785
if (-1 == xioctl (drv->fd, VIDIOC_G_FREQUENCY, &frq)) {
786
perror ("s_frequency");
789
*freq = frq.frequency * d;
791
printf("board is at freq %4.3f MHz (%d)\n",
792
*freq/1000000, frq.frequency);
794
frq.frequency = (uint32_t)(((*freq)+d/2) / d);
796
if (-1 == xioctl (drv->fd, VIDIOC_S_FREQUENCY, &frq)) {
797
perror ("s_frequency");
801
printf("board set to freq %4.3f MHz (%d)\n",
802
*freq/1000000, frq.frequency);