📄 zoran_driver.c
字号:
/* * Zoran zr36057/zr36067 PCI controller driver, for the * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux * Media Labs LML33/LML33R10. * * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> * * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> * * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be> * * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com> * * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net> * * Based on * * Miro DC10 driver * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> * * Iomega Buz driver version 1.0 * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> * * buz.0.0.3 * Copyright (C) 1998 Dave Perks <dperks@ibm.net> * * bttv - Bt848 frame grabber driver * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) * & Marcus Metzler (mocm@thp.uni-koeln.de) * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include <linux/version.h>#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <linux/wait.h>#include <linux/byteorder/generic.h>#include <linux/interrupt.h>#include <linux/i2c.h>#include <linux/i2c-algo-bit.h>#include <linux/spinlock.h>#define MAP_NR(x) virt_to_page(x)#define ZORAN_HARDWARE VID_HARDWARE_ZR36067#define ZORAN_VID_TYPE ( \ VID_TYPE_CAPTURE | \ VID_TYPE_OVERLAY | \ VID_TYPE_CLIPPING | \ VID_TYPE_FRAMERAM | \ VID_TYPE_SCALES | \ VID_TYPE_MJPEG_DECODER | \ VID_TYPE_MJPEG_ENCODER \ )#include <linux/videodev.h>#include "videocodec.h"#include <asm/io.h>#include <asm/uaccess.h>#include <linux/proc_fs.h>#include <linux/video_decoder.h>#include <linux/video_encoder.h>#include "zoran.h"#include "zoran_device.h"#include "zoran_card.h"#ifdef HAVE_V4L2 /* we declare some card type definitions here, they mean * the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */#define ZORAN_V4L2_VID_FLAGS ( \ V4L2_CAP_STREAMING |\ V4L2_CAP_VIDEO_CAPTURE |\ V4L2_CAP_VIDEO_OUTPUT |\ V4L2_CAP_VIDEO_OVERLAY \ )#endif#include <asm/byteorder.h>const struct zoran_format zoran_formats[] = { { .name = "15-bit RGB", .palette = VIDEO_PALETTE_RGB555,#ifdef HAVE_V4L2#ifdef __LITTLE_ENDIAN .fourcc = V4L2_PIX_FMT_RGB555,#else .fourcc = V4L2_PIX_FMT_RGB555X,#endif .colorspace = V4L2_COLORSPACE_SRGB,#endif .depth = 15, .flags = ZORAN_FORMAT_CAPTURE | ZORAN_FORMAT_OVERLAY, }, { .name = "16-bit RGB", .palette = VIDEO_PALETTE_RGB565,#ifdef HAVE_V4L2#ifdef __LITTLE_ENDIAN .fourcc = V4L2_PIX_FMT_RGB565,#else .fourcc = V4L2_PIX_FMT_RGB565X,#endif .colorspace = V4L2_COLORSPACE_SRGB,#endif .depth = 16, .flags = ZORAN_FORMAT_CAPTURE | ZORAN_FORMAT_OVERLAY, }, { .name = "24-bit RGB", .palette = VIDEO_PALETTE_RGB24,#ifdef HAVE_V4L2#ifdef __LITTLE_ENDIAN .fourcc = V4L2_PIX_FMT_BGR24,#else .fourcc = V4L2_PIX_FMT_RGB24,#endif .colorspace = V4L2_COLORSPACE_SRGB,#endif .depth = 24, .flags = ZORAN_FORMAT_CAPTURE | ZORAN_FORMAT_OVERLAY, }, { .name = "32-bit RGB", .palette = VIDEO_PALETTE_RGB32,#ifdef HAVE_V4L2#ifdef __LITTLE_ENDIAN .fourcc = V4L2_PIX_FMT_BGR32,#else .fourcc = V4L2_PIX_FMT_RGB32,#endif .colorspace = V4L2_COLORSPACE_SRGB,#endif .depth = 32, .flags = ZORAN_FORMAT_CAPTURE | ZORAN_FORMAT_OVERLAY, }, { .name = "4:2:2, packed, YUYV", .palette = VIDEO_PALETTE_YUV422,#ifdef HAVE_V4L2 .fourcc = V4L2_PIX_FMT_YUYV, .colorspace = V4L2_COLORSPACE_SMPTE170M,#endif .depth = 16, .flags = ZORAN_FORMAT_CAPTURE | ZORAN_FORMAT_OVERLAY, }, { .name = "Hardware-encoded Motion-JPEG", .palette = -1,#ifdef HAVE_V4L2 .fourcc = V4L2_PIX_FMT_MJPEG, .colorspace = V4L2_COLORSPACE_SMPTE170M,#endif .depth = 0, .flags = ZORAN_FORMAT_CAPTURE | ZORAN_FORMAT_PLAYBACK | ZORAN_FORMAT_COMPRESSED, }};static const int zoran_num_formats = (sizeof(zoran_formats) / sizeof(struct zoran_format));// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined#if !defined(CONFIG_BIGPHYS_AREA)//#undef CONFIG_BIGPHYS_AREA#define BUZ_USE_HIMEM#endif#if defined(CONFIG_BIGPHYS_AREA)# include <linux/bigphysarea.h>#endifextern int *zr_debug;#define dprintk(num, format, args...) \ do { \ if (*zr_debug >= num) \ printk(format, ##args); \ } while (0)extern int v4l_nbufs;extern int v4l_bufsize;extern int jpg_nbufs;extern int jpg_bufsize;extern int pass_through;static int lock_norm = 0; /* 1=Don't change TV standard (norm) */module_param(lock_norm, int, 0);MODULE_PARM_DESC(lock_norm, "Users can't change norm");#ifdef HAVE_V4L2 /* small helper function for calculating buffersizes for v4l2 * we calculate the nearest higher power-of-two, which * will be the recommended buffersize */static __u32zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings){ __u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm; __u32 num = (1024 * 512) / (div); __u32 result = 2; num--; while (num) { num >>= 1; result <<= 1; } if (result > jpg_bufsize) return jpg_bufsize; if (result < 8192) return 8192; return result;}#endif/* forward references */static void v4l_fbuffer_free(struct file *file);static void jpg_fbuffer_free(struct file *file);/* * Allocate the V4L grab buffers * * These have to be pysically contiguous. * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc * else we try to allocate them with bigphysarea_alloc_pages * if the bigphysarea patch is present in the kernel, * else we try to use high memory (if the user has bootet * Linux with the necessary memory left over). */#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)static unsigned longget_high_mem (unsigned long size){/* * Check if there is usable memory at the end of Linux memory * of at least size. Return the physical address of this memory, * return 0 on failure. * * The idea is from Alexandro Rubini's book "Linux device drivers". * The driver from him which is downloadable from O'Reilly's * web site misses the "virt_to_phys(high_memory)" part * (and therefore doesn't work at all - at least with 2.2.x kernels). * * It should be unnecessary to mention that THIS IS DANGEROUS, * if more than one driver at a time has the idea to use this memory!!!! */ volatile unsigned char __iomem *mem; unsigned char c; unsigned long hi_mem_ph; unsigned long i; /* Map the high memory to user space */ hi_mem_ph = virt_to_phys(high_memory); mem = ioremap(hi_mem_ph, size); if (!mem) { dprintk(1, KERN_ERR "%s: get_high_mem() - ioremap failed\n", ZORAN_NAME); return 0; } for (i = 0; i < size; i++) { /* Check if it is memory */ c = i & 0xff; writeb(c, mem + i); if (readb(mem + i) != c) break; c = 255 - c; writeb(c, mem + i); if (readb(mem + i) != c) break; writeb(0, mem + i); /* zero out memory */ /* give the kernel air to breath */ if ((i & 0x3ffff) == 0x3ffff) schedule(); } iounmap(mem); if (i != size) { dprintk(1, KERN_ERR "%s: get_high_mem() - requested %lu, avail %lu\n", ZORAN_NAME, size, i); return 0; } return hi_mem_ph;}#endifstatic intv4l_fbuffer_alloc (struct file *file){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; int i, off; unsigned char *mem;#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA) unsigned long pmem = 0;#endif /* we might have old buffers lying around... */ if (fh->v4l_buffers.ready_to_be_freed) { v4l_fbuffer_free(file); } for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { if (fh->v4l_buffers.buffer[i].fbuffer) dprintk(2, KERN_WARNING "%s: v4l_fbuffer_alloc() - buffer %d allready allocated!?\n", ZR_DEVNAME(zr), i); //udelay(20); if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) { /* Use kmalloc */ mem = (unsigned char *) kmalloc(fh->v4l_buffers. buffer_size, GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR "%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n", ZR_DEVNAME(zr), i); v4l_fbuffer_free(file); return -ENOBUFS; } fh->v4l_buffers.buffer[i].fbuffer = mem; fh->v4l_buffers.buffer[i].fbuffer_phys = virt_to_phys(mem); fh->v4l_buffers.buffer[i].fbuffer_bus = virt_to_bus(mem); for (off = 0; off < fh->v4l_buffers.buffer_size; off += PAGE_SIZE) SetPageReserved(MAP_NR(mem + off)); dprintk(4, KERN_INFO "%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n", ZR_DEVNAME(zr), i, (unsigned long) mem, virt_to_bus(mem)); } else {#if defined(CONFIG_BIGPHYS_AREA) /* Use bigphysarea_alloc_pages */ int n = (fh->v4l_buffers.buffer_size + PAGE_SIZE - 1) / PAGE_SIZE; mem = (unsigned char *) bigphysarea_alloc_pages(n, 0, GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n", ZR_DEVNAME(zr), i); v4l_fbuffer_free(file); return -ENOBUFS; } fh->v4l_buffers.buffer[i].fbuffer = mem; fh->v4l_buffers.buffer[i].fbuffer_phys = virt_to_phys(mem); fh->v4l_buffers.buffer[i].fbuffer_bus = virt_to_bus(mem); dprintk(4, KERN_INFO "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n", ZR_DEVNAME(zr), i, (unsigned) mem, (unsigned) virt_to_bus(mem)); /* Zero out the allocated memory */ memset(fh->v4l_buffers.buffer[i].fbuffer, 0, fh->v4l_buffers.buffer_size);#elif defined(BUZ_USE_HIMEM) /* Use high memory which has been left at boot time */ /* Ok., Ok. this is an evil hack - we make * the assumption that physical addresses are * the same as bus addresses (true at least * for Intel processors). The whole method of * obtaining and using this memory is not very * nice - but I hope it saves some poor users * from kernel hacking, which might have even * more evil results */ if (i == 0) { int size = fh->v4l_buffers.num_buffers * fh->v4l_buffers.buffer_size; pmem = get_high_mem(size); if (pmem == 0) { dprintk(1, KERN_ERR "%s: v4l_fbuffer_alloc() - get_high_mem (size = %d KB) for V4L bufs failed\n", ZR_DEVNAME(zr), size >> 10); return -ENOBUFS; } fh->v4l_buffers.buffer[0].fbuffer = NULL; fh->v4l_buffers.buffer[0].fbuffer_phys = pmem; fh->v4l_buffers.buffer[0].fbuffer_bus = pmem; dprintk(4, KERN_INFO "%s: v4l_fbuffer_alloc() - using %d KB high memory\n", ZR_DEVNAME(zr), size >> 10); } else { fh->v4l_buffers.buffer[i].fbuffer = NULL; fh->v4l_buffers.buffer[i].fbuffer_phys = pmem + i * fh->v4l_buffers.buffer_size; fh->v4l_buffers.buffer[i].fbuffer_bus = pmem + i * fh->v4l_buffers.buffer_size; }#else /* No bigphysarea present, usage of high memory disabled, * but user wants buffers of more than MAX_KMALLOC_MEM */ dprintk(1, KERN_ERR "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n", ZR_DEVNAME(zr)); dprintk(1, KERN_ERR "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n", ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers, fh->v4l_buffers.buffer_size >> 10); return -ENOBUFS;#endif } } fh->v4l_buffers.allocated = 1; return 0;}/* free the V4L grab buffers */static voidv4l_fbuffer_free (struct file *file){ struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; int i, off; unsigned char *mem; dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr)); for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { if (!fh->v4l_buffers.buffer[i].fbuffer) continue; if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) { mem = fh->v4l_buffers.buffer[i].fbuffer; for (off = 0; off < fh->v4l_buffers.buffer_size; off += PAGE_SIZE) ClearPageReserved(MAP_NR(mem + off)); kfree((void *) fh->v4l_buffers.buffer[i].fbuffer); }#if defined(CONFIG_BIGPHYS_AREA) else bigphysarea_free_pages((void *) fh->v4l_buffers. buffer[i].fbuffer);#endif fh->v4l_buffers.buffer[i].fbuffer = NULL; } fh->v4l_buffers.allocated = 0; fh->v4l_buffers.ready_to_be_freed = 0;}/* * Allocate the MJPEG grab buffers. * * If the requested buffer size is smaller than MAX_KMALLOC_MEM, * kmalloc is used to request a physically contiguous area, * else we allocate the memory in framgents with get_zeroed_page. * * If a Natoma chipset is present and this is a revision 1 zr36057, * each MJPEG buffer needs to be physically contiguous. * (RJ: This statement is from Dave Perks' original driver, * I could never check it because I have a zr36067) * The driver cares about this because it reduces the buffer * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). * * RJ: The contents grab buffers needs never be accessed in the driver.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -