📄 zoran_driver.c
字号:
* Therefore there is no need to allocate them with vmalloc in order * to get a contiguous virtual memory space. * I don't understand why many other drivers first allocate them with * vmalloc (which uses internally also get_zeroed_page, but delivers you * virtual addresses) and then again have to make a lot of efforts * to get the physical address. * * Ben Capper: * On big-endian architectures (such as ppc) some extra steps * are needed. When reading and writing to the stat_com array * and fragment buffers, the device expects to see little- * endian values. The use of cpu_to_le32() and le32_to_cpu() * in this function (and one or two others in zoran_device.c) * ensure that these values are always stored in little-endian * form, regardless of architecture. The zr36057 does Very Bad * Things on big endian architectures if the stat_com array * and fragment buffers are not little-endian. */static intjpg_fbuffer_alloc (struct file *file){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; int i, j, off; unsigned long mem; /* we might have old buffers lying around */ if (fh->jpg_buffers.ready_to_be_freed) { jpg_fbuffer_free(file); } for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { if (fh->jpg_buffers.buffer[i].frag_tab) dprintk(2, KERN_WARNING "%s: jpg_fbuffer_alloc() - buffer %d allready allocated!?\n", ZR_DEVNAME(zr), i); /* Allocate fragment table for this buffer */ mem = get_zeroed_page(GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR "%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n", ZR_DEVNAME(zr), i); jpg_fbuffer_free(file); return -ENOBUFS; } memset((void *) mem, 0, PAGE_SIZE); fh->jpg_buffers.buffer[i].frag_tab = (u32 *) mem; fh->jpg_buffers.buffer[i].frag_tab_bus = virt_to_bus((void *) mem); //if (alloc_contig) { if (fh->jpg_buffers.need_contiguous) { mem = (unsigned long) kmalloc(fh->jpg_buffers. buffer_size, GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR "%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n", ZR_DEVNAME(zr), i); jpg_fbuffer_free(file); return -ENOBUFS; } fh->jpg_buffers.buffer[i].frag_tab[0] = cpu_to_le32(virt_to_bus((void *) mem)); fh->jpg_buffers.buffer[i].frag_tab[1] = cpu_to_le32(((fh->jpg_buffers.buffer_size / 4) << 1) | 1); for (off = 0; off < fh->jpg_buffers.buffer_size; off += PAGE_SIZE) SetPageReserved(MAP_NR(mem + off)); } else { /* jpg_bufsize is allreay page aligned */ for (j = 0; j < fh->jpg_buffers.buffer_size / PAGE_SIZE; j++) { mem = get_zeroed_page(GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR "%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n", ZR_DEVNAME(zr), i); jpg_fbuffer_free(file); return -ENOBUFS; } fh->jpg_buffers.buffer[i].frag_tab[2 * j] = cpu_to_le32(virt_to_bus((void *) mem)); fh->jpg_buffers.buffer[i].frag_tab[2 * j + 1] = cpu_to_le32((PAGE_SIZE / 4) << 1); SetPageReserved(MAP_NR(mem)); } fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1); } } dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n", ZR_DEVNAME(zr), (fh->jpg_buffers.num_buffers * fh->jpg_buffers.buffer_size) >> 10); fh->jpg_buffers.allocated = 1; return 0;}/* free the MJPEG grab buffers */static voidjpg_fbuffer_free (struct file *file){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; int i, j, off; unsigned char *mem; dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr)); for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { if (!fh->jpg_buffers.buffer[i].frag_tab) continue; //if (alloc_contig) { if (fh->jpg_buffers.need_contiguous) { if (fh->jpg_buffers.buffer[i].frag_tab[0]) { mem = (unsigned char *) bus_to_virt(le32_to_cpu( fh->jpg_buffers.buffer[i].frag_tab[0])); for (off = 0; off < fh->jpg_buffers.buffer_size; off += PAGE_SIZE) ClearPageReserved(MAP_NR (mem + off)); kfree(mem); fh->jpg_buffers.buffer[i].frag_tab[0] = 0; fh->jpg_buffers.buffer[i].frag_tab[1] = 0; } } else { for (j = 0; j < fh->jpg_buffers.buffer_size / PAGE_SIZE; j++) { if (!fh->jpg_buffers.buffer[i]. frag_tab[2 * j]) break; ClearPageReserved(MAP_NR (bus_to_virt (le32_to_cpu (fh->jpg_buffers. buffer[i].frag_tab[2 * j])))); free_page((unsigned long) bus_to_virt (le32_to_cpu (fh->jpg_buffers. buffer[i]. frag_tab[2 * j]))); fh->jpg_buffers.buffer[i].frag_tab[2 * j] = 0; fh->jpg_buffers.buffer[i].frag_tab[2 * j + 1] = 0; } } free_page((unsigned long) fh->jpg_buffers.buffer[i]. frag_tab); fh->jpg_buffers.buffer[i].frag_tab = NULL; } fh->jpg_buffers.allocated = 0; fh->jpg_buffers.ready_to_be_freed = 0;}/* * V4L Buffer grabbing */static intzoran_v4l_set_format (struct file *file, int width, int height, const struct zoran_format *format){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; int bpp; /* Check size and format of the grab wanted */ if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { dprintk(1, KERN_ERR "%s: v4l_set_format() - wrong frame size (%dx%d)\n", ZR_DEVNAME(zr), width, height); return -EINVAL; } bpp = (format->depth + 7) / 8; /* Check against available buffer size */ if (height * width * bpp > fh->v4l_buffers.buffer_size) { dprintk(1, KERN_ERR "%s: v4l_set_format() - video buffer size (%d kB) is too small\n", ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10); return -EINVAL; } /* The video front end needs 4-byte alinged line sizes */ if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { dprintk(1, KERN_ERR "%s: v4l_set_format() - wrong frame alingment\n", ZR_DEVNAME(zr)); return -EINVAL; } fh->v4l_settings.width = width; fh->v4l_settings.height = height; fh->v4l_settings.format = format; fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width; return 0;}static intzoran_v4l_queue_frame (struct file *file, int num){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; unsigned long flags; int res = 0; if (!fh->v4l_buffers.allocated) { dprintk(1, KERN_ERR "%s: v4l_queue_frame() - buffers not yet allocated\n", ZR_DEVNAME(zr)); res = -ENOMEM; } /* No grabbing outside the buffer range! */ if (num >= fh->v4l_buffers.num_buffers || num < 0) { dprintk(1, KERN_ERR "%s: v4l_queue_frame() - buffer %d is out of range\n", ZR_DEVNAME(zr), num); res = -EINVAL; } spin_lock_irqsave(&zr->spinlock, flags); if (fh->v4l_buffers.active == ZORAN_FREE) { if (zr->v4l_buffers.active == ZORAN_FREE) { zr->v4l_buffers = fh->v4l_buffers; fh->v4l_buffers.active = ZORAN_ACTIVE; } else { dprintk(1, KERN_ERR "%s: v4l_queue_frame() - another session is already capturing\n", ZR_DEVNAME(zr)); res = -EBUSY; } } /* make sure a grab isn't going on currently with this buffer */ if (!res) { switch (zr->v4l_buffers.buffer[num].state) { default: case BUZ_STATE_PEND: if (zr->v4l_buffers.active == ZORAN_FREE) { fh->v4l_buffers.active = ZORAN_FREE; zr->v4l_buffers.allocated = 0; } res = -EBUSY; /* what are you doing? */ break; case BUZ_STATE_DONE: dprintk(2, KERN_WARNING "%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n", ZR_DEVNAME(zr), num); case BUZ_STATE_USER: /* since there is at least one unused buffer there's room for at least * one more pend[] entry */ zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = num; zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND; zr->v4l_buffers.buffer[num].bs.length = fh->v4l_settings.bytesperline * zr->v4l_settings.height; fh->v4l_buffers.buffer[num] = zr->v4l_buffers.buffer[num]; break; } } spin_unlock_irqrestore(&zr->spinlock, flags); if (!res && zr->v4l_buffers.active == ZORAN_FREE) zr->v4l_buffers.active = fh->v4l_buffers.active; return res;}static intv4l_grab (struct file *file, struct video_mmap *mp){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; int res = 0, i; for (i = 0; i < zoran_num_formats; i++) { if (zoran_formats[i].palette == mp->format && zoran_formats[i].flags & ZORAN_FORMAT_CAPTURE && !(zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)) break; } if (i == zoran_num_formats || zoran_formats[i].depth == 0) { dprintk(1, KERN_ERR "%s: v4l_grab() - wrong bytes-per-pixel format\n", ZR_DEVNAME(zr)); return -EINVAL; } /* * To minimize the time spent in the IRQ routine, we avoid setting up * the video front end there. * If this grab has different parameters from a running streaming capture * we stop the streaming capture and start it over again. */ if (zr->v4l_memgrab_active && (zr->v4l_settings.width != mp->width || zr->v4l_settings.height != mp->height || zr->v4l_settings.format->palette != mp->format)) { res = wait_grab_pending(zr); if (res) return res; } if ((res = zoran_v4l_set_format(file, mp->width, mp->height, &zoran_formats[i]))) return res; zr->v4l_settings = fh->v4l_settings; /* queue the frame in the pending queue */ if ((res = zoran_v4l_queue_frame(file, mp->frame))) { fh->v4l_buffers.active = ZORAN_FREE; return res; } /* put the 36057 into frame grabbing mode */ if (!res && !zr->v4l_memgrab_active) zr36057_set_memgrab(zr, 1); //dprintk(4, KERN_INFO "%s: Frame grab 3...\n", ZR_DEVNAME(zr)); return res;}/* * Sync on a V4L buffer */static intv4l_sync (struct file *file, int frame){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; unsigned long flags; if (fh->v4l_buffers.active == ZORAN_FREE) { dprintk(1, KERN_ERR "%s: v4l_sync() - no grab active for this session\n", ZR_DEVNAME(zr)); return -EINVAL; } /* check passed-in frame number */ if (frame >= fh->v4l_buffers.num_buffers || frame < 0) { dprintk(1, KERN_ERR "%s: v4l_sync() - frame %d is invalid\n", ZR_DEVNAME(zr), frame); return -EINVAL; } /* Check if is buffer was queued at all */ if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) { dprintk(1, KERN_ERR "%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n", ZR_DEVNAME(zr)); return -EPROTO; } /* wait on this buffer to get ready */ if (!wait_event_interruptible_timeout(zr->v4l_capq, (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), 10*HZ)) return -ETIME; if (signal_pending(current)) return -ERESTARTSYS; /* buffer should now be in BUZ_STATE_DONE */ if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE) dprintk(2, KERN_ERR "%s: v4l_sync() - internal state error\n", ZR_DEVNAME(zr)); zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER; fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame]; spin_lock_irqsave(&zr->spinlock, flags); /* Check if streaming capture has finished */ if (zr->v4l_pend_tail == zr->v4l_pend_head) { zr36057_set_memgrab(zr, 0); if (zr->v4l_buffers.active == ZORAN_ACTIVE) { fh->v4l_buffers.active = zr->v4l_buffers.active = ZORAN_FREE; zr->v4l_buffers.allocated = 0; } } spin_unlock_irqrestore(&zr->spinlock, flags); return 0;}/* * Queue a MJPEG buffer for capture/playback */static intzoran_jpg_queue_frame (struct file *file, int num, enum zoran_codec_mode mode){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; unsigned long flags; int res = 0; /* Check if buffers are allocated */ if (!fh->jpg_buffers.allocated) { dprintk(1, KERN_ERR "%s: jpg_queue_frame() - buffers not yet allocated\n", ZR_DEVNAME(zr)); return -ENOMEM; } /* No grabbing outside the buffer range! */ if (num >= fh->jpg_buffers.num_buffers || num < 0) { dprintk(1, KERN_ERR "%s: jpg_queue_frame() - buffer %d out of range\n", ZR_DEVNAME(zr), num); return -EINVAL; } /* what is the codec mode right now? */ if (zr->codec_mode == BUZ_MODE_IDLE) { zr->jpg_settings = fh->jpg_settings; } else if (zr->codec_mode != mode) { /* wrong codec mode active - invalid */ dprintk(1, KERN_ERR "%s: jpg_queue_frame() - codec in wrong mode\n", ZR_DEVNAME(zr)); return -EINVAL; } if (fh->jpg_buffers.active == ZORAN_FREE) { if (zr->jpg_buffers.active == ZORAN_FREE) { zr->jpg_buffers = fh->jpg_buffers; fh->jpg_buffers.active = ZORAN_ACTIVE; } else { dprintk(1, KERN_ERR "%s: jpg_queue_frame() - another session is already capturing\n", ZR_DEVNAME(zr)); res = -EBUSY; } } if (!res && zr->codec_mode == BUZ_MODE_IDLE) { /* Ok load up the jpeg codec */ zr36057_enable_jpg(zr, mode); } spin_lock_irqsave(&zr->spinlock, flags); if (!res) { switch (zr->jpg_buffers.buffer[num].state) { case BUZ_STATE_DONE: dprintk(2, KERN_WARNING "%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n", ZR_DEVNAME(zr)); case BUZ_STATE_USER:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -