📄 cx23885-video.c
字号:
/* * Driver for the Conexant CX23885 PCIe bridge * * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * 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/init.h>#include <linux/list.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kmod.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/delay.h>#include "compat.h"#include <linux/kthread.h>#include <asm/div64.h>#include "cx23885.h"#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#ifdef CONFIG_VIDEO_V4L1_COMPAT/* Include V4L1 specific functions. Should be removed soon */#include <linux/videodev.h>#endifMODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");MODULE_LICENSE("GPL");/* ------------------------------------------------------------------ */static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };module_param_array(video_nr, int, NULL, 0444);module_param_array(vbi_nr, int, NULL, 0444);module_param_array(radio_nr, int, NULL, 0444);MODULE_PARM_DESC(video_nr, "video device numbers");MODULE_PARM_DESC(vbi_nr, "vbi device numbers");MODULE_PARM_DESC(radio_nr, "radio device numbers");static unsigned int video_debug;module_param(video_debug, int, 0644);MODULE_PARM_DESC(video_debug, "enable debug messages [video]");static unsigned int irq_debug;module_param(irq_debug, int, 0644);MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");static unsigned int vid_limit = 16;module_param(vid_limit, int, 0644);MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");#define dprintk(level, fmt, arg...)\ do { if (video_debug >= level)\ printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ } while (0)/* ------------------------------------------------------------------- *//* static data */#define FORMAT_FLAGS_PACKED 0x01static struct cx23885_fmt formats[] = { { .name = "8 bpp, gray", .fourcc = V4L2_PIX_FMT_GREY,#if 0 .cxformat = ColorFormatY8,#endif .depth = 8, .flags = FORMAT_FLAGS_PACKED, }, { .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555,#if 0 .cxformat = ColorFormatRGB15,#endif .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X,#if 0 .cxformat = ColorFormatRGB15 | ColorFormatBSWAP,#endif .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565,#if 0 .cxformat = ColorFormatRGB16,#endif .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X,#if 0 .cxformat = ColorFormatRGB16 | ColorFormatBSWAP,#endif .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24,#if 0 .cxformat = ColorFormatRGB24,#endif .depth = 24, .flags = FORMAT_FLAGS_PACKED, }, { .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32,#if 0 .cxformat = ColorFormatRGB32,#endif .depth = 32, .flags = FORMAT_FLAGS_PACKED, }, { .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32,#if 0 .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP,#endif .depth = 32, .flags = FORMAT_FLAGS_PACKED, }, { .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV,#if 0 .cxformat = ColorFormatYUY2,#endif .depth = 16, .flags = FORMAT_FLAGS_PACKED, }, { .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY,#if 0 .cxformat = ColorFormatYUY2 | ColorFormatBSWAP,#endif .depth = 16, .flags = FORMAT_FLAGS_PACKED, },};static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc){ unsigned int i; for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fourcc) return formats+i; printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); return NULL;}/* ------------------------------------------------------------------- */static const struct v4l2_queryctrl no_ctl = { .name = "42", .flags = V4L2_CTRL_FLAG_DISABLED,};static struct cx23885_ctrl cx23885_ctls[] = { /* --- video --- */ { .v = { .id = V4L2_CID_BRIGHTNESS, .name = "Brightness", .minimum = 0x00, .maximum = 0xff, .step = 1, .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, .reg = LUMA_CTRL, .mask = 0x00ff, .shift = 0, }, { .v = { .id = V4L2_CID_CONTRAST, .name = "Contrast", .minimum = 0, .maximum = 0xff, .step = 1, .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 0, .reg = LUMA_CTRL, .mask = 0xff00, .shift = 8, }, { .v = { .id = V4L2_CID_HUE, .name = "Hue", .minimum = 0, .maximum = 0xff, .step = 1, .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, .reg = CHROMA_CTRL, .mask = 0xff0000, .shift = 16, }, { /* strictly, this only describes only U saturation. * V saturation is handled specially through code. */ .v = { .id = V4L2_CID_SATURATION, .name = "Saturation", .minimum = 0, .maximum = 0xff, .step = 1, .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 0, .reg = CHROMA_CTRL, .mask = 0x00ff, .shift = 0, }, { /* --- audio --- */ .v = { .id = V4L2_CID_AUDIO_MUTE, .name = "Mute", .minimum = 0, .maximum = 1, .default_value = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, }, .reg = PATH1_CTL1, .mask = (0x1f << 24), .shift = 24, }, { .v = { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", .minimum = 0, .maximum = 0x3f, .step = 1, .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, }, .reg = PATH1_VOL_CTL, .mask = 0xff, .shift = 0, }};static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);static const u32 cx23885_user_ctrls[] = { V4L2_CID_USER_CLASS, V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST, V4L2_CID_SATURATION, V4L2_CID_HUE, V4L2_CID_AUDIO_VOLUME,#if 0 V4L2_CID_AUDIO_BALANCE,#endif V4L2_CID_AUDIO_MUTE, 0};static const u32 *ctrl_classes[] = { cx23885_user_ctrls, NULL};static void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count){ struct cx23885_buffer *buf; int bc; for (bc = 0;; bc++) { if (list_empty(&q->active)) break; buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); /* count comes from the hw and is is 16bit wide -- * this trick handles wrap-arounds correctly for * up to 32767 buffers in flight... */ if ((s16) (count - buf->count) < 0) break; do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); buf->vb.state = VIDEOBUF_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } if (list_empty(&q->active)) del_timer(&q->timeout); else mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); if (bc != 1) printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", __func__, bc);}static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm){ dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__, (unsigned int)norm, v4l2_norm_to_name(norm)); dev->tvnorm = norm; /* Tell the analog tuner/demods */ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm); /* Tell the internal A/V decoder */ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm); return 0;}static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, struct pci_dev *pci, struct video_device *template, char *type){ struct video_device *vfd; dprintk(1, "%s()\n", __func__); vfd = video_device_alloc(); if (NULL == vfd) return NULL; *vfd = *template; vfd->minor = -1; vfd->parent = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx23885_boards[dev->board].name); return vfd;}static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl){ int i; if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) return -EINVAL; for (i = 0; i < CX23885_CTLS; i++) if (cx23885_ctls[i].v.id == qctrl->id) break; if (i == CX23885_CTLS) { *qctrl = no_ctl; return 0; } *qctrl = cx23885_ctls[i].v; return 0;}/* ------------------------------------------------------------------- *//* resource management */static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, unsigned int bit){ dprintk(1, "%s()\n", __func__); if (fh->resources & bit) /* have it already allocated */ return 1; /* is it free? */ mutex_lock(&dev->lock); if (dev->resources & bit) { /* no, someone else uses it */ mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk(1, "res: get %d\n", bit); mutex_unlock(&dev->lock); return 1;}static int res_check(struct cx23885_fh *fh, unsigned int bit){ return fh->resources & bit;}static int res_locked(struct cx23885_dev *dev, unsigned int bit){ return dev->resources & bit;}static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, unsigned int bits){ BUG_ON((fh->resources & bits) != bits); dprintk(1, "%s()\n", __func__); mutex_lock(&dev->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk(1, "res: put %d\n", bits); mutex_unlock(&dev->lock);}static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input){ struct v4l2_routing route; memset(&route, 0, sizeof(route)); dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0, INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3); dev->input = input; route.input = INPUT(input)->vmux; /* Tell the internal A/V decoder */ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_INT_S_VIDEO_ROUTING, &route);#if 0 route.input = 0; /* Let the AVCore default */ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_INT_S_AUDIO_ROUTING, &route);#endif return 0;}/* ------------------------------------------------------------------ */static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -