From 9b5d0f1e6dd6b4a67d0851a1c5a4bcf9b0c2f258 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 18 Jul 2007 17:59:15 -0300 Subject: V4L/DVB (5862): V4L: Add internal ioctl-like interface. This patch adds an internal ioctl-like interface which can be used in situations where a single Video4Linux device is implemented by multiple device drivers. One master device controls one or more slave devices. The slaves provide Video4Linux ioctl-like interface for the use of the master. Only a handful of ioctls are implemented at the moment. More can (and should) be added as more functionality is required. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-int-device.h | 210 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 include/media/v4l2-int-device.h (limited to 'include') diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h new file mode 100644 index 000000000000..2b6fc1122f6c --- /dev/null +++ b/include/media/v4l2-int-device.h @@ -0,0 +1,210 @@ +/* + * include/media/v4l2-int-device.h + * + * V4L2 internal ioctl interface. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef V4L2_INT_DEVICE_H +#define V4L2_INT_DEVICE_H + +#include +#include + +#define V4L2NAMESIZE 32 + +enum v4l2_int_type { + v4l2_int_type_master = 1, + v4l2_int_type_slave +}; + +enum v4l2_int_ioctl_num { + /* + * + * "Proper" V4L ioctls, as in struct video_device. + * + */ + vidioc_int_enum_fmt_cap_num = 1, + vidioc_int_g_fmt_cap_num, + vidioc_int_s_fmt_cap_num, + vidioc_int_try_fmt_cap_num, + vidioc_int_queryctrl_num, + vidioc_int_g_ctrl_num, + vidioc_int_s_ctrl_num, + vidioc_int_g_parm_num, + vidioc_int_s_parm_num, + + /* + * + * Strictly internal ioctls. + * + */ + /* Initialise the device when slave attaches to the master. */ + vidioc_int_dev_init_num = 1000, + /* Delinitialise the device at slave detach. */ + vidioc_int_dev_exit_num, + /* Set device power state: 0 is off, non-zero is on. */ + vidioc_int_s_power_num, + /* Get parallel interface clock speed for current settings. */ + vidioc_int_g_ext_clk_num, + /* + * Tell what the parallel interface clock speed actually is. + */ + vidioc_int_s_ext_clk_num, + /* Does the slave need to be reset after VIDIOC_DQBUF? */ + vidioc_int_g_needs_reset_num, + + /* + * + * VIDIOC_INT_* ioctls. + * + */ + /* VIDIOC_INT_RESET */ + vidioc_int_reset_num, + /* VIDIOC_INT_INIT */ + vidioc_int_init_num, + /* VIDIOC_INT_G_CHIP_IDENT */ + vidioc_int_g_chip_ident_num, + + /* + * + * Start of private ioctls. + * + */ + vidioc_int_priv_start_num = 2000, +}; + +struct v4l2_int_device; + +struct v4l2_int_master { + int (*attach)(struct v4l2_int_device *master, + struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *master); +}; + +typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); + +struct v4l2_int_ioctl_desc { + int num; + v4l2_int_ioctl_func *func; +}; + +struct v4l2_int_slave { + /* Don't touch master. */ + struct v4l2_int_device *master; + + char attach_to[V4L2NAMESIZE]; + + int num_ioctls; + struct v4l2_int_ioctl_desc *ioctls; +}; + +struct v4l2_int_device { + /* Don't touch head. */ + struct list_head head; + + struct module *module; + + char name[V4L2NAMESIZE]; + + enum v4l2_int_type type; + union { + struct v4l2_int_master *master; + struct v4l2_int_slave *slave; + } u; + + void *priv; +}; + +int v4l2_int_device_register(struct v4l2_int_device *d); +void v4l2_int_device_unregister(struct v4l2_int_device *d); + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); + +/* + * + * IOCTL wrapper functions for better type checking. + * + */ + +#define V4L2_INT_WRAPPER_0(name) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d) \ + { \ + return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d, \ + arg_type asterisk arg) \ + { \ + return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ + (void *)arg); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *, \ + arg_type asterisk)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *); +V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *); +V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *); +V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); + +V4L2_INT_WRAPPER_0(dev_init); +V4L2_INT_WRAPPER_0(dev_exit); +V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); +V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); +V4L2_INT_WRAPPER_1(g_needs_reset, void, *); + +V4L2_INT_WRAPPER_0(reset); +V4L2_INT_WRAPPER_0(init); +V4L2_INT_WRAPPER_1(g_chip_ident, int, *); + +#endif -- cgit v1.2.3 From 63116febb9233743279a05be510ab8524f5f6242 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 20 Jul 2007 13:12:51 -0300 Subject: V4L/DVB (5883): V4L: Fix a compile warning on non-32-bit machines. Fix a compile warning on non-32-bit machines in v4l2-int-device.h. Add internal ioctl interface fallback function for ioctls with one argument. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 28 +++++++++++++++++++--------- include/media/v4l2-int-device.h | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 7885d9b38c92..aa2a8156338d 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -115,13 +115,9 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d) mutex_unlock(&mutex); } -static int no_such_ioctl(struct v4l2_int_device *d) -{ - return -EINVAL; -} - /* Adapted from search_extable in extable.c. */ -static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, + v4l2_int_ioctl_func *no_such_ioctl) { const struct v4l2_int_ioctl_desc *first = slave->ioctls; const struct v4l2_int_ioctl_desc *last = @@ -140,15 +136,29 @@ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) return mid->func; } - return &no_such_ioctl; + return no_such_ioctl; +} + +static int no_such_ioctl_0(struct v4l2_int_device *d) +{ + return -EINVAL; } int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { - return ((v4l2_int_ioctl_func_0 *)find_ioctl(d->u.slave, cmd))(d); + return ((v4l2_int_ioctl_func_0 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); +} + +static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) +{ + return -EINVAL; } int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { - return ((v4l2_int_ioctl_func_1 *)find_ioctl(d->u.slave, cmd))(d, arg); + return ((v4l2_int_ioctl_func_1 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 2b6fc1122f6c..deb28ce6685d 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -170,7 +170,7 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); arg_type asterisk arg) \ { \ return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ - (void *)arg); \ + (void *)(unsigned long)arg); \ } \ \ static inline struct v4l2_int_ioctl_desc \ -- cgit v1.2.3 From 32db775452818656d5fd8fd8b0f54425f5cfc177 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 09:29:43 -0300 Subject: V4L/DVB (5902): Add ivtv-fb framebuffer driver. Add the ivtv-fb framebuffer driver for cx23415 devices (currently only the Hauppauge PVR-350 cards). This makes it possible to use the On-Screen Display functionality of these cards, either for menus during MPEG playback, or as a console or X display. Signed-off-by: Kevin Thayer Signed-off-by: Chris Kennedy Signed-off-by: Hans Verkuil Signed-off-by: John P Harvey Signed-off-by: Ian Armstrong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 16 + drivers/media/video/ivtv/Makefile | 1 + drivers/media/video/ivtv/ivtv-driver.c | 15 +- drivers/media/video/ivtv/ivtv-driver.h | 26 +- drivers/media/video/ivtv/ivtv-fb.c | 1215 ++++++++++++++++++++++++++++++++ include/media/ivtv-fb.h | 35 + 6 files changed, 1283 insertions(+), 25 deletions(-) create mode 100644 drivers/media/video/ivtv/ivtv-fb.c create mode 100644 include/media/ivtv-fb.h (limited to 'include') diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index e43beb2c9cbf..399f231abb96 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -25,3 +25,19 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. + +config VIDEO_IVTV_FB + tristate "Conexant cx23415 framebuffer support" + depends on VIDEO_IVTV && FB && EXPERIMENTAL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This is a framebuffer driver for the Conexant cx23415 MPEG + encoder/decoder. + + This is used in the Hauppauge PVR-350 card. There is a driver + homepage at . + + To compile this driver as a module, choose M here: the + module will be called ivtv-fb. diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 7e95148fbf4f..90e2d1270561 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,3 +5,4 @@ ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-video.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o +obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 622af634104e..81cbaf7dd51c 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -95,8 +95,14 @@ const u32 yuv_offset[4] = { /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; -static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; static int cardtype_c = 1; static int tuner_c = 1; @@ -1242,8 +1248,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); + spin_lock(&ivtv_cards_lock); kfree(ivtv_cards[ivtv_cards_active]); ivtv_cards[ivtv_cards_active] = NULL; + spin_unlock(&ivtv_cards_lock); return retval; } @@ -1346,6 +1354,7 @@ static void module_cleanup(void) pci_unregister_driver(&ivtv_pci_driver); + spin_lock(&ivtv_cards_lock); for (i = 0; i < ivtv_cards_active; i++) { if (ivtv_cards[i] == NULL) continue; @@ -1354,6 +1363,7 @@ static void module_cleanup(void) } kfree(ivtv_cards[i]); } + spin_unlock(&ivtv_cards_lock); } /* Note: These symbols are exported because they are used by the ivtv-fb @@ -1361,6 +1371,7 @@ static void module_cleanup(void) EXPORT_SYMBOL(ivtv_set_irq_mask); EXPORT_SYMBOL(ivtv_cards_active); EXPORT_SYMBOL(ivtv_cards); +EXPORT_SYMBOL(ivtv_cards_lock); EXPORT_SYMBOL(ivtv_api); EXPORT_SYMBOL(ivtv_vapi); EXPORT_SYMBOL(ivtv_vapi_result); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8abb34a35816..8fe9d9c7a18e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -89,11 +89,9 @@ extern const u32 yuv_offset[4]; -/* Maximum ivtv driver instances. - Based on 6 PVR500s each with two PVR15s... - TODO: make this dynamic. I believe it is only a global in order to support - ivtv-fb. There must be a better way to do that. */ -#define IVTV_MAX_CARDS 12 +/* Maximum ivtv driver instances. Some people have a huge number of + capture cards, so set this to a high value. */ +#define IVTV_MAX_CARDS 32 /* Supported cards */ #define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ @@ -303,28 +301,10 @@ extern const u32 yuv_offset[4]; #define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) #define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_debug) \ - printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) -#define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args) /* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ #define MPEG_FRAME_TYPE_IFRAME 1 diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c new file mode 100644 index 000000000000..8e9bd75fc2bf --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -0,0 +1,1215 @@ +/* + On Screen Display cx23415 Framebuffer driver + + This module presents the cx23415 OSD (onscreen display) framebuffer memory + as a standard Linux /dev/fb style framebuffer device. The framebuffer has + support for 8,16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + mode, there is a choice of a three color depths (12, 15 or 16 bits), but no + local alpha. The colorspace is selectable between rgb & yuv. + Depending on the TV standard configured in the ivtv module at load time, + the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. + Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) + or 59.94 (NTSC) + + Copyright (c) 2003 Matt T. Yourst + + Derived from drivers/video/vesafb.c + Portions (c) 1998 Gerd Knorr + + 2.6 kernel port: + Copyright (C) 2004 Matthias Badaire + + Copyright (C) 2004 Chris Kennedy + + Copyright (C) 2006 Ian Armstrong + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv-driver.h" +#include "ivtv-queue.h" +#include "ivtv-udma.h" +#include "ivtv-irq.h" +#include "ivtv-fileops.h" +#include "ivtv-mailbox.h" +#include "ivtv-cards.h" +#include + +/* card parameters */ +static int ivtv_fb_card_id = -1; +static int ivtv_fb_debug = 0; +static int osd_laced; +static int osd_compat; +static int osd_depth; +static int osd_upper; +static int osd_left; +static int osd_yres; +static int osd_xres; + +module_param(ivtv_fb_card_id, int, 0444); +module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(osd_laced, bool, 0444); +module_param(osd_compat, bool, 0444); +module_param(osd_depth, int, 0444); +module_param(osd_upper, int, 0444); +module_param(osd_left, int, 0444); +module_param(osd_yres, int, 0444); +module_param(osd_xres, int, 0444); + +MODULE_PARM_DESC(ivtv_fb_card_id, + "Only use framebuffer of the specified ivtv card (0-31)\n" + "\t\t\tdefault -1: initialize all available framebuffers"); + +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: errors only\n" + "\t\t\t(debug = 3 gives full debugging)"); + +MODULE_PARM_DESC(osd_compat, + "Compatibility mode - Display size is locked (use for old X drivers)\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +/* Why upper, left, xres, yres, depth, laced ? To match terminology used + by fbset. + Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ + +MODULE_PARM_DESC(osd_laced, + "Interlaced mode\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +MODULE_PARM_DESC(osd_depth, + "Bits per pixel - 8,16,32\n" + "\t\t\tdefault 8"); + +MODULE_PARM_DESC(osd_upper, + "Vertical start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_left, + "Horizontal start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_yres, + "Display height\n" + "\t\t\tdefault 480 (PAL)\n" + "\t\t\t 400 (NTSC)"); + +MODULE_PARM_DESC(osd_xres, + "Display width\n" + "\t\t\tdefault 640"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); +MODULE_LICENSE("GPL"); + +/* --------------------------------------------------------------------- */ + +#define IVTV_FB_DBGFLG_WARN (1 << 0) +#define IVTV_FB_DBGFLG_INFO (1 << 1) + +#define IVTV_FB_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtv_fb_debug) \ + printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + } while (0) +#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) + +/* Standard kernel messages */ +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) + +/* --------------------------------------------------------------------- */ + +#define IVTV_OSD_MAX_WIDTH 720 +#define IVTV_OSD_MAX_HEIGHT 576 + +#define IVTV_OSD_BPP_8 0x00 +#define IVTV_OSD_BPP_16_444 0x03 +#define IVTV_OSD_BPP_16_555 0x02 +#define IVTV_OSD_BPP_16_565 0x01 +#define IVTV_OSD_BPP_32 0x04 + +struct osd_info { + /* Timing info for modes */ + u32 pixclock; + u32 hlimit; + u32 vlimit; + + /* Physical base address */ + unsigned long video_pbase; + /* Relative base address (relative to start of decoder memory) */ + u32 video_rbase; + /* Mapped base address */ + volatile char __iomem *video_vbase; + /* Buffer size */ + u32 video_buffer_size; + +#ifdef CONFIG_MTRR + /* video_base rounded down as required by hardware MTRRs */ + unsigned long fb_start_aligned_physaddr; + /* video_base rounded up as required by hardware MTRRs */ + unsigned long fb_end_aligned_physaddr; +#endif + + /* Store the buffer offset */ + int set_osd_coords_x; + int set_osd_coords_y; + + /* Current dimensions (NOT VISIBLE SIZE!) */ + int display_width; + int display_height; + int display_byte_stride; + + /* Current bits per pixel */ + int bits_per_pixel; + int bytes_per_pixel; + + /* Frame buffer stuff */ + struct fb_info ivtvfb_info; + struct fb_var_screeninfo ivtvfb_defined; + struct fb_fix_screeninfo ivtvfb_fix; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +/* --------------------------------------------------------------------- */ + +/* ivtv API calls for framebuffer related support */ + +static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, + u32 *fblength) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + int rc; + + rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); + *fbbase = data[0]; + *fblength = data[1]; + return rc; +} + +static int ivtv_fb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); + + osd->offset = data[0] - itv->osd_info->video_rbase; + osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + return 0; +} + +static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +{ + itv->osd_info->display_width = osd->pixel_stride; + itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel; + itv->osd_info->set_osd_coords_x += osd->x; + itv->osd_info->set_osd_coords_y = osd->y; + + return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, + osd->offset + itv->osd_info->video_rbase, + osd->pixel_stride, + osd->lines, osd->x, osd->y); +} + +static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +{ + + int osd_height_limit = itv->is_50hz ? 576 : 480; + + /* Only fail if resolution too high, otherwise fudge the start coords. */ + if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) + return -EINVAL; + + /* Ensure we don't exceed display limits */ + if (ivtv_window->top + ivtv_window->height > osd_height_limit) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d,%d)\n", + ivtv_window->top, ivtv_window->height); + ivtv_window->top = osd_height_limit - ivtv_window->height; + } + + if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d,%d)\n", + ivtv_window->left, ivtv_window->width); + ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; + } + + /* Set the OSD origin */ + write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); + + /* How much to display */ + write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_vis_w = ivtv_window->width; + itv->yuv_info.osd_vis_h = ivtv_window->height; + itv->yuv_info.osd_x_offset = ivtv_window->left; + itv->yuv_info.osd_y_offset = ivtv_window->top; + + return 0; +} + +static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, + unsigned long ivtv_dest_addr, void __user *userbuf, + int size_in_bytes) +{ + DEFINE_WAIT(wait); + int ret = 0; + int got_sig = 0; + + mutex_lock(&itv->udma.lock); + /* Map User DMA */ + if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { + mutex_unlock(&itv->udma.lock); + IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + "Error with get_user_pages: %d bytes, %d pages returned\n", + size_in_bytes, itv->udma.page_count); + + /* get_user_pages must have failed completely */ + return -EIO; + } + + IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + size_in_bytes, itv->udma.page_count); + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + mutex_unlock(&itv->udma.lock); + if (got_sig) { + IVTV_DEBUG_INFO("User stopped OSD\n"); + return -EINTR; + } + + return ret; +} + +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) +{ + DEFINE_WAIT(wait); + + /* Nothing to do */ + if (count == 0) { + IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + return -EINVAL; + } + + /* Check Total FB Size */ + if ((dest_offset + count) > itv->osd_info->video_buffer_size) { + IVTV_FB_WARN( + "ivtv_fb_prep_frame: Overflowing the framebuffer %ld, " + "only %d available\n", + (dest_offset + count), itv->osd_info->video_buffer_size); + return -E2BIG; + } + + /* Not fatal, but will have undesirable results */ + if ((unsigned long)source & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source); + + if (dest_offset & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n",dest_offset); + + if (count & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n",count); + + /* Check Source */ + if (!access_ok(VERIFY_READ, source + dest_offset, count)) { + IVTV_FB_WARN( + "Invalid userspace pointer!!! 0x%08lx\n", + (unsigned long)source); + + IVTV_FB_DEBUG_WARN( + "access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + dest_offset, (unsigned long)source, + count); + return -EINVAL; + } + + /* OSD Address to send DMA to */ + dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase; + + /* Fill Buffers */ + return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); +} + +static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + DEFINE_WAIT(wait); + struct ivtv *itv = (struct ivtv *)info->par; + int rc=0; + + switch (cmd) { + + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + u32 trace; + + vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + trace = read_reg (0x028c0) >> 16; + if (itv->is_50hz && trace > 312) trace -= 312; + else if (itv->is_60hz && trace > 262) trace -= 262; + if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; + vblank.count = itv->lastVsyncFrame; + vblank.vcount = trace; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + case FBIO_WAITFORVSYNC: { + prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); + if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; + finish_wait (&itv->vsync_waitq, &wait); + return rc; + } + + case IVTVFB_IOCTL_PREP_FRAME: { + struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + + IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + if (copy_from_user(&args, (void __user *)arg, sizeof(args))) + return -EFAULT; + + return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + } + + default: + IVTV_FB_ERR("Unknown IOCTL %d\n",cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) +{ + + struct ivtv_osd_coords ivtv_osd; + struct v4l2_rect ivtv_window; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + + /* Select color space */ + if (var->nonstd) /* YUV */ + write_reg (read_reg(0x02a00) | 0x0002000,0x02a00); + else /* RGB */ + write_reg (read_reg(0x02a00) & ~0x0002000,0x02a00); + + /* Set the color mode + Although rare, occasionally things go wrong. The extra mode + change seems to help... */ + + switch (var->bits_per_pixel) { + case 8: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8); + break; + case 32: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32); + break; + case 16: + switch (var->green.length) { + case 4: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444); + break; + case 5: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555); + break; + case 6: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + + itv->osd_info->bits_per_pixel = var->bits_per_pixel; + itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8; + + /* Set the flicker filter */ + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: /* Filter on */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); + break; + case FB_VMODE_INTERLACED: /* Filter off */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + } + + /* Read the current osd info */ + ivtv_fb_get_osd_coords(itv, &ivtv_osd); + + /* Now set the OSD to the size we want */ + ivtv_osd.pixel_stride = var->xres_virtual; + ivtv_osd.lines = var->yres_virtual; + ivtv_osd.x = 0; + ivtv_osd.y = 0; + ivtv_fb_set_osd_coords(itv, &ivtv_osd); + + /* Can't seem to find the right API combo for this. + Use another function which does what we need through direct register access. */ + ivtv_window.width = var->xres; + ivtv_window.height = var->yres; + + /* Minimum margin cannot be 0, as X won't allow such a mode */ + if (!var->upper_margin) var->upper_margin ++; + if (!var->left_margin) var->left_margin ++; + ivtv_window.top = var->upper_margin - 1; + ivtv_window.left = var->left_margin - 1; + + ivtv_fb_set_display_window(itv, &ivtv_window); + + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + + IVTV_FB_INFO("=== Display mode change ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + + return 0; +} + +static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) +{ + IVTV_FB_DEBUG_INFO ("ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "cx23415 TV out"); + fix->smem_start = itv->osd_info->video_pbase; + fix->smem_len = itv->osd_info->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = itv->osd_info->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) +{ + int osd_height_limit = itv->is_50hz ? 576 : 480; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + + /* Check the bits per pixel */ + if (osd_compat) { + if (var->bits_per_pixel != 32) { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + } + + if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + else if (var->bits_per_pixel == 16) { + /* To find out the true mode, check green length */ + switch (var->green.length) { + case 4: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + break; + case 5: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + default: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + } + } + else { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + + /* Check the resolution */ + if (osd_compat) { + if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres || + var->xres_virtual != itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual != + itv->osd_info->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n", + var->xres,var->yres, var->xres_virtual,var->yres_virtual); + return -EINVAL; + } + } + else { + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit ) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d\n", + var->xres,var->yres); + return -EINVAL; + } + + /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ + if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel/8) > itv->osd_info->video_buffer_size || + var->xres_virtual < var->xres || + var->yres_virtual < var->yres) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution: %d x %d\n", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + + /* Some extra checks if in 8 bit mode */ + if (var->bits_per_pixel == 8) { + /* Width must be a multiple of 4 */ + if (var->xres & 3) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 8bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 3) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + else if (var->bits_per_pixel == 16) { + /* Width must be a multiple of 2 */ + if (var->xres & 1) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 16bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 1) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + + /* Now check the offsets */ + if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual, + var->yoffset,var->yres_virtual); + return -EINVAL; + } + + /* Check pixel format */ + if (var->nonstd > 1) { + IVTV_FB_DEBUG_WARN ("Invalid nonstd % d\n",var->nonstd); + return -EINVAL; + } + + /* Check video mode */ + if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && + ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { + IVTV_FB_DEBUG_WARN ("Invalid video mode: %d\n",var->vmode & FB_VMODE_MASK); + return -EINVAL; + } + + /* Check the left & upper margins + If the margins are too large, just center the screen + (enforcing margins causes too many problems) */ + + if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { + var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); + } + if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { + var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); + } + + /* Maintain overall 'size' for a constant refresh rate */ + var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres; + var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres; + + /* Fixed sync times */ + var->hsync_len = 24; + var->vsync_len = 2; + + /* Non-interlaced / interlaced mode is used to switch the OSD filter + on or off. Adjust the clock timings to maintain a constant + vertical refresh rate. */ + var->pixclock = itv->osd_info->pixclock; + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + var->pixclock /= 2; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n"); + + IVTV_FB_INFO("=== Validated display mode ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + return 0; +} + +static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *) info->par; + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + return _ivtvfb_check_var (var,itv); +} + +static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 osd_pan_index; + struct ivtv *itv = (struct ivtv *) info->par; + + osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; + write_reg (osd_pan_index,0x02A0C); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_x_pan = var->xoffset; + itv->yuv_info.osd_y_pan = var->yoffset; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + return 0; +} + +static int ivtvfb_set_par(struct fb_info *info) +{ + int rc = 0; + struct ivtv *itv = (struct ivtv *) info->par; + + IVTV_FB_DEBUG_INFO ("ivtvfb_set_par\n"); + + rc = ivtvfb_set_var(itv, &info->var); + ivtvfb_pan_display(&info->var, info); + ivtvfb_get_fix (itv, &info->fix); + return rc; +} + +static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + struct ivtv *itv = (struct ivtv *) info->par; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (info->var.bits_per_pixel <= 8) { + write_reg(regno, 0x02a30); + write_reg(color, 0x02a34); + } + else { + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + } + } + palette[regno] = color; + } + + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int ivtvfb_blank(int blank_mode, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *)info->par; + + IVTV_FB_DEBUG_INFO ("Set blanking mode : %d\n",blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + break; + } + return 0; +} + +static struct fb_ops ivtvfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = ivtvfb_check_var, + .fb_set_par = ivtvfb_set_par, + .fb_setcolreg = ivtvfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = ivtvfb_ioctl, + .fb_pan_display = ivtvfb_pan_display, + .fb_blank = ivtvfb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int ivtvfb_init_vidmode(struct ivtv *itv) +{ + int max_height; + struct v4l2_rect start_window; + + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + itv->osd_info->pixclock = 84316; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 591; + } + else { + itv->osd_info->pixclock = 83926; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 495; + } + + /* Color mode */ + + if (osd_compat) osd_depth = 32; + if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; + itv->osd_info->bits_per_pixel = osd_depth; + itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8; + + /* Horizontal size & position */ + + if (osd_xres > 720) osd_xres = 720; + + /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ + if (osd_depth == 8) + osd_xres &= ~3; + else if (osd_depth == 16) + osd_xres &= ~1; + + if (osd_xres) + start_window.width = osd_xres; + else + start_window.width = osd_compat ? 720: 640; + + /* Check horizontal start (osd_left). */ + if (osd_left && osd_left + start_window.width > 721) { + IVTV_FB_ERR ("Invalid osd_left - assuming default\n"); + osd_left = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_left --; + + start_window.left = + osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + + itv->osd_info->display_byte_stride = + start_window.width * itv->osd_info->bytes_per_pixel; + + /* Vertical size & position */ + + max_height = itv->is_50hz ? 576 : 480; + + if ( osd_yres > max_height) osd_yres = max_height; + + if (osd_yres) + start_window.height = osd_yres; + else { + if (itv->is_50hz) + start_window.height = osd_compat ? max_height : 480; + else + start_window.height = osd_compat ? max_height : 400; + } + + /* Check vertical start (osd_upper). */ + if (osd_upper + start_window.height > max_height + 1) { + IVTV_FB_ERR ("Invalid osd_upper - assuming default\n"); + osd_upper = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_upper --; + + start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); + + itv->osd_info->display_width = start_window.width; + itv->osd_info->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel; + itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1; + itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1; + itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + itv->osd_info->ivtvfb_defined.nonstd = 0; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv); + + /* Generate valid fb_fix_screeninfo */ + + ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix); + + /* Generate valid fb_info */ + + itv->osd_info->ivtvfb_info.node = -1; + itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + itv->osd_info->ivtvfb_info.par = itv; + itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined; + itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix; + itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000; + itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000; + itv->osd_info->ivtvfb_info.monspecs.vfmin = 10; + itv->osd_info->ivtvfb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR ("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL); + + if (!itv->osd_info->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR ("abort, unable to alloc pseudo pallete\n"); + return -ENOMEM; + } + + return 0; +} + +/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ + +static int ivtvfb_init_io(struct ivtv *itv) +{ + ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size); + + /* The osd buffer size depends on the number of video buffers allocated + on the PVR350 itself. For now we'll hardcode the smallest osd buffer + size to prevent any overlap. */ + itv->osd_info->video_buffer_size = 1704960; + + itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; + itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase; + + if (!itv->osd_info->video_vbase) { + IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + itv->osd_info->video_buffer_size, itv->osd_info->video_pbase); + return -EIO; + } + + IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + itv->osd_info->video_pbase, itv->osd_info->video_vbase, + itv->osd_info->video_buffer_size / 1024); + +#ifdef CONFIG_MTRR + { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + + while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1); + itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size; + itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1; + itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr, + itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr, + MTRR_TYPE_WRCOMB, 1) < 0) { + IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", + (unsigned int)itv->osd_info->fb_start_aligned_physaddr, + (unsigned int)itv->osd_info->fb_end_aligned_physaddr); + } + } +#endif /* CONFIG_MTRR */ + + /* Blank the entire osd. */ + memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size); + + return 0; +} + +/* Release any memory we've grabbed & remove mtrr entry */ +static void ivtvfb_release_buffers (struct ivtv *itv) +{ + /* Release cmap */ + if (itv->osd_info->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap); + + /* Release pseudo palette */ + if (itv->osd_info->ivtvfb_info.pseudo_palette) + kfree(itv->osd_info->ivtvfb_info.pseudo_palette); + +#ifdef CONFIG_MTRR + mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr, + (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr)); +#endif /* CONFIG_MTRR */ + + kfree(itv->osd_info); + itv->osd_info = NULL; +} + +/* Initialize the specified card */ + +static int ivtvfb_init_card (struct ivtv *itv) +{ + int rc; + + if (itv->osd_info) { + IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + return -EBUSY; + } + + itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); + if (itv->osd_info == 0) { + IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + return -ENOMEM; + } + + /* Find & setup the OSD buffer */ + if ((rc = ivtvfb_init_io (itv))) + return rc; + + /* Set the startup video mode information */ + if ((rc = ivtvfb_init_vidmode (itv))) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Register the framebuffer */ + if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { + ivtvfb_release_buffers(itv); + return -EINVAL; + } + + itv->osd_video_pbase = itv->osd_info->video_pbase; + + /* Set the card to the requested mode */ + ivtvfb_set_par(&itv->osd_info->ivtvfb_info); + + /* Set color 0 to black */ + write_reg(0, 0x02a30); + write_reg(0, 0x02a34); + + /* Enable the osd */ + ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); + + /* Note if we're running in compatibility mode */ + if (osd_compat) + IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + + /* Allocate DMA */ + ivtv_udma_alloc(itv); + return 0; + +} + +static int __init ivtvfb_init(void) +{ + struct ivtv *itv; + int i, registered = 0; + + if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + IVTV_MAX_CARDS - 1); + return -EINVAL; + } + + /* Locate & initialise all cards supporting an OSD. */ + for (i = 0; i < ivtv_cards_active; i++) { + if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + continue; + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (ivtvfb_init_card(itv) == 0) { + IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + registered++; + } + } + } + if (!registered) { + printk(KERN_ERR "ivtv-fb: no cards found"); + return -ENODEV; + } + return 0; +} + +static void ivtvfb_cleanup(void) +{ + struct ivtv *itv; + int i; + + printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + + for (i = 0; i < ivtv_cards_active; i++) { + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { + IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + unregister_framebuffer(&itv->osd_info->ivtvfb_info); + ivtvfb_release_buffers(itv); + itv->osd_video_pbase = 0; + } + } +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h new file mode 100644 index 000000000000..902b2f3d3cb6 --- /dev/null +++ b/include/media/ivtv-fb.h @@ -0,0 +1,35 @@ +/* + On Screen Display cx23415 Framebuffer driver + + Copyright (C) 2006 Ian Armstrong + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_IVTV_FB_H +#define _LINUX_IVTV_FB_H + +/* Framebuffer external API */ + +struct ivtvfb_ioctl_dma_host_to_ivtv_args { + void __user *source; + unsigned long dest_offset; + int count; +}; + +/* Framebuffer ioctls should use the range 1 - 28 */ +#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) + +#endif -- cgit v1.2.3 From d715e766ddf4786a06abe6a841e956ad8a875963 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 10:30:32 -0300 Subject: V4L/DVB (5905): ivtv-fb: Use proper ioctl value Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 6 +++--- include/media/ivtv-fb.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 01cd65328e8a..55265bd5c250 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -424,10 +424,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar finish_wait(&itv->vsync_waitq, &wait); return rc; - case IVTVFB_IOCTL_PREP_FRAME: { - struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + case IVTVFB_IOC_DMA_FRAME: { + struct ivtvfb_dma_frame args; - IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 902b2f3d3cb6..3b746f5e3c9e 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -23,13 +23,12 @@ /* Framebuffer external API */ -struct ivtvfb_ioctl_dma_host_to_ivtv_args { +struct ivtvfb_dma_frame { void __user *source; unsigned long dest_offset; int count; }; -/* Framebuffer ioctls should use the range 1 - 28 */ -#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) #endif -- cgit v1.2.3 From 59a00adbd30ed5d3a97ac41ad9e4b040a111eea8 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 23 Jul 2007 11:34:34 -0300 Subject: V4L/DVB (5913): Clean up duplicate includes in include/media/ This patch cleans up duplicate includes in include/media/ Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-dev.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 17f8f3a2f0a3..8b79e2cf77fa 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -23,8 +23,6 @@ #include #endif -#include - #define VIDEO_MAJOR 81 /* Minor device allocation */ #define MINOR_VFL_TYPE_GRABBER_MIN 0 -- cgit v1.2.3 From ac247433fe205acf460f05de64a30ee71ea307f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 27 Jul 2007 06:56:50 -0300 Subject: V4L/DVB (5929): Add vp27smpx driver This device is internal to the Panasonic VP27S tuner and is used to set the mono/stereo/bilingual setting of the tuner. It is used by two Japanese cx23416-based cards. Signed-off-by: Takahiro Adachi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 ++ drivers/media/video/Makefile | 1 + drivers/media/video/ivtv/Kconfig | 1 + drivers/media/video/ivtv/ivtv-cards.c | 4 +- drivers/media/video/ivtv/ivtv-cards.h | 3 +- drivers/media/video/ivtv/ivtv-driver.c | 4 + drivers/media/video/ivtv/ivtv-i2c.c | 2 + drivers/media/video/vp27smpx.c | 211 +++++++++++++++++++++++++++++++++ include/linux/i2c-id.h | 1 + include/media/v4l2-chip-ident.h | 3 + 10 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 drivers/media/video/vp27smpx.c (limited to 'include') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 675c8574403e..0e1d2ccc4e81 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -148,6 +148,15 @@ config VIDEO_WM8739 To compile this driver as a module, choose M here: the module will be called wm8739. +config VIDEO_VP27SMPX + tristate "Panasonic VP27s internal MPX" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the internal MPX of the Panasonic VP27s tuner. + + To compile this driver as a module, choose M here: the + module will be called vp27smpx. + comment "Video decoders" config VIDEO_BT819 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c5286bfba447..113e525f6dab 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o +obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_MXB) += mxb.o diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 399f231abb96..5efacb332114 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -14,6 +14,7 @@ config VIDEO_IVTV select VIDEO_CS53L32A select VIDEO_WM8775 select VIDEO_WM8739 + select VIDEO_VP27SMPX select VIDEO_UPD64031A select VIDEO_UPD64083 ---help--- diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index baab14b40e87..e51d7cc35b1c 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -616,7 +616,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO | + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX | IVTV_HW_TUNER | IVTV_HW_WM8739 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .video_inputs = { @@ -654,7 +654,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_TVAUDIO | IVTV_HW_WM8739, + IVTV_HW_VP27SMPX | IVTV_HW_WM8739, .video_inputs = { { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 91e9e90c14a5..3191920f4c6b 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -33,7 +33,8 @@ #define IVTV_HW_UPD6408X (1 << 11) #define IVTV_HW_SAA717X (1 << 12) #define IVTV_HW_WM8739 (1 << 13) -#define IVTV_HW_GPIO (1 << 14) +#define IVTV_HW_VP27SMPX (1 << 14) +#define IVTV_HW_GPIO (1 << 15) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index cf52111a2dcc..f8ef267e56b2 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -853,6 +853,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) #ifndef CONFIG_VIDEO_MSP3400 if (hw & IVTV_HW_MSP34XX) ivtv_request_module(itv, "msp3400"); +#endif +#ifndef CONFIG_VIDEO_VP27SMPX + if (hw & IVTV_HW_VP27SMPX) + ivtv_request_module(itv, "vp27smpx"); #endif if (hw & IVTV_HW_TVAUDIO) ivtv_request_module(itv, "tvaudio"); diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index b3557435456d..5e12ebc2a9de 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -109,6 +109,7 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_UPD64083, I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, + I2C_DRIVERID_VP27SMPX, 0 /* IVTV_HW_GPIO dummy driver ID */ }; @@ -128,6 +129,7 @@ static const char * const hw_drivernames[] = { "upd64083", "saa717x", "wm8739", + "vp27smpx", "gpio", }; diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c new file mode 100644 index 000000000000..9aa526bd2c84 --- /dev/null +++ b/drivers/media/video/vp27smpx.c @@ -0,0 +1,211 @@ +/* + * vp27smpx - driver version 0.0.1 + * + * Copyright (C) 2007 Hans Verkuil + * + * Special thanks to Kazz for the i2c data. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("vp27smpx driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +/* ----------------------------------------------------------------------- */ + +struct vp27smpx_state { + int radio; + u32 audmode; +}; + +static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + u8 data[3] = { 0x00, 0x00, 0x04 }; + + switch (audmode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + data[1] = 0x01; + break; + case V4L2_TUNER_MODE_LANG2: + data[1] = 0x02; + break; + } + + if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) { + v4l_err(client, "%s: I/O error setting audmode\n", client->name); + } + else { + state->audmode = audmode; + } +} + +static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + struct v4l2_tuner *vt = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + state->radio = 1; + break; + + case VIDIOC_S_STD: + state->radio = 0; + break; + + case VIDIOC_S_TUNER: + if (!state->radio) + vp27smpx_set_audmode(client, vt->audmode); + break; + + case VIDIOC_G_TUNER: + if (state->radio) + break; + vt->audmode = state->audmode; + vt->capability = V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0); + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Audio Mode: %u%s\n", state->audmode, + state->radio ? " (Radio)" : ""); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static struct i2c_driver i2c_driver; + +static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct vp27smpx_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + state->audmode = V4L2_TUNER_MODE_STEREO; + i2c_set_clientdata(client, state); + + /* initialize vp27smpx */ + vp27smpx_set_audmode(client, state->audmode); + i2c_attach_client(client); + + return 0; +} + +static int vp27smpx_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, vp27smpx_attach); + return 0; +} + +static int vp27smpx_detach(struct i2c_client *client) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(state); + kfree(client); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "vp27smpx", + }, + .id = I2C_DRIVERID_VP27SMPX, + .attach_adapter = vp27smpx_probe, + .detach_client = vp27smpx_detach, + .command = vp27smpx_command, +}; + + +static int __init vp27smpx_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit vp27smpx_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(vp27smpx_init_module); +module_exit(vp27smpx_cleanup_module); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index b69014865714..4891e03ad23a 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -119,6 +119,7 @@ #define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ +#define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 09d16c4f00f7..8ae42c41dd08 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -65,6 +65,9 @@ enum { V4L2_IDENT_CX23415 = 415, V4L2_IDENT_CX23416 = 416, + /* module vp27smpx: just ident 2700 */ + V4L2_IDENT_VP27SMPX = 2700, + /* module wm8739: just ident 8739 */ V4L2_IDENT_WM8739 = 8739, -- cgit v1.2.3 From 36c15f8ee41fbc3d8eaf88bba95be3d50268d5d2 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 13:59:55 -0300 Subject: V4L/DVB (5934): dvb-ttpci/saa7146: Replace saa7146_i2c_transfer by generic i2c_transfer Convert av7110_v4l.c to use i2c_transfer() instead of saa7146_i2c_transfer(). Make saa7146_i2c_transfer() static. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 1 - drivers/media/common/saa7146_i2c.c | 2 +- drivers/media/dvb/ttpci/av7110_v4l.c | 6 ++++-- include/media/saa7146.h | 1 - 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index ba6701e97671..12cda9eebd12 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -548,7 +548,6 @@ EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); EXPORT_SYMBOL_GPL(saa7146_setgpio); -EXPORT_SYMBOL_GPL(saa7146_i2c_transfer); EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); EXPORT_SYMBOL_GPL(saa7146_debug); diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 8c85efc26527..f823286341eb 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -277,7 +277,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d return 0; } -int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) +static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) { int i = 0, count = 0; u32* buffer = dev->d_i2c.cpu_addr; diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 87afaebc0703..76cca003252f 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = { static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) { + struct av7110 *av7110 = dev->ext_priv; u8 buf[] = { 0x00, reg, data }; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) { + struct av7110 *av7110 = dev->ext_priv; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 67703249b245..cd3ff2c29d5e 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -146,7 +146,6 @@ struct saa7146_dev /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); -int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg *msgs, int num, int retries); /* from saa7146_core.c */ extern struct list_head saa7146_devices; -- cgit v1.2.3 From 5e082f1521598a91c9194b2356b157cade9b6e87 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 3 Aug 2007 18:32:38 -0300 Subject: V4L/DVB (5978): tuner: Better tuner radio support Add radio support for the Thomson DTT7612 tuner. This tuner uses a different 1st intermediate frequency than the other radio tuners supported (a lot of NTSC radio tuners probably need this change too). Add a new tuner-simple parameter, radio_if. It selects the 1st IF used for radio reception. The radio frequency setting code in tuner-simple now uses this field, instead of a special case select() block for each tuner with radio support. The tuner parameters for tuners that used a 33.3 MHz RIF now set radio_if to 1 in tuner-types.c. The Thomson DTT7612 gets radio_if = 2, also add has_tda9887 = 1 and fm_gain_normal = 1. Add some defines for tda9887 bits that control IF setting in radio mode. Add a new tda9887 config option, TDA9887_RIF_41_3, that selects a 41.3 MHz radio IF. Fix the way tda9887 radio options work. The driver was modifying the default radio mode config templates based on the TDA9887_XXXX flags. This means that _all_ tuners would get the same settings. If you had a one tuner than used TDA9887_GAIN_NORMAL and one that didn't, both would get the setting. Now the tda9987 driver just checks if tuner mode is radio and then applies the config settings directly to the data being sent, just like how all the TV mode settings already work. The PLL setting math is made a little more accurate. And a grammar error in a printk is fixed. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 19 ++++++++++--- drivers/media/video/tuner-simple.c | 55 +++++++++++++++++++++++++------------- drivers/media/video/tuner-types.c | 5 ++++ include/media/tuner-types.h | 4 +++ include/media/tuner.h | 1 + 5 files changed, 62 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index a8f773274fe3..aa311e4f1f61 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -97,6 +97,8 @@ struct tvnorm { #define cAudioIF_6_5 0x03 // bit e0:1 +#define cVideoIFMask 0x1c // bit e2:4 +/* Video IF selection in TV Mode (bit B3=0) */ #define cVideoIF_58_75 0x00 // bit e2:4 #define cVideoIF_45_75 0x04 // bit e2:4 #define cVideoIF_38_90 0x08 // bit e2:4 @@ -106,6 +108,13 @@ struct tvnorm { #define cRadioIF_45_75 0x18 // bit e2:4 #define cRadioIF_38_90 0x1C // bit e2:4 +/* IF1 selection in Radio Mode (bit B3=1) */ +#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) +#define cRadioIF_41_30 0x04 // bit e2,4 + +/* Output of AFC pin in radio mode when bit E7=1 */ +#define cRadioAGC_SIF 0x00 // bit e3 +#define cRadioAGC_FM 0x08 // bit e3 #define cTunerGainNormal 0x00 // bit e5 #define cTunerGainLow 0x20 // bit e5 @@ -487,9 +496,13 @@ static int tda9887_set_config(struct tuner *t, char *buf) if (t->tda9887_config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (t->tda9887_config & TDA9887_GAIN_NORMAL) { - radio_stereo.e &= ~cTunerGainLow; - radio_mono.e &= ~cTunerGainLow; + if (t->mode == V4L2_TUNER_RADIO) { + if (t->tda9887_config & TDA9887_RIF_41_3) { + buf[3] &= ~cVideoIFMask; + buf[3] |= cRadioIF_41_30; + } + if (t->tda9887_config & TDA9887_GAIN_NORMAL) + buf[3] &= ~cTunerGainLow; } return 0; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 2d57e8bc0db3..10a7d36a2646 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -402,53 +402,68 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) u8 buffer[4]; u16 div; int rc, j; - enum param_type desired_type = TUNER_PARAM_TYPE_RADIO; struct tuner_params *params; tun = &tuners[t->type]; - for (j = 0; j < tun->count-1; j++) { - if (desired_type != tun->params[j].type) - continue; + for (j = tun->count-1; j > 0; j--) + if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) + break; + /* default params (j=0) will be used if desired type wasn't found */ + params = &tun->params[j]; + + /* Select Radio 1st IF used */ + switch (params->radio_if) { + case 0: /* 10.7 MHz */ + freq += (unsigned int)(10.7*16000); break; + case 1: /* 33.3 MHz */ + freq += (unsigned int)(33.3*16000); + break; + case 2: /* 41.3 MHz */ + freq += (unsigned int)(41.3*16000); + break; + default: + tuner_warn("Unsupported radio_if value %d\n", params->radio_if); + return; } - /* use default tuner_params if desired_type not available */ - if (desired_type != tun->params[j].type) - j = 0; - - div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ - params = &tun->params[j]; - buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ + /* Bandswitch byte */ switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n"); + tuner_dbg ("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); return; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_LG_NTSC_TAPE: + case TUNER_PHILIPS_FM1256_IH3: buffer[3] = 0x19; break; case TUNER_TNF_5335MF: buffer[3] = 0x11; break; - case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0x19; - break; case TUNER_LG_PAL_FM: buffer[3] = 0xa5; break; - case TUNER_MICROTUNE_4049FM5: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0xa4; + case TUNER_THOMSON_DTT761X: + buffer[3] = 0x39; break; + case TUNER_MICROTUNE_4049FM5: default: buffer[3] = 0xa4; break; } + + buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | + TUNER_RATIO_SELECT_50; /* 50 kHz step */ + + /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps + freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = + freq * (1/800) */ + div = (freq + 400) / 800; + if (params->cb_first_if_lower_freq && div < t->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; @@ -475,6 +490,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config &= ~TDA9887_PORT1_ACTIVE;*/ if (params->fm_gain_normal) config |= TDA9887_GAIN_NORMAL; + if (params->radio_if == 2) + config |= TDA9887_RIF_41_3; i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); } if (4 != (rc = i2c_master_send(c,buffer,4))) diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 53a99b39387f..c6a7934bd5a6 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -652,6 +652,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = { .port1_invert_for_secam_lc = 1, .default_pll_gating_18 = 1, .fm_gain_normal=1, + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -733,6 +734,7 @@ static struct tuner_params tuner_philips_fm1256_ih3_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_fm1236_mk3_ntsc_ranges, .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -859,6 +861,9 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_thomson_dtt761x_ntsc_ranges, .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), + .has_tda9887 = 1, + .fm_gain_normal = 1, + .radio_if = 2, /* 41.3 MHz */ }, }; diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h index e5ad3fcfe984..b201371416a0 100644 --- a/include/media/tuner-types.h +++ b/include/media/tuner-types.h @@ -79,6 +79,10 @@ struct tuner_params { /* Select 18% (or according to datasheet 0%) L standard PLL gating, vs the driver default of 36%. */ unsigned int default_pll_gating_18:1; + /* IF to use in radio mode. Tuners with a separate radio IF filter + seem to use 10.7, while those without use 33.3 for PAL/SECAM tuners + and 41.3 for NTSC tuners. 0 = 10.7, 1 = 33.3, 2 = 41.3 */ + unsigned int radio_if:2; /* Default tda9887 TOP value in dB for the low band. Default is 0. Range: -16:+15 */ signed int default_top_low:5; diff --git a/include/media/tuner.h b/include/media/tuner.h index 160381c72e4b..c03dceb92605 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -146,6 +146,7 @@ extern int tuner_debug; #define TDA9887_AUTOMUTE (1<<18) #define TDA9887_GATING_18 (1<<19) #define TDA9887_GAIN_NORMAL (1<<20) +#define TDA9887_RIF_41_3 (1<<21) /* radio IF1 41.3 vs 33.3 */ #ifdef __KERNEL__ -- cgit v1.2.3 From 01f1e44fe8455b6c6c557a62119b8622fb99f5f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 21 Aug 2007 18:32:42 -0300 Subject: V4L/DVB (6088): cx2341x: some controls can't be changed while the device is busy The driver should now pass the 'busy' state of the device to the cx2341x module whenever controls are set or tried. -EBUSY will be returned if the device is busy and the user attempts to modify certain 'dangerous' controls. It concerns controls that change the audio or video compression mode and bitrates. The cx88-blackbird and pvrusb2 drivers currently always pass '0' (not busy) to the cx2341x, effectively keeping the old behavior for now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx2341x.c | 18 +++++++++++++++--- drivers/media/video/cx88/cx88-blackbird.c | 6 +++--- drivers/media/video/ivtv/ivtv-controls.c | 6 +++--- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 6 +++--- drivers/media/video/v4l2-common.c | 1 + include/media/cx2341x.h | 2 +- 6 files changed, 26 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 904bba0dbc4d..62304255dcae 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -190,17 +190,21 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, /* Map the control ID to the correct field in the cx2341x_mpeg_params struct. Return -EINVAL if the ID is unknown, else return 0. */ -static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, +static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_control *ctrl) { switch (ctrl->id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + if (busy) + return -EBUSY; params->audio_sampling_freq = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_ENCODING: params->audio_encoding = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + if (busy) + return -EBUSY; params->audio_l2_bitrate = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_MODE: @@ -245,6 +249,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_gop_closure = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (busy) + return -EBUSY; /* MPEG-1 only allows CBR */ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) @@ -252,9 +258,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_bitrate_mode = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE: + if (busy) + return -EBUSY; params->video_bitrate = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + if (busy) + return -EBUSY; params->video_bitrate_peak = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: @@ -267,6 +277,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_mute_yuv = ctrl->value; break; case V4L2_CID_MPEG_STREAM_TYPE: + if (busy) + return -EBUSY; params->stream_type = ctrl->value; params->video_encoding = (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || @@ -631,7 +643,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) (params->audio_crc << 14); } -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd) { int err = 0; @@ -663,7 +675,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); if (err) break; - err = cx2341x_set_ctrl(params, ctrl); + err = cx2341x_set_ctrl(params, busy, ctrl); if (err) break; } diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 206af419aea7..47007380a98a 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -876,7 +876,7 @@ static int vidioc_g_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS); + return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); } static int vidioc_s_ext_ctrls (struct file *file, void *priv, @@ -889,7 +889,7 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); if (!err) { err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); dev->params = p; @@ -907,7 +907,7 @@ static int vidioc_try_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); return err; } diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 7a876c3e5b19..0005ea46f208 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -232,7 +232,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { struct cx2341x_mpeg_params p = itv->params; - int err = cx2341x_ext_ctrls(&p, arg, cmd); + int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); if (err) return err; @@ -282,7 +282,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd); return -EINVAL; } @@ -292,7 +292,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd); return -EINVAL; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 1311891e7ee3..2d5be5cfbccf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -492,7 +492,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) cs.controls = &c1; cs.count = 1; c1.id = cptr->info->v4l_id; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_G_EXT_CTRLS); if (ret) return ret; *vp = c1.value; @@ -510,7 +510,7 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) cs.count = 1; c1.id = cptr->info->v4l_id; c1.value = v; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_S_EXT_CTRLS); if (ret) return ret; cptr->hdw->enc_stale = !0; @@ -2478,7 +2478,7 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) cs.count = 1; c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; c1.value = hdw->srate_val; - cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS); + cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS); } /* Scan i2c core at this point - before we clear all the dirty diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index d2915d3530ea..0689a041d777 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -716,6 +716,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_LOUDNESS: case V4L2_CID_MPEG_AUDIO_MUTE: + case V4L2_CID_MPEG_VIDEO_MUTE: case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: case V4L2_CID_MPEG_VIDEO_PULLDOWN: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h index 38c12fed7535..af8071d7620d 100644 --- a/include/media/cx2341x.h +++ b/include/media/cx2341x.h @@ -91,7 +91,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl); const char **cx2341x_ctrl_get_menu(u32 id); -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p); void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix); -- cgit v1.2.3 From 5d05704cbe7f9c4708e0f35be13839f593441215 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:16:37 -0300 Subject: V4L/DVB (6108): videodev2.h: add new pixel formats for the cx23415 OSD The Conexant cx23415 MPEG encoder/decoder supports some unusual pixelformats for the On-Screen Display. Add new defines to videodev2.h for these formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index ae9b24c12f6a..1f503e94eff1 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -271,6 +271,7 @@ struct v4l2_pix_format /* Pixel format FOURCC depth Description */ #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ @@ -280,6 +281,7 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P','A','L','8') /* 8 8-bit palette */ #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ @@ -287,6 +289,10 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ +#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y','4','4','4') /* 16 xxxxyyyy uuuuvvvv */ +#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y','U','V','O') /* 16 YUV-5-5-5 */ +#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y','U','V','P') /* 16 YUV-5-6-5 */ +#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y','U','V','4') /* 32 YUV-8-8-8-8 */ /* two planes -- one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ @@ -298,7 +304,6 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */ -#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ -- cgit v1.2.3 From 66cfaeff95d20d1377b4fa3d2c6aa7c29d832941 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 05:45:48 -0300 Subject: V4L/DVB (6118): ivtv-fb: add missing FBIO_WAITFORVSYNC ioctl define Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 3 +-- include/media/ivtv-fb.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index ffe6478682ae..d2b1f5d5c8b2 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include @@ -59,7 +59,6 @@ #include "ivtv-driver.h" #include "ivtv-udma.h" #include "ivtv-mailbox.h" -#include /* card parameters */ static int ivtv_fb_card_id = -1; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 3b746f5e3c9e..d3a797b17280 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -29,6 +29,7 @@ struct ivtvfb_dma_frame { int count; }; -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif -- cgit v1.2.3 From 0f45b8c57e40cca1778b0b75daab65ca139e5bb9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:04:10 -0300 Subject: V4L/DVB (6119): ivtvfb: renamed ivtv-fb to ivtvfb, move header to include/linux The convention for framebuffer devices is to call them xxxfb, not xxx-fb. Conform to this. Also move the ivtvfb.h header to include/linux: it is a public header. The FBIO_WAITFORVSYNC ioctl is now also defined in the ivtvfb.h header, no more need to include matroxfb.h for just this ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 2 +- drivers/media/video/ivtv/Makefile | 2 +- drivers/media/video/ivtv/ivtv-fb.c | 1199 ------------------------------------ drivers/media/video/ivtv/ivtvfb.c | 1190 +++++++++++++++++++++++++++++++++++ include/linux/ivtvfb.h | 42 ++ include/media/ivtv-fb.h | 35 -- 6 files changed, 1234 insertions(+), 1236 deletions(-) delete mode 100644 drivers/media/video/ivtv/ivtv-fb.c create mode 100644 drivers/media/video/ivtv/ivtvfb.c create mode 100644 include/linux/ivtvfb.h delete mode 100644 include/media/ivtv-fb.h (limited to 'include') diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 5efacb332114..7f20c166d59f 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -27,7 +27,7 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. -config VIDEO_IVTV_FB +config VIDEO_FB_IVTV tristate "Conexant cx23415 framebuffer support" depends on VIDEO_IVTV && FB && EXPERIMENTAL select FB_CFB_FILLRECT diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 6998781e2b11..e8eefd96d897 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,4 +5,4 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o -obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o +obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c deleted file mode 100644 index d2b1f5d5c8b2..000000000000 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ /dev/null @@ -1,1199 +0,0 @@ -/* - On Screen Display cx23415 Framebuffer driver - - This module presents the cx23415 OSD (onscreen display) framebuffer memory - as a standard Linux /dev/fb style framebuffer device. The framebuffer has - support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp - mode, there is a choice of a three color depths (12, 15 or 16 bits), but no - local alpha. The colorspace is selectable between rgb & yuv. - Depending on the TV standard configured in the ivtv module at load time, - the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. - Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) - or 59.94 (NTSC) - - Copyright (c) 2003 Matt T. Yourst - - Derived from drivers/video/vesafb.c - Portions (c) 1998 Gerd Knorr - - 2.6 kernel port: - Copyright (C) 2004 Matthias Badaire - - Copyright (C) 2004 Chris Kennedy - - Copyright (C) 2006 Ian Armstrong - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_MTRR -#include -#endif - -#include "ivtv-driver.h" -#include "ivtv-udma.h" -#include "ivtv-mailbox.h" - -/* card parameters */ -static int ivtv_fb_card_id = -1; -static int ivtv_fb_debug = 0; -static int osd_laced; -static int osd_compat; -static int osd_depth; -static int osd_upper; -static int osd_left; -static int osd_yres; -static int osd_xres; - -module_param(ivtv_fb_card_id, int, 0444); -module_param_named(debug,ivtv_fb_debug, int, 0644); -module_param(osd_laced, bool, 0444); -module_param(osd_compat, bool, 0444); -module_param(osd_depth, int, 0444); -module_param(osd_upper, int, 0444); -module_param(osd_left, int, 0444); -module_param(osd_yres, int, 0444); -module_param(osd_xres, int, 0444); - -MODULE_PARM_DESC(ivtv_fb_card_id, - "Only use framebuffer of the specified ivtv card (0-31)\n" - "\t\t\tdefault -1: initialize all available framebuffers"); - -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 3 gives full debugging)"); - -MODULE_PARM_DESC(osd_compat, - "Compatibility mode - Display size is locked (use for old X drivers)\n" - "\t\t\t0=off\n" - "\t\t\t1=on\n" - "\t\t\tdefault off"); - -/* Why upper, left, xres, yres, depth, laced ? To match terminology used - by fbset. - Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ - -MODULE_PARM_DESC(osd_laced, - "Interlaced mode\n" - "\t\t\t0=off\n" - "\t\t\t1=on\n" - "\t\t\tdefault off"); - -MODULE_PARM_DESC(osd_depth, - "Bits per pixel - 8, 16, 32\n" - "\t\t\tdefault 8"); - -MODULE_PARM_DESC(osd_upper, - "Vertical start position\n" - "\t\t\tdefault 0 (Centered)"); - -MODULE_PARM_DESC(osd_left, - "Horizontal start position\n" - "\t\t\tdefault 0 (Centered)"); - -MODULE_PARM_DESC(osd_yres, - "Display height\n" - "\t\t\tdefault 480 (PAL)\n" - "\t\t\t 400 (NTSC)"); - -MODULE_PARM_DESC(osd_xres, - "Display width\n" - "\t\t\tdefault 640"); - -MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); -MODULE_LICENSE("GPL"); - -/* --------------------------------------------------------------------- */ - -#define IVTV_FB_DBGFLG_WARN (1 << 0) -#define IVTV_FB_DBGFLG_INFO (1 << 1) - -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_fb_debug) \ - printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) - -/* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) - -/* --------------------------------------------------------------------- */ - -#define IVTV_OSD_MAX_WIDTH 720 -#define IVTV_OSD_MAX_HEIGHT 576 - -#define IVTV_OSD_BPP_8 0x00 -#define IVTV_OSD_BPP_16_444 0x03 -#define IVTV_OSD_BPP_16_555 0x02 -#define IVTV_OSD_BPP_16_565 0x01 -#define IVTV_OSD_BPP_32 0x04 - -struct osd_info { - /* Physical base address */ - unsigned long video_pbase; - /* Relative base address (relative to start of decoder memory) */ - u32 video_rbase; - /* Mapped base address */ - volatile char __iomem *video_vbase; - /* Buffer size */ - u32 video_buffer_size; - -#ifdef CONFIG_MTRR - /* video_base rounded down as required by hardware MTRRs */ - unsigned long fb_start_aligned_physaddr; - /* video_base rounded up as required by hardware MTRRs */ - unsigned long fb_end_aligned_physaddr; -#endif - - /* Current osd mode */ - int osd_mode; - - /* Store the buffer offset */ - int set_osd_coords_x; - int set_osd_coords_y; - - /* Current dimensions (NOT VISIBLE SIZE!) */ - int display_width; - int display_height; - int display_byte_stride; - - /* Current bits per pixel */ - int bits_per_pixel; - int bytes_per_pixel; - - /* Frame buffer stuff */ - struct fb_info ivtvfb_info; - struct fb_var_screeninfo ivtvfb_defined; - struct fb_fix_screeninfo ivtvfb_fix; -}; - -struct ivtv_osd_coords { - unsigned long offset; - unsigned long max_offset; - int pixel_stride; - int lines; - int x; - int y; -}; - -/* --------------------------------------------------------------------- */ - -/* ivtv API calls for framebuffer related support */ - -static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, - u32 *fblength) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - int rc; - - rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); - *fbbase = data[0]; - *fblength = data[1]; - return rc; -} - -static int ivtv_fb_get_osd_coords(struct ivtv *itv, - struct ivtv_osd_coords *osd) -{ - struct osd_info *oi = itv->osd_info; - u32 data[CX2341X_MBOX_MAX_DATA]; - - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); - - osd->offset = data[0] - oi->video_rbase; - osd->max_offset = oi->display_width * oi->display_height * 4; - osd->pixel_stride = data[1]; - osd->lines = data[2]; - osd->x = data[3]; - osd->y = data[4]; - return 0; -} - -static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) -{ - struct osd_info *oi = itv->osd_info; - - oi->display_width = osd->pixel_stride; - oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; - oi->set_osd_coords_x += osd->x; - oi->set_osd_coords_y = osd->y; - - return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, - osd->offset + oi->video_rbase, - osd->pixel_stride, - osd->lines, osd->x, osd->y); -} - -static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) -{ - int osd_height_limit = itv->is_50hz ? 576 : 480; - - /* Only fail if resolution too high, otherwise fudge the start coords. */ - if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) - return -EINVAL; - - /* Ensure we don't exceed display limits */ - if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", - ivtv_window->top, ivtv_window->height); - ivtv_window->top = osd_height_limit - ivtv_window->height; - } - - if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", - ivtv_window->left, ivtv_window->width); - ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; - } - - /* Set the OSD origin */ - write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); - - /* How much to display */ - write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); - - /* Pass this info back the yuv handler */ - itv->yuv_info.osd_vis_w = ivtv_window->width; - itv->yuv_info.osd_vis_h = ivtv_window->height; - itv->yuv_info.osd_x_offset = ivtv_window->left; - itv->yuv_info.osd_y_offset = ivtv_window->top; - - return 0; -} - -static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, - unsigned long ivtv_dest_addr, void __user *userbuf, - int size_in_bytes) -{ - DEFINE_WAIT(wait); - int ret = 0; - int got_sig = 0; - - mutex_lock(&itv->udma.lock); - /* Map User DMA */ - if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { - mutex_unlock(&itv->udma.lock); - IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " - "Error with get_user_pages: %d bytes, %d pages returned\n", - size_in_bytes, itv->udma.page_count); - - /* get_user_pages must have failed completely */ - return -EIO; - } - - IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", - size_in_bytes, itv->udma.page_count); - - ivtv_udma_prepare(itv); - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ - while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { - /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ - got_sig = signal_pending(current); - if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) - break; - got_sig = 0; - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - - /* Unmap Last DMA Xfer */ - ivtv_udma_unmap(itv); - mutex_unlock(&itv->udma.lock); - if (got_sig) { - IVTV_DEBUG_INFO("User stopped OSD\n"); - return -EINTR; - } - - return ret; -} - -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, - unsigned long dest_offset, int count) -{ - DEFINE_WAIT(wait); - struct osd_info *oi = itv->osd_info; - - /* Nothing to do */ - if (count == 0) { - IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); - return -EINVAL; - } - - /* Check Total FB Size */ - if ((dest_offset + count) > oi->video_buffer_size) { - IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", - dest_offset + count, oi->video_buffer_size); - return -E2BIG; - } - - /* Not fatal, but will have undesirable results */ - if ((unsigned long)source & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", - (unsigned long)source); - - if (dest_offset & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); - - if (count & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); - - /* Check Source */ - if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", - (unsigned long)source); - - IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", - dest_offset, (unsigned long)source, - count); - return -EINVAL; - } - - /* OSD Address to send DMA to */ - dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; - - /* Fill Buffers */ - return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); -} - -static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) -{ - DEFINE_WAIT(wait); - struct ivtv *itv = (struct ivtv *)info->par; - int rc = 0; - - switch (cmd) { - case FBIOGET_VBLANK: { - struct fb_vblank vblank; - u32 trace; - - vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | - FB_VBLANK_HAVE_VSYNC; - trace = read_reg(0x028c0) >> 16; - if (itv->is_50hz && trace > 312) trace -= 312; - else if (itv->is_60hz && trace > 262) trace -= 262; - if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->last_vsync_field; - vblank.vcount = trace; - vblank.hcount = 0; - if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) - return -EFAULT; - return 0; - } - - case FBIO_WAITFORVSYNC: - prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); - if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; - finish_wait(&itv->vsync_waitq, &wait); - return rc; - - case IVTVFB_IOC_DMA_FRAME: { - struct ivtvfb_dma_frame args; - - IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); - if (copy_from_user(&args, (void __user *)arg, sizeof(args))) - return -EFAULT; - - return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); - } - - default: - IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); - return -EINVAL; - } - return 0; -} - -/* Framebuffer device handling */ - -static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) -{ - struct osd_info *oi = itv->osd_info; - struct ivtv_osd_coords ivtv_osd; - struct v4l2_rect ivtv_window; - int osd_mode = -1; - - IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); - - /* Select color space */ - if (var->nonstd) /* YUV */ - write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); - else /* RGB */ - write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); - - /* Set the color mode */ - switch (var->bits_per_pixel) { - case 8: - osd_mode = IVTV_OSD_BPP_8; - break; - case 32: - osd_mode = IVTV_OSD_BPP_32; - break; - case 16: - switch (var->green.length) { - case 4: - osd_mode = IVTV_OSD_BPP_16_444; - break; - case 5: - osd_mode = IVTV_OSD_BPP_16_555; - break; - case 6: - osd_mode = IVTV_OSD_BPP_16_565; - break; - default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); - } - break; - default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); - } - - /* Change osd mode if needed. - Although rare, things can go wrong. The extra mode - change seems to help... */ - if (osd_mode != -1 && osd_mode != oi->osd_mode) { - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); - oi->osd_mode = osd_mode; - } - - oi->bits_per_pixel = var->bits_per_pixel; - oi->bytes_per_pixel = var->bits_per_pixel / 8; - - /* Set the flicker filter */ - switch (var->vmode & FB_VMODE_MASK) { - case FB_VMODE_NONINTERLACED: /* Filter on */ - ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); - break; - case FB_VMODE_INTERLACED: /* Filter off */ - ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); - break; - default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); - } - - /* Read the current osd info */ - ivtv_fb_get_osd_coords(itv, &ivtv_osd); - - /* Now set the OSD to the size we want */ - ivtv_osd.pixel_stride = var->xres_virtual; - ivtv_osd.lines = var->yres_virtual; - ivtv_osd.x = 0; - ivtv_osd.y = 0; - ivtv_fb_set_osd_coords(itv, &ivtv_osd); - - /* Can't seem to find the right API combo for this. - Use another function which does what we need through direct register access. */ - ivtv_window.width = var->xres; - ivtv_window.height = var->yres; - - /* Minimum margin cannot be 0, as X won't allow such a mode */ - if (!var->upper_margin) var->upper_margin++; - if (!var->left_margin) var->left_margin++; - ivtv_window.top = var->upper_margin - 1; - ivtv_window.left = var->left_margin - 1; - - ivtv_fb_set_display_window(itv, &ivtv_window); - - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", - var->xres, var->yres, - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", - var->left_margin, var->upper_margin); - - IVTV_FB_DEBUG_INFO("Display filter: %s\n", - (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); - - return 0; -} - -static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) -{ - struct osd_info *oi = itv->osd_info; - - IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "cx23415 TV out"); - fix->smem_start = oi->video_pbase; - fix->smem_len = oi->video_buffer_size; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - fix->xpanstep = 1; - fix->ypanstep = 1; - fix->ywrapstep = 0; - fix->line_length = oi->display_byte_stride; - fix->accel = FB_ACCEL_NONE; - return 0; -} - -/* Check the requested display mode, returning -EINVAL if we can't - handle it. */ - -static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - int osd_height_limit; - u32 pixclock, hlimit, vlimit; - - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); - - /* Set base references for mode calcs. */ - if (itv->is_50hz) { - pixclock = 84316; - hlimit = 776; - vlimit = 591; - osd_height_limit = 576; - } - else { - pixclock = 83926; - hlimit = 776; - vlimit = 495; - osd_height_limit = 480; - } - - /* Check the bits per pixel */ - if (osd_compat) { - if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); - return -EINVAL; - } - } - - if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { - var->transp.offset = 24; - var->transp.length = 8; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - } - else if (var->bits_per_pixel == 16) { - /* To find out the true mode, check green length */ - switch (var->green.length) { - case 4: - var->red.offset = 8; - var->red.length = 4; - var->green.offset = 4; - var->green.length = 4; - var->blue.offset = 0; - var->blue.length = 4; - var->transp.offset = 12; - var->transp.length = 1; - break; - case 5: - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 15; - var->transp.length = 1; - break; - default: - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - } - } - else { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); - return -EINVAL; - } - - /* Check the resolution */ - if (osd_compat) { - if (var->xres != oi->ivtvfb_defined.xres || - var->yres != oi->ivtvfb_defined.yres || - var->xres_virtual != oi->ivtvfb_defined.xres_virtual || - var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", - var->xres, var->yres, var->xres_virtual, var->yres_virtual); - return -EINVAL; - } - } - else { - if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", - var->xres, var->yres); - return -EINVAL; - } - - /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ - if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || - var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || - var->xres_virtual < var->xres || - var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", - var->xres_virtual, var->yres_virtual); - return -EINVAL; - } - } - - /* Some extra checks if in 8 bit mode */ - if (var->bits_per_pixel == 8) { - /* Width must be a multiple of 4 */ - if (var->xres & 3) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); - return -EINVAL; - } - if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); - return -EINVAL; - } - } - else if (var->bits_per_pixel == 16) { - /* Width must be a multiple of 2 */ - if (var->xres & 1) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); - return -EINVAL; - } - if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); - return -EINVAL; - } - } - - /* Now check the offsets */ - if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", - var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); - return -EINVAL; - } - - /* Check pixel format */ - if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); - return -EINVAL; - } - - /* Check video mode */ - if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && - ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); - return -EINVAL; - } - - /* Check the left & upper margins - If the margins are too large, just center the screen - (enforcing margins causes too many problems) */ - - if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { - var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); - } - if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { - var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); - } - - /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = hlimit - var->left_margin - var->xres; - var->lower_margin = vlimit - var->upper_margin - var->yres; - - /* Fixed sync times */ - var->hsync_len = 24; - var->vsync_len = 2; - - /* Non-interlaced / interlaced mode is used to switch the OSD filter - on or off. Adjust the clock timings to maintain a constant - vertical refresh rate. */ - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - var->pixclock = pixclock / 2; - else - var->pixclock = pixclock; - - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", - var->xres, var->yres, - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", - var->left_margin, var->upper_margin); - - IVTV_FB_DEBUG_INFO("Display filter: %s\n", - (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); - return 0; -} - -static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); - return _ivtvfb_check_var(var, itv); -} - -static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - u32 osd_pan_index; - struct ivtv *itv = (struct ivtv *) info->par; - - osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; - write_reg(osd_pan_index, 0x02A0C); - - /* Pass this info back the yuv handler */ - itv->yuv_info.osd_x_pan = var->xoffset; - itv->yuv_info.osd_y_pan = var->yoffset; - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - return 0; -} - -static int ivtvfb_set_par(struct fb_info *info) -{ - int rc = 0; - struct ivtv *itv = (struct ivtv *) info->par; - - IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); - - rc = ivtvfb_set_var(itv, &info->var); - ivtvfb_pan_display(&info->var, info); - ivtvfb_get_fix(itv, &info->fix); - return rc; -} - -static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - u32 color, *palette; - struct ivtv *itv = (struct ivtv *)info->par; - - if (regno >= info->cmap.len) - return -EINVAL; - - color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); - if (info->var.bits_per_pixel <= 8) { - write_reg(regno, 0x02a30); - write_reg(color, 0x02a34); - return 0; - } - if (regno >= 16) - return -EINVAL; - - palette = info->pseudo_palette; - if (info->var.bits_per_pixel == 16) { - switch (info->var.green.length) { - case 4: - color = ((red & 0xf000) >> 4) | - ((green & 0xf000) >> 8) | - ((blue & 0xf000) >> 12); - break; - case 5: - color = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 6: - color = (red & 0xf800 ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - } - } - palette[regno] = color; - return 0; -} - -/* We don't really support blanking. All this does is enable or - disable the OSD. */ -static int ivtvfb_blank(int blank_mode, struct fb_info *info) -{ - struct ivtv *itv = (struct ivtv *)info->par; - - IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); - switch (blank_mode) { - case FB_BLANK_UNBLANK: - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); - break; - case FB_BLANK_NORMAL: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); - break; - } - return 0; -} - -static struct fb_ops ivtvfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = ivtvfb_check_var, - .fb_set_par = ivtvfb_set_par, - .fb_setcolreg = ivtvfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = NULL, - .fb_ioctl = ivtvfb_ioctl, - .fb_pan_display = ivtvfb_pan_display, - .fb_blank = ivtvfb_blank, -}; - -/* Initialization */ - - -/* Setup our initial video mode */ -static int ivtvfb_init_vidmode(struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - struct v4l2_rect start_window; - int max_height; - - /* Color mode */ - - if (osd_compat) osd_depth = 32; - if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; - oi->bits_per_pixel = osd_depth; - oi->bytes_per_pixel = oi->bits_per_pixel / 8; - - /* Invalidate current osd mode to force a mode switch later */ - oi->osd_mode = -1; - - /* Horizontal size & position */ - - if (osd_xres > 720) osd_xres = 720; - - /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ - if (osd_depth == 8) - osd_xres &= ~3; - else if (osd_depth == 16) - osd_xres &= ~1; - - if (osd_xres) - start_window.width = osd_xres; - else - start_window.width = osd_compat ? 720: 640; - - /* Check horizontal start (osd_left). */ - if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR("Invalid osd_left - assuming default\n"); - osd_left = 0; - } - - /* Hardware coords start at 0, user coords start at 1. */ - osd_left--; - - start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); - - oi->display_byte_stride = - start_window.width * oi->bytes_per_pixel; - - /* Vertical size & position */ - - max_height = itv->is_50hz ? 576 : 480; - - if (osd_yres > max_height) - osd_yres = max_height; - - if (osd_yres) - start_window.height = osd_yres; - else - start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400); - - /* Check vertical start (osd_upper). */ - if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); - osd_upper = 0; - } - - /* Hardware coords start at 0, user coords start at 1. */ - osd_upper--; - - start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); - - oi->display_width = start_window.width; - oi->display_height = start_window.height; - - /* Generate a valid fb_var_screeninfo */ - - oi->ivtvfb_defined.xres = oi->display_width; - oi->ivtvfb_defined.yres = oi->display_height; - oi->ivtvfb_defined.xres_virtual = oi->display_width; - oi->ivtvfb_defined.yres_virtual = oi->display_height; - oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; - oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); - oi->ivtvfb_defined.left_margin = start_window.left + 1; - oi->ivtvfb_defined.upper_margin = start_window.top + 1; - oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; - oi->ivtvfb_defined.nonstd = 0; - - /* We've filled in the most data, let the usual mode check - routine fill in the rest. */ - _ivtvfb_check_var(&oi->ivtvfb_defined, itv); - - /* Generate valid fb_fix_screeninfo */ - - ivtvfb_get_fix(itv, &oi->ivtvfb_fix); - - /* Generate valid fb_info */ - - oi->ivtvfb_info.node = -1; - oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; - oi->ivtvfb_info.fbops = &ivtvfb_ops; - oi->ivtvfb_info.par = itv; - oi->ivtvfb_info.var = oi->ivtvfb_defined; - oi->ivtvfb_info.fix = oi->ivtvfb_fix; - oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; - oi->ivtvfb_info.fbops = &ivtvfb_ops; - - /* Supply some monitor specs. Bogus values will do for now */ - oi->ivtvfb_info.monspecs.hfmin = 8000; - oi->ivtvfb_info.monspecs.hfmax = 70000; - oi->ivtvfb_info.monspecs.vfmin = 10; - oi->ivtvfb_info.monspecs.vfmax = 100; - - /* Allocate color map */ - if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR("abort, unable to alloc cmap\n"); - return -ENOMEM; - } - - /* Allocate the pseudo palette */ - oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); - - if (!oi->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); - return -ENOMEM; - } - - return 0; -} - -/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ - -static int ivtvfb_init_io(struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - - mutex_lock(&itv->serialize_lock); - if (ivtv_init_on_first_open(itv)) { - mutex_unlock(&itv->serialize_lock); - IVTV_FB_ERR("Failed to initialize ivtv\n"); - return -ENXIO; - } - mutex_unlock(&itv->serialize_lock); - - ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); - - /* The osd buffer size depends on the number of video buffers allocated - on the PVR350 itself. For now we'll hardcode the smallest osd buffer - size to prevent any overlap. */ - oi->video_buffer_size = 1704960; - - oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; - oi->video_vbase = itv->dec_mem + oi->video_rbase; - - if (!oi->video_vbase) { - IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", - oi->video_buffer_size, oi->video_pbase); - return -EIO; - } - - IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - oi->video_pbase, oi->video_vbase, - oi->video_buffer_size / 1024); - -#ifdef CONFIG_MTRR - { - /* Find the largest power of two that maps the whole buffer */ - int size_shift = 31; - - while (!(oi->video_buffer_size & (1 << size_shift))) { - size_shift--; - } - size_shift++; - oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); - oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; - oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; - oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); - if (mtrr_add(oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, - MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_WARN("cannot use mttr\n"); - oi->fb_start_aligned_physaddr = 0; - oi->fb_end_aligned_physaddr = 0; - } - } -#endif - - /* Blank the entire osd. */ - memset_io(oi->video_vbase, 0, oi->video_buffer_size); - - return 0; -} - -/* Release any memory we've grabbed & remove mtrr entry */ -static void ivtvfb_release_buffers (struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - - /* Release cmap */ - if (oi->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&oi->ivtvfb_info.cmap); - - /* Release pseudo palette */ - if (oi->ivtvfb_info.pseudo_palette) - kfree(oi->ivtvfb_info.pseudo_palette); - -#ifdef CONFIG_MTRR - if (oi->fb_end_aligned_physaddr) { - mtrr_del(-1, oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); - } -#endif - - kfree(oi); - itv->osd_info = NULL; -} - -/* Initialize the specified card */ - -static int ivtvfb_init_card(struct ivtv *itv) -{ - int rc; - - if (itv->osd_info) { - IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); - return -EBUSY; - } - - itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); - if (itv->osd_info == 0) { - IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); - return -ENOMEM; - } - - /* Find & setup the OSD buffer */ - if ((rc = ivtvfb_init_io(itv))) - return rc; - - /* Set the startup video mode information */ - if ((rc = ivtvfb_init_vidmode(itv))) { - ivtvfb_release_buffers(itv); - return rc; - } - - /* Register the framebuffer */ - if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { - ivtvfb_release_buffers(itv); - return -EINVAL; - } - - itv->osd_video_pbase = itv->osd_info->video_pbase; - - /* Set the card to the requested mode */ - ivtvfb_set_par(&itv->osd_info->ivtvfb_info); - - /* Set color 0 to black */ - write_reg(0, 0x02a30); - write_reg(0, 0x02a34); - - /* Enable the osd */ - ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); - - /* Note if we're running in compatibility mode */ - if (osd_compat) - IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); - - /* Allocate DMA */ - ivtv_udma_alloc(itv); - return 0; - -} - -static int __init ivtvfb_init(void) -{ - struct ivtv *itv; - int i, registered = 0; - - if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", - IVTV_MAX_CARDS - 1); - return -EINVAL; - } - - /* Locate & initialise all cards supporting an OSD. */ - for (i = 0; i < ivtv_cards_active; i++) { - if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) - continue; - itv = ivtv_cards[i]; - if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (ivtvfb_init_card(itv) == 0) { - IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); - registered++; - } - } - } - if (!registered) { - printk(KERN_ERR "ivtv-fb: no cards found"); - return -ENODEV; - } - return 0; -} - -static void ivtvfb_cleanup(void) -{ - struct ivtv *itv; - int i; - - printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); - - for (i = 0; i < ivtv_cards_active; i++) { - itv = ivtv_cards[i]; - if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { - IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); - ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); - unregister_framebuffer(&itv->osd_info->ivtvfb_info); - ivtvfb_release_buffers(itv); - itv->osd_video_pbase = 0; - } - } -} - -module_init(ivtvfb_init); -module_exit(ivtvfb_cleanup); diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c new file mode 100644 index 000000000000..ff721c088479 --- /dev/null +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -0,0 +1,1190 @@ +/* + On Screen Display cx23415 Framebuffer driver + + This module presents the cx23415 OSD (onscreen display) framebuffer memory + as a standard Linux /dev/fb style framebuffer device. The framebuffer has + support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + mode, there is a choice of a three color depths (12, 15 or 16 bits), but no + local alpha. The colorspace is selectable between rgb & yuv. + Depending on the TV standard configured in the ivtv module at load time, + the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. + Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) + or 59.94 (NTSC) + + Copyright (c) 2003 Matt T. Yourst + + Derived from drivers/video/vesafb.c + Portions (c) 1998 Gerd Knorr + + 2.6 kernel port: + Copyright (C) 2004 Matthias Badaire + + Copyright (C) 2004 Chris Kennedy + + Copyright (C) 2006 Ian Armstrong + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv-driver.h" +#include "ivtv-udma.h" +#include "ivtv-mailbox.h" + +/* card parameters */ +static int ivtv_fb_card_id = -1; +static int ivtv_fb_debug = 0; +static int osd_laced; +static int osd_compat; +static int osd_depth; +static int osd_upper; +static int osd_left; +static int osd_yres; +static int osd_xres; + +module_param(ivtv_fb_card_id, int, 0444); +module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(osd_laced, bool, 0444); +module_param(osd_compat, bool, 0444); +module_param(osd_depth, int, 0444); +module_param(osd_upper, int, 0444); +module_param(osd_left, int, 0444); +module_param(osd_yres, int, 0444); +module_param(osd_xres, int, 0444); + +MODULE_PARM_DESC(ivtv_fb_card_id, + "Only use framebuffer of the specified ivtv card (0-31)\n" + "\t\t\tdefault -1: initialize all available framebuffers"); + +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: errors only\n" + "\t\t\t(debug = 3 gives full debugging)"); + +MODULE_PARM_DESC(osd_compat, + "Compatibility mode - Display size is locked (use for old X drivers)\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +/* Why upper, left, xres, yres, depth, laced ? To match terminology used + by fbset. + Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ + +MODULE_PARM_DESC(osd_laced, + "Interlaced mode\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +MODULE_PARM_DESC(osd_depth, + "Bits per pixel - 8, 16, 32\n" + "\t\t\tdefault 8"); + +MODULE_PARM_DESC(osd_upper, + "Vertical start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_left, + "Horizontal start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_yres, + "Display height\n" + "\t\t\tdefault 480 (PAL)\n" + "\t\t\t 400 (NTSC)"); + +MODULE_PARM_DESC(osd_xres, + "Display width\n" + "\t\t\tdefault 640"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); +MODULE_LICENSE("GPL"); + +/* --------------------------------------------------------------------- */ + +#define IVTV_FB_DBGFLG_WARN (1 << 0) +#define IVTV_FB_DBGFLG_INFO (1 << 1) + +#define IVTV_FB_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtv_fb_debug) \ + printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + } while (0) +#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) + +/* Standard kernel messages */ +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) + +/* --------------------------------------------------------------------- */ + +#define IVTV_OSD_MAX_WIDTH 720 +#define IVTV_OSD_MAX_HEIGHT 576 + +#define IVTV_OSD_BPP_8 0x00 +#define IVTV_OSD_BPP_16_444 0x03 +#define IVTV_OSD_BPP_16_555 0x02 +#define IVTV_OSD_BPP_16_565 0x01 +#define IVTV_OSD_BPP_32 0x04 + +struct osd_info { + /* Physical base address */ + unsigned long video_pbase; + /* Relative base address (relative to start of decoder memory) */ + u32 video_rbase; + /* Mapped base address */ + volatile char __iomem *video_vbase; + /* Buffer size */ + u32 video_buffer_size; + +#ifdef CONFIG_MTRR + /* video_base rounded down as required by hardware MTRRs */ + unsigned long fb_start_aligned_physaddr; + /* video_base rounded up as required by hardware MTRRs */ + unsigned long fb_end_aligned_physaddr; +#endif + + /* Current osd mode */ + int osd_mode; + + /* Store the buffer offset */ + int set_osd_coords_x; + int set_osd_coords_y; + + /* Current dimensions (NOT VISIBLE SIZE!) */ + int display_width; + int display_height; + int display_byte_stride; + + /* Current bits per pixel */ + int bits_per_pixel; + int bytes_per_pixel; + + /* Frame buffer stuff */ + struct fb_info ivtvfb_info; + struct fb_var_screeninfo ivtvfb_defined; + struct fb_fix_screeninfo ivtvfb_fix; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +/* --------------------------------------------------------------------- */ + +/* ivtv API calls for framebuffer related support */ + +static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, + u32 *fblength) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + int rc; + + rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); + *fbbase = data[0]; + *fblength = data[1]; + return rc; +} + +static int ivtv_fb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + struct osd_info *oi = itv->osd_info; + u32 data[CX2341X_MBOX_MAX_DATA]; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); + + osd->offset = data[0] - oi->video_rbase; + osd->max_offset = oi->display_width * oi->display_height * 4; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + return 0; +} + +static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +{ + struct osd_info *oi = itv->osd_info; + + oi->display_width = osd->pixel_stride; + oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; + oi->set_osd_coords_x += osd->x; + oi->set_osd_coords_y = osd->y; + + return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, + osd->offset + oi->video_rbase, + osd->pixel_stride, + osd->lines, osd->x, osd->y); +} + +static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +{ + int osd_height_limit = itv->is_50hz ? 576 : 480; + + /* Only fail if resolution too high, otherwise fudge the start coords. */ + if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) + return -EINVAL; + + /* Ensure we don't exceed display limits */ + if (ivtv_window->top + ivtv_window->height > osd_height_limit) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", + ivtv_window->top, ivtv_window->height); + ivtv_window->top = osd_height_limit - ivtv_window->height; + } + + if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", + ivtv_window->left, ivtv_window->width); + ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; + } + + /* Set the OSD origin */ + write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); + + /* How much to display */ + write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_vis_w = ivtv_window->width; + itv->yuv_info.osd_vis_h = ivtv_window->height; + itv->yuv_info.osd_x_offset = ivtv_window->left; + itv->yuv_info.osd_y_offset = ivtv_window->top; + + return 0; +} + +static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, + unsigned long ivtv_dest_addr, void __user *userbuf, + int size_in_bytes) +{ + DEFINE_WAIT(wait); + int ret = 0; + int got_sig = 0; + + mutex_lock(&itv->udma.lock); + /* Map User DMA */ + if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { + mutex_unlock(&itv->udma.lock); + IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + "Error with get_user_pages: %d bytes, %d pages returned\n", + size_in_bytes, itv->udma.page_count); + + /* get_user_pages must have failed completely */ + return -EIO; + } + + IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + size_in_bytes, itv->udma.page_count); + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + mutex_unlock(&itv->udma.lock); + if (got_sig) { + IVTV_DEBUG_INFO("User stopped OSD\n"); + return -EINTR; + } + + return ret; +} + +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, + unsigned long dest_offset, int count) +{ + DEFINE_WAIT(wait); + struct osd_info *oi = itv->osd_info; + + /* Nothing to do */ + if (count == 0) { + IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + return -EINVAL; + } + + /* Check Total FB Size */ + if ((dest_offset + count) > oi->video_buffer_size) { + IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + dest_offset + count, oi->video_buffer_size); + return -E2BIG; + } + + /* Not fatal, but will have undesirable results */ + if ((unsigned long)source & 3) + IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + (unsigned long)source); + + if (dest_offset & 3) + IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); + + if (count & 3) + IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); + + /* Check Source */ + if (!access_ok(VERIFY_READ, source + dest_offset, count)) { + IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", + (unsigned long)source); + + IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + dest_offset, (unsigned long)source, + count); + return -EINVAL; + } + + /* OSD Address to send DMA to */ + dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; + + /* Fill Buffers */ + return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); +} + +static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + DEFINE_WAIT(wait); + struct ivtv *itv = (struct ivtv *)info->par; + int rc = 0; + + switch (cmd) { + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + u32 trace; + + vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + trace = read_reg(0x028c0) >> 16; + if (itv->is_50hz && trace > 312) trace -= 312; + else if (itv->is_60hz && trace > 262) trace -= 262; + if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; + vblank.count = itv->last_vsync_field; + vblank.vcount = trace; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + case FBIO_WAITFORVSYNC: + prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); + if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; + finish_wait(&itv->vsync_waitq, &wait); + return rc; + + case IVTVFB_IOC_DMA_FRAME: { + struct ivtvfb_dma_frame args; + + IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); + if (copy_from_user(&args, (void __user *)arg, sizeof(args))) + return -EFAULT; + + return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + } + + default: + IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) +{ + struct osd_info *oi = itv->osd_info; + struct ivtv_osd_coords ivtv_osd; + struct v4l2_rect ivtv_window; + int osd_mode = -1; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + + /* Select color space */ + if (var->nonstd) /* YUV */ + write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); + else /* RGB */ + write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); + + /* Set the color mode */ + switch (var->bits_per_pixel) { + case 8: + osd_mode = IVTV_OSD_BPP_8; + break; + case 32: + osd_mode = IVTV_OSD_BPP_32; + break; + case 16: + switch (var->green.length) { + case 4: + osd_mode = IVTV_OSD_BPP_16_444; + break; + case 5: + osd_mode = IVTV_OSD_BPP_16_555; + break; + case 6: + osd_mode = IVTV_OSD_BPP_16_565; + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + + /* Change osd mode if needed. + Although rare, things can go wrong. The extra mode + change seems to help... */ + if (osd_mode != -1 && osd_mode != oi->osd_mode) { + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); + oi->osd_mode = osd_mode; + } + + oi->bits_per_pixel = var->bits_per_pixel; + oi->bytes_per_pixel = var->bits_per_pixel / 8; + + /* Set the flicker filter */ + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: /* Filter on */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); + break; + case FB_VMODE_INTERLACED: /* Filter off */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + } + + /* Read the current osd info */ + ivtv_fb_get_osd_coords(itv, &ivtv_osd); + + /* Now set the OSD to the size we want */ + ivtv_osd.pixel_stride = var->xres_virtual; + ivtv_osd.lines = var->yres_virtual; + ivtv_osd.x = 0; + ivtv_osd.y = 0; + ivtv_fb_set_osd_coords(itv, &ivtv_osd); + + /* Can't seem to find the right API combo for this. + Use another function which does what we need through direct register access. */ + ivtv_window.width = var->xres; + ivtv_window.height = var->yres; + + /* Minimum margin cannot be 0, as X won't allow such a mode */ + if (!var->upper_margin) var->upper_margin++; + if (!var->left_margin) var->left_margin++; + ivtv_window.top = var->upper_margin - 1; + ivtv_window.left = var->left_margin - 1; + + ivtv_fb_set_display_window(itv, &ivtv_window); + + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); + + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + + return 0; +} + +static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) +{ + struct osd_info *oi = itv->osd_info; + + IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "cx23415 TV out"); + fix->smem_start = oi->video_pbase; + fix->smem_len = oi->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = oi->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + int osd_height_limit; + u32 pixclock, hlimit, vlimit; + + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + pixclock = 84316; + hlimit = 776; + vlimit = 591; + osd_height_limit = 576; + } + else { + pixclock = 83926; + hlimit = 776; + vlimit = 495; + osd_height_limit = 480; + } + + /* Check the bits per pixel */ + if (osd_compat) { + if (var->bits_per_pixel != 32) { + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + return -EINVAL; + } + } + + if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + else if (var->bits_per_pixel == 16) { + /* To find out the true mode, check green length */ + switch (var->green.length) { + case 4: + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + var->transp.offset = 12; + var->transp.length = 1; + break; + case 5: + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + break; + default: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + } + } + else { + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + return -EINVAL; + } + + /* Check the resolution */ + if (osd_compat) { + if (var->xres != oi->ivtvfb_defined.xres || + var->yres != oi->ivtvfb_defined.yres || + var->xres_virtual != oi->ivtvfb_defined.xres_virtual || + var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + var->xres, var->yres, var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + else { + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + var->xres, var->yres); + return -EINVAL; + } + + /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ + if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || + var->xres_virtual < var->xres || + var->yres_virtual < var->yres) { + IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + + /* Some extra checks if in 8 bit mode */ + if (var->bits_per_pixel == 8) { + /* Width must be a multiple of 4 */ + if (var->xres & 3) { + IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 3) { + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + else if (var->bits_per_pixel == 16) { + /* Width must be a multiple of 2 */ + if (var->xres & 1) { + IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 1) { + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + + /* Now check the offsets */ + if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { + IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); + return -EINVAL; + } + + /* Check pixel format */ + if (var->nonstd > 1) { + IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); + return -EINVAL; + } + + /* Check video mode */ + if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && + ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { + IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); + return -EINVAL; + } + + /* Check the left & upper margins + If the margins are too large, just center the screen + (enforcing margins causes too many problems) */ + + if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { + var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); + } + if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { + var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); + } + + /* Maintain overall 'size' for a constant refresh rate */ + var->right_margin = hlimit - var->left_margin - var->xres; + var->lower_margin = vlimit - var->upper_margin - var->yres; + + /* Fixed sync times */ + var->hsync_len = 24; + var->vsync_len = 2; + + /* Non-interlaced / interlaced mode is used to switch the OSD filter + on or off. Adjust the clock timings to maintain a constant + vertical refresh rate. */ + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + var->pixclock = pixclock / 2; + else + var->pixclock = pixclock; + + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); + + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + return 0; +} + +static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *) info->par; + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + return _ivtvfb_check_var(var, itv); +} + +static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 osd_pan_index; + struct ivtv *itv = (struct ivtv *) info->par; + + osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; + write_reg(osd_pan_index, 0x02A0C); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_x_pan = var->xoffset; + itv->yuv_info.osd_y_pan = var->yoffset; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + return 0; +} + +static int ivtvfb_set_par(struct fb_info *info) +{ + int rc = 0; + struct ivtv *itv = (struct ivtv *) info->par; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); + + rc = ivtvfb_set_var(itv, &info->var); + ivtvfb_pan_display(&info->var, info); + ivtvfb_get_fix(itv, &info->fix); + return rc; +} + +static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + struct ivtv *itv = (struct ivtv *)info->par; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (info->var.bits_per_pixel <= 8) { + write_reg(regno, 0x02a30); + write_reg(color, 0x02a34); + return 0; + } + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + } + } + palette[regno] = color; + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int ivtvfb_blank(int blank_mode, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *)info->par; + + IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + break; + } + return 0; +} + +static struct fb_ops ivtvfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = ivtvfb_check_var, + .fb_set_par = ivtvfb_set_par, + .fb_setcolreg = ivtvfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = ivtvfb_ioctl, + .fb_pan_display = ivtvfb_pan_display, + .fb_blank = ivtvfb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int ivtvfb_init_vidmode(struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + struct v4l2_rect start_window; + int max_height; + + /* Color mode */ + + if (osd_compat) osd_depth = 32; + if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; + oi->bits_per_pixel = osd_depth; + oi->bytes_per_pixel = oi->bits_per_pixel / 8; + + /* Invalidate current osd mode to force a mode switch later */ + oi->osd_mode = -1; + + /* Horizontal size & position */ + + if (osd_xres > 720) osd_xres = 720; + + /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ + if (osd_depth == 8) + osd_xres &= ~3; + else if (osd_depth == 16) + osd_xres &= ~1; + + if (osd_xres) + start_window.width = osd_xres; + else + start_window.width = osd_compat ? 720: 640; + + /* Check horizontal start (osd_left). */ + if (osd_left && osd_left + start_window.width > 721) { + IVTV_FB_ERR("Invalid osd_left - assuming default\n"); + osd_left = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_left--; + + start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + + oi->display_byte_stride = + start_window.width * oi->bytes_per_pixel; + + /* Vertical size & position */ + + max_height = itv->is_50hz ? 576 : 480; + + if (osd_yres > max_height) + osd_yres = max_height; + + if (osd_yres) + start_window.height = osd_yres; + else + start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400); + + /* Check vertical start (osd_upper). */ + if (osd_upper + start_window.height > max_height + 1) { + IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); + osd_upper = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_upper--; + + start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); + + oi->display_width = start_window.width; + oi->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + oi->ivtvfb_defined.xres = oi->display_width; + oi->ivtvfb_defined.yres = oi->display_height; + oi->ivtvfb_defined.xres_virtual = oi->display_width; + oi->ivtvfb_defined.yres_virtual = oi->display_height; + oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; + oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + oi->ivtvfb_defined.left_margin = start_window.left + 1; + oi->ivtvfb_defined.upper_margin = start_window.top + 1; + oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + oi->ivtvfb_defined.nonstd = 0; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _ivtvfb_check_var(&oi->ivtvfb_defined, itv); + + /* Generate valid fb_fix_screeninfo */ + + ivtvfb_get_fix(itv, &oi->ivtvfb_fix); + + /* Generate valid fb_info */ + + oi->ivtvfb_info.node = -1; + oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.par = itv; + oi->ivtvfb_info.var = oi->ivtvfb_defined; + oi->ivtvfb_info.fix = oi->ivtvfb_fix; + oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + oi->ivtvfb_info.monspecs.hfmin = 8000; + oi->ivtvfb_info.monspecs.hfmax = 70000; + oi->ivtvfb_info.monspecs.vfmin = 10; + oi->ivtvfb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + + if (!oi->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); + return -ENOMEM; + } + + return 0; +} + +/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ + +static int ivtvfb_init_io(struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + mutex_unlock(&itv->serialize_lock); + IVTV_FB_ERR("Failed to initialize ivtv\n"); + return -ENXIO; + } + mutex_unlock(&itv->serialize_lock); + + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); + + /* The osd buffer size depends on the number of video buffers allocated + on the PVR350 itself. For now we'll hardcode the smallest osd buffer + size to prevent any overlap. */ + oi->video_buffer_size = 1704960; + + oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; + oi->video_vbase = itv->dec_mem + oi->video_rbase; + + if (!oi->video_vbase) { + IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + oi->video_buffer_size, oi->video_pbase); + return -EIO; + } + + IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + oi->video_pbase, oi->video_vbase, + oi->video_buffer_size / 1024); + +#ifdef CONFIG_MTRR + { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + + while (!(oi->video_buffer_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); + oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; + oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; + oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, + MTRR_TYPE_WRCOMB, 1) < 0) { + IVTV_FB_WARN("cannot use mttr\n"); + oi->fb_start_aligned_physaddr = 0; + oi->fb_end_aligned_physaddr = 0; + } + } +#endif + + /* Blank the entire osd. */ + memset_io(oi->video_vbase, 0, oi->video_buffer_size); + + return 0; +} + +/* Release any memory we've grabbed & remove mtrr entry */ +static void ivtvfb_release_buffers (struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + + /* Release cmap */ + if (oi->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); + + /* Release pseudo palette */ + if (oi->ivtvfb_info.pseudo_palette) + kfree(oi->ivtvfb_info.pseudo_palette); + +#ifdef CONFIG_MTRR + if (oi->fb_end_aligned_physaddr) { + mtrr_del(-1, oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); + } +#endif + + kfree(oi); + itv->osd_info = NULL; +} + +/* Initialize the specified card */ + +static int ivtvfb_init_card(struct ivtv *itv) +{ + int rc; + + if (itv->osd_info) { + IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + return -EBUSY; + } + + itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); + if (itv->osd_info == 0) { + IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + return -ENOMEM; + } + + /* Find & setup the OSD buffer */ + if ((rc = ivtvfb_init_io(itv))) + return rc; + + /* Set the startup video mode information */ + if ((rc = ivtvfb_init_vidmode(itv))) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Register the framebuffer */ + if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { + ivtvfb_release_buffers(itv); + return -EINVAL; + } + + itv->osd_video_pbase = itv->osd_info->video_pbase; + + /* Set the card to the requested mode */ + ivtvfb_set_par(&itv->osd_info->ivtvfb_info); + + /* Set color 0 to black */ + write_reg(0, 0x02a30); + write_reg(0, 0x02a34); + + /* Enable the osd */ + ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); + + /* Note if we're running in compatibility mode */ + if (osd_compat) + IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + + /* Allocate DMA */ + ivtv_udma_alloc(itv); + return 0; + +} + +static int __init ivtvfb_init(void) +{ + struct ivtv *itv; + int i, registered = 0; + + if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + IVTV_MAX_CARDS - 1); + return -EINVAL; + } + + /* Locate & initialise all cards supporting an OSD. */ + for (i = 0; i < ivtv_cards_active; i++) { + if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + continue; + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (ivtvfb_init_card(itv) == 0) { + IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + registered++; + } + } + } + if (!registered) { + printk(KERN_ERR "ivtv-fb: no cards found"); + return -ENODEV; + } + return 0; +} + +static void ivtvfb_cleanup(void) +{ + struct ivtv *itv; + int i; + + printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + + for (i = 0; i < ivtv_cards_active; i++) { + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { + IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + unregister_framebuffer(&itv->osd_info->ivtvfb_info); + ivtvfb_release_buffers(itv); + itv->osd_video_pbase = 0; + } + } +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff --git a/include/linux/ivtvfb.h b/include/linux/ivtvfb.h new file mode 100644 index 000000000000..e980ba62ddcc --- /dev/null +++ b/include/linux/ivtvfb.h @@ -0,0 +1,42 @@ +/* + On Screen Display cx23415 Framebuffer driver + + Copyright (C) 2006, 2007 Ian Armstrong + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_IVTVFB_H__ +#define __LINUX_IVTVFB_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include + +/* Framebuffer external API */ + +struct ivtvfb_dma_frame { + void __user *source; + unsigned long dest_offset; + int count; +}; + +#define IVTVFB_IOC_DMA_FRAME _IOW('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) + +#endif diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h deleted file mode 100644 index d3a797b17280..000000000000 --- a/include/media/ivtv-fb.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - On Screen Display cx23415 Framebuffer driver - - Copyright (C) 2006 Ian Armstrong - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_IVTV_FB_H -#define _LINUX_IVTV_FB_H - -/* Framebuffer external API */ - -struct ivtvfb_dma_frame { - void __user *source; - unsigned long dest_offset; - int count; -}; - -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) - -#endif -- cgit v1.2.3 From 51b39dfa5477fdb2459e3c46f855f01b8b03102d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:13:04 -0300 Subject: V4L/DVB (6123): ivtv: move ivtv.h public header to include/linux Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 +- include/linux/ivtv.h | 72 ++++++++++++++++++++++++++++++++++ include/media/ivtv.h | 65 ------------------------------ 3 files changed, 73 insertions(+), 66 deletions(-) create mode 100644 include/linux/ivtv.h delete mode 100644 include/media/ivtv.h (limited to 'include') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 32dfc7a859fa..3bda1df63cb6 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -62,7 +62,7 @@ #include #include -#include +#include /* Memory layout */ diff --git a/include/linux/ivtv.h b/include/linux/ivtv.h new file mode 100644 index 000000000000..794b8daa9378 --- /dev/null +++ b/include/linux/ivtv.h @@ -0,0 +1,72 @@ +/* + Public ivtv API header + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004-2007 Hans Verkuil + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_IVTV_H__ +#define __LINUX_IVTV_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include + +/* ivtv knows several distinct output modes: MPEG streaming, + YUV streaming, YUV updates through user DMA and the passthrough + mode. + + In order to clearly tell the driver that we are in user DMA + YUV mode you need to call IVTV_IOC_DMA_FRAME with y_source == NULL + first (althrough if you don't then the first time + DMA_FRAME is called the mode switch is done automatically). + + When you close the file handle the user DMA mode is exited again. + + While in one mode, you cannot use another mode (EBUSY is returned). + + All this means that if you want to change the YUV interlacing + for the user DMA YUV mode you first need to do call IVTV_IOC_DMA_FRAME + with y_source == NULL before you can set the correct format using + VIDIOC_S_FMT. + + Eventually all this should be replaced with a proper V4L2 API, + but for now we have to do it this way. */ + +struct ivtv_dma_frame { + enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_OUTPUT */ + __u32 pixelformat; /* 0 == same as destination */ + void __user *y_source; /* if NULL and type == V4L2_BUF_TYPE_VIDEO_OUTPUT, + then just switch to user DMA YUV output mode */ + void __user *uv_source; /* Unused for RGB pixelformats */ + struct v4l2_rect src; + struct v4l2_rect dst; + __u32 src_width; + __u32 src_height; +}; + +#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) + +/* These are the VBI types as they appear in the embedded VBI private packets. */ +#define IVTV_SLICED_TYPE_TELETEXT_B (1) +#define IVTV_SLICED_TYPE_CAPTION_525 (4) +#define IVTV_SLICED_TYPE_WSS_625 (5) +#define IVTV_SLICED_TYPE_VPS (7) + +#endif /* _LINUX_IVTV_H */ diff --git a/include/media/ivtv.h b/include/media/ivtv.h deleted file mode 100644 index 412b48ea8eda..000000000000 --- a/include/media/ivtv.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Public ivtv API header - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004-2007 Hans Verkuil - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_IVTV_H -#define _LINUX_IVTV_H - -/* ivtv knows several distinct output modes: MPEG streaming, - YUV streaming, YUV updates through user DMA and the passthrough - mode. - - In order to clearly tell the driver that we are in user DMA - YUV mode you need to call IVTV_IOC_DMA_FRAME with y_source == NULL - first (althrough if you don't then the first time - DMA_FRAME is called the mode switch is done automatically). - - When you close the file handle the user DMA mode is exited again. - - While in one mode, you cannot use another mode (EBUSY is returned). - - All this means that if you want to change the YUV interlacing - for the user DMA YUV mode you first need to do call IVTV_IOC_DMA_FRAME - with y_source == NULL before you can set the correct format using - VIDIOC_S_FMT. - - Eventually all this should be replaced with a proper V4L2 API, - but for now we have to do it this way. */ - -struct ivtv_dma_frame { - enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_OUTPUT */ - __u32 pixelformat; /* 0 == same as destination */ - void __user *y_source; /* if NULL and type == V4L2_BUF_TYPE_VIDEO_OUTPUT, - then just switch to user DMA YUV output mode */ - void __user *uv_source; /* Unused for RGB pixelformats */ - struct v4l2_rect src; - struct v4l2_rect dst; - __u32 src_width; - __u32 src_height; -}; - -#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) - -/* These are the VBI types as they appear in the embedded VBI private packets. */ -#define IVTV_SLICED_TYPE_TELETEXT_B (1) -#define IVTV_SLICED_TYPE_CAPTION_525 (4) -#define IVTV_SLICED_TYPE_WSS_625 (5) -#define IVTV_SLICED_TYPE_VPS (7) - -#endif /* _LINUX_IVTV_H */ -- cgit v1.2.3 From 275511a0aca8483c03df1c6e3a33a27cee334709 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sun, 11 Mar 2007 20:44:05 -0300 Subject: V4L/DVB (6149): Add I2C_HW_B_CX23885 for Conexant 23885/23887 PCIe bridge Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- include/linux/i2c-id.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 4891e03ad23a..a271b67a8e2d 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -197,6 +197,7 @@ #define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */ #define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */ #define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */ +#define I2C_HW_B_CX23885 0x010022 /* conexant 23885 based tv cards (bus1) */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x020000 /* Parallel port interface */ -- cgit v1.2.3 From d54d6980916d5521ad47fa61e5b6ff8733221714 Mon Sep 17 00:00:00 2001 From: Chaogui Zhang Date: Fri, 24 Aug 2007 01:02:32 -0300 Subject: V4L/DVB (6178): add IR remote support for FusionHDTV 5 RT Gold This patch adds support for the built-in IR receiver of the DViCO Fusion HDTV5 RT GOLD PCI card, using FusionHDTV MCE remote controller. Signed-off-by: Chaogui Zhang Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 69 +++++++++++++++++++++++++++++++++++++++ drivers/media/video/ir-kbd-i2c.c | 36 +++++++++++++++++++- include/media/ir-common.h | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 137f68bee39f..1879c304ae6d 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1782,3 +1782,72 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_tt_1500); + +/* DViCO FUSION HDTV 5 RT GOLD remote */ +IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { + + [ 0x0b ] = KEY_1, + [ 0x17 ] = KEY_2, + [ 0x1b ] = KEY_3, + [ 0x07 ] = KEY_4, + [ 0x50 ] = KEY_5, + [ 0x54 ] = KEY_6, + [ 0x48 ] = KEY_7, + [ 0x4c ] = KEY_8, + [ 0x58 ] = KEY_9, + [ 0x03 ] = KEY_0, + + [ 0x5e ] = KEY_OK, + [ 0x51 ] = KEY_UP, + [ 0x53 ] = KEY_DOWN, + [ 0x5b ] = KEY_LEFT, + [ 0x5f ] = KEY_RIGHT, + + [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ + [ 0x0e ] = KEY_MP3, + [ 0x1a ] = KEY_DVD, + [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x16 ] = KEY_SETUP, + [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ + [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ + + [ 0x49 ] = KEY_BACK, + [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ + [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ + [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ + [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + * MS windows logo on remote */ + + [ 0x15 ] = KEY_VOLUMEUP, + [ 0x05 ] = KEY_VOLUMEDOWN, + [ 0x11 ] = KEY_CHANNELUP, + [ 0x09 ] = KEY_CHANNELDOWN, + + /* The following are not defined in kernel 2.6 and + * I cannot find suitable substitute key definitions. + + [ 0x52 ] = KEY_PHOTO, + [ 0x5a ] = KEY_LIVE, + [ 0x19 ] = KEY_FOLDER, + + */ + + [ 0x52 ] = KEY_RESERVED, + [ 0x5a ] = KEY_RESERVED, + [ 0x19 ] = KEY_RESERVED, + + [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ + [ 0x1f ] = KEY_ZOOM, + + [ 0x43 ] = KEY_REWIND, + [ 0x47 ] = KEY_PLAYPAUSE, + [ 0x4f ] = KEY_FORWARD, + [ 0x57 ] = KEY_MUTE, + [ 0x0d ] = KEY_STOP, + [ 0x01 ] = KEY_RECORD, + [ 0x4e ] = KEY_POWER, +}; + +EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index b3939a0bada0..3d5a28c2c929 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -10,6 +10,8 @@ * Ulrich Mueller * modified for em2820 based USB TV tuners by * Markus Rechberger + * modified for DViCO Fusion HDTV 5 RT GOLD by + * Chaogui Zhang * * 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 @@ -141,6 +143,32 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } +static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char buf[4]; + + /* poll IR chip */ + if (4 != i2c_master_recv(&ir->c,buf,4)) { + dprintk(1,"read error\n"); + return -EIO; + } + + if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) + dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + buf[0], buf[1], buf[2], buf[3]); + + /* no key pressed or signal from other ir remote */ + if(buf[0] != 0x1 || buf[1] != 0xfe) + return 0; + + *ir_key = buf[2]; + *ir_raw = (buf[2] << 8) | buf[3]; + + return 1; + +} + + static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -363,6 +391,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_type = IR_TYPE_OTHER; ir_codes = ir_codes_empty; break; + case 0x6b: + name = "FusionGold"; + ir->get_key = get_key_fusion_gold; + ir_type = IR_TYPE_RC5; + ir_codes = ir_codes_fusion_gold; + break; case 0x7a: case 0x47: case 0x71: @@ -474,7 +508,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; - static const int probe_cx88[] = { 0x18, 0x71, -1 }; + static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 9807a7c15830..dfae84038e2d 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,6 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; #endif -- cgit v1.2.3 From 3c44358c49ee4142d0f868509b5b3b02759fa16a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:07:12 -0300 Subject: V4L/DVB (6179): Clean up FusionHDTV ir code - fixed missing buttons in keymap. - make function names & descriptions more generic, since this same ir receiver and remote is used in many FusionHDTV products. - miscellaneous cleanups. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 32 ++++++++++++-------------------- drivers/media/video/ir-kbd-i2c.c | 12 +++++------- include/media/ir-common.h | 2 +- 3 files changed, 18 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 1879c304ae6d..aefcf28da1ca 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1783,8 +1783,8 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { EXPORT_SYMBOL_GPL(ir_codes_tt_1500); -/* DViCO FUSION HDTV 5 RT GOLD remote */ -IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { +/* DViCO FUSION HDTV MCE remote */ +IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { [ 0x0b ] = KEY_1, [ 0x17 ] = KEY_2, @@ -1806,7 +1806,7 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ [ 0x0e ] = KEY_MP3, [ 0x1a ] = KEY_DVD, - [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x1e ] = KEY_FAVORITES, /* Labeled CPF on remote */ [ 0x16 ] = KEY_SETUP, [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ @@ -1815,9 +1815,10 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ - [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ - [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ - [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + + [ 0x0f ] = KEY_PREVIOUSSONG, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_NEXTSONG, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_ENTER, /* Labeled START with a green * MS windows logo on remote */ [ 0x15 ] = KEY_VOLUMEUP, @@ -1825,29 +1826,20 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x11 ] = KEY_CHANNELUP, [ 0x09 ] = KEY_CHANNELDOWN, - /* The following are not defined in kernel 2.6 and - * I cannot find suitable substitute key definitions. - - [ 0x52 ] = KEY_PHOTO, - [ 0x5a ] = KEY_LIVE, - [ 0x19 ] = KEY_FOLDER, - - */ - - [ 0x52 ] = KEY_RESERVED, - [ 0x5a ] = KEY_RESERVED, - [ 0x19 ] = KEY_RESERVED, + [ 0x52 ] = KEY_CAMERA, + [ 0x5a ] = KEY_TUNER, + [ 0x19 ] = KEY_OPEN, [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ [ 0x1f ] = KEY_ZOOM, [ 0x43 ] = KEY_REWIND, [ 0x47 ] = KEY_PLAYPAUSE, - [ 0x4f ] = KEY_FORWARD, + [ 0x4f ] = KEY_FASTFORWARD, [ 0x57 ] = KEY_MUTE, [ 0x0d ] = KEY_STOP, [ 0x01 ] = KEY_RECORD, [ 0x4e ] = KEY_POWER, }; -EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); +EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 3d5a28c2c929..04f6eb5ea292 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -143,7 +143,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[4]; @@ -154,7 +154,7 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) } if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) - dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); /* no key pressed or signal from other ir remote */ @@ -165,10 +165,8 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) *ir_raw = (buf[2] << 8) | buf[3]; return 1; - } - static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -392,10 +390,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_codes = ir_codes_empty; break; case 0x6b: - name = "FusionGold"; - ir->get_key = get_key_fusion_gold; + name = "FusionHDTV"; + ir->get_key = get_key_fusionhdtv; ir_type = IR_TYPE_RC5; - ir_codes = ir_codes_fusion_gold; + ir_codes = ir_codes_fusionhdtv_mce; break; case 0x7a: case 0x47: diff --git a/include/media/ir-common.h b/include/media/ir-common.h index dfae84038e2d..7a785fa77212 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,7 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; -extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; #endif -- cgit v1.2.3 From 098c645e39e10dc580763b5ea4bd4fb390013474 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:38 -0300 Subject: V4L/DVB (6216): V4L: Int if: add vidioc_int_g_ifparm, other updates vidioc_int_g_ifparm can be used to obtain hardware-specific information about the interface used by the slave. Rearrange v4l2-int-device.h as well. Also remove useless & characters. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 4 +- include/media/v4l2-int-device.h | 130 ++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index a643730fa3b2..7ad8700ebdea 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -150,7 +150,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { return ((v4l2_int_ioctl_func_0 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); + (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); } static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) @@ -162,5 +162,5 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { return ((v4l2_int_ioctl_func_1 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); + (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index deb28ce6685d..861978deb3bf 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -30,11 +30,84 @@ #define V4L2NAMESIZE 32 +/* + * + * The internal V4L2 device interface core. + * + */ + enum v4l2_int_type { v4l2_int_type_master = 1, v4l2_int_type_slave }; +struct v4l2_int_device; + +struct v4l2_int_master { + int (*attach)(struct v4l2_int_device *master, + struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *master); +}; + +typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); + +struct v4l2_int_ioctl_desc { + int num; + v4l2_int_ioctl_func *func; +}; + +struct v4l2_int_slave { + /* Don't touch master. */ + struct v4l2_int_device *master; + + char attach_to[V4L2NAMESIZE]; + + int num_ioctls; + struct v4l2_int_ioctl_desc *ioctls; +}; + +struct v4l2_int_device { + /* Don't touch head. */ + struct list_head head; + + struct module *module; + + char name[V4L2NAMESIZE]; + + enum v4l2_int_type type; + union { + struct v4l2_int_master *master; + struct v4l2_int_slave *slave; + } u; + + void *priv; +}; + +int v4l2_int_device_register(struct v4l2_int_device *d); +void v4l2_int_device_unregister(struct v4l2_int_device *d); + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); + +/* + * + * Types and definitions for IOCTL commands. + * + */ + +/* Slave interface type. */ +enum v4l2_if_type { +}; + +struct v4l2_ifparm { + enum v4l2_if_type if_type; + union { + } u; +}; + +/* IOCTL command numbers. */ enum v4l2_int_ioctl_num { /* * @@ -62,10 +135,12 @@ enum v4l2_int_ioctl_num { vidioc_int_dev_exit_num, /* Set device power state: 0 is off, non-zero is on. */ vidioc_int_s_power_num, - /* Get parallel interface clock speed for current settings. */ + /* Get slave interface parameters. */ + vidioc_int_g_ifparm_num, + /* Get external clock speed for current slave settings. */ vidioc_int_g_ext_clk_num, /* - * Tell what the parallel interface clock speed actually is. + * Tell what the generated interface clock speed actually is. */ vidioc_int_s_ext_clk_num, /* Does the slave need to be reset after VIDIOC_DQBUF? */ @@ -91,56 +166,6 @@ enum v4l2_int_ioctl_num { vidioc_int_priv_start_num = 2000, }; -struct v4l2_int_device; - -struct v4l2_int_master { - int (*attach)(struct v4l2_int_device *master, - struct v4l2_int_device *slave); - void (*detach)(struct v4l2_int_device *master); -}; - -typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); -typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); -typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); - -struct v4l2_int_ioctl_desc { - int num; - v4l2_int_ioctl_func *func; -}; - -struct v4l2_int_slave { - /* Don't touch master. */ - struct v4l2_int_device *master; - - char attach_to[V4L2NAMESIZE]; - - int num_ioctls; - struct v4l2_int_ioctl_desc *ioctls; -}; - -struct v4l2_int_device { - /* Don't touch head. */ - struct list_head head; - - struct module *module; - - char name[V4L2NAMESIZE]; - - enum v4l2_int_type type; - union { - struct v4l2_int_master *master; - struct v4l2_int_slave *slave; - } u; - - void *priv; -}; - -int v4l2_int_device_register(struct v4l2_int_device *d); -void v4l2_int_device_unregister(struct v4l2_int_device *d); - -int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); -int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); - /* * * IOCTL wrapper functions for better type checking. @@ -199,6 +224,7 @@ V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); V4L2_INT_WRAPPER_1(g_needs_reset, void, *); -- cgit v1.2.3 From 08256ea0da18db20f2edc2e8c935cf74c33ad564 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:39 -0300 Subject: V4L/DVB (6217): V4L: Int if: Add BT.656 interface support This patch adds BT.656 interface settings for [gs]_ifparm. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-int-device.h | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'include') diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 861978deb3bf..4e07707bd5ea 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -99,11 +99,61 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); /* Slave interface type. */ enum v4l2_if_type { + /* + * Parallel 8-, 10- or 12-bit interface, used by for example + * on certain image sensors. + */ + V4L2_IF_TYPE_BT656, +}; + +enum v4l2_if_type_bt656_mode { + /* + * Modes without Bt synchronisation codes. Separate + * synchronisation signal lines are used. + */ + V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT, + /* + * Use Bt synchronisation codes. The vertical and horizontal + * synchronisation is done based on synchronisation codes. + */ + V4L2_IF_TYPE_BT656_MODE_BT_8BIT, + V4L2_IF_TYPE_BT656_MODE_BT_10BIT, +}; + +struct v4l2_if_type_bt656 { + /* + * 0: Frame begins when vsync is high. + * 1: Frame begins when vsync changes from low to high. + */ + unsigned frame_start_on_rising_vs:1; + /* Use Bt synchronisation codes for sync correction. */ + unsigned bt_sync_correct:1; + /* Swap every two adjacent image data elements. */ + unsigned swap:1; + /* Inverted latch clock polarity from slave. */ + unsigned latch_clk_inv:1; + /* Hs polarity. 0 is active high, 1 active low. */ + unsigned nobt_hs_inv:1; + /* Vs polarity. 0 is active high, 1 active low. */ + unsigned nobt_vs_inv:1; + enum v4l2_if_type_bt656_mode mode; + /* Minimum accepted bus clock for slave (in Hz). */ + u32 clock_min; + /* Maximum accepted bus clock for slave. */ + u32 clock_max; + /* + * Current wish of the slave. May only change in response to + * ioctls that affect image capture. + */ + u32 clock_curr; }; struct v4l2_ifparm { enum v4l2_if_type if_type; union { + struct v4l2_if_type_bt656 bt656; } u; }; -- cgit v1.2.3 From 768f4bd3d6a88c13a4099451aa85ae75c9061316 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:41 -0300 Subject: V4L/DVB (6219): V4L: Int if: Remove [gs]_ext_clk Remove support for g_ext_clk and s_ext_clk. The same functionality is now handled by g_ifparm. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-int-device.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'include') diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 4e07707bd5ea..066ebfc4f983 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -187,12 +187,6 @@ enum v4l2_int_ioctl_num { vidioc_int_s_power_num, /* Get slave interface parameters. */ vidioc_int_g_ifparm_num, - /* Get external clock speed for current slave settings. */ - vidioc_int_g_ext_clk_num, - /* - * Tell what the generated interface clock speed actually is. - */ - vidioc_int_s_ext_clk_num, /* Does the slave need to be reset after VIDIOC_DQBUF? */ vidioc_int_g_needs_reset_num, @@ -275,8 +269,6 @@ V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); V4L2_INT_WRAPPER_1(s_power, int, ); V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); -V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); -V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); V4L2_INT_WRAPPER_1(g_needs_reset, void, *); V4L2_INT_WRAPPER_0(reset); -- cgit v1.2.3 From 7a7d9a89d0307b1743d782197e2c5fc5ddf183f3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:26:14 -0300 Subject: V4L/DVB (6251): Replace video-buf to a more generic approach video-buf currently does two different tasks: - Manages video buffers with a common code that allows implementing all the V4L2 different modes of buffering; - Controls memory allocations While the first task is generic, the second were written to support PCI DMA Scatter/Gather needs. The original approach can't even work for those video capture hardware that don't support scatter/gather. I did one approach to make it more generic. While the approach worked fine for vivi driver, it were not generic enough to handle USB needs. This patch creates two different modules, one containing the generic video buffer handling (videobuf-core) and another with PCI DMA S/G. After this patch, it would be simpler to write an USB video-buf and a non-SG DMA module. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 976 ++++++++++++++++++++++++++++++++++ drivers/media/video/videobuf-dma-sg.c | 772 +++++++++++++++++++++++++++ include/media/videobuf-core.h | 236 ++++++++ include/media/videobuf-dma-sg.h | 142 +++++ 4 files changed, 2126 insertions(+) create mode 100644 drivers/media/video/videobuf-core.c create mode 100644 drivers/media/video/videobuf-dma-sg.c create mode 100644 include/media/videobuf-core.h create mode 100644 include/media/videobuf-dma-sg.h (limited to 'include') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c new file mode 100644 index 000000000000..256501384af7 --- /dev/null +++ b/drivers/media/video/videobuf-core.c @@ -0,0 +1,976 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_BUFFER 0x20070728 +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +#define CALL(q, f, arg...) \ + ( (q->int_ops->f)? q->int_ops->f(arg) : 0) + +void* videobuf_alloc(struct videobuf_queue* q) +{ + struct videobuf_buffer *vb; + + BUG_ON (q->msizeint_ops || !q->int_ops->alloc) { + printk(KERN_ERR "No specific ops defined!\n"); + BUG(); + } + + vb = q->int_ops->alloc(q->msize); + + if (NULL != vb) { + init_waitqueue_head(&vb->done); + vb->magic = MAGIC_BUFFER; + } + + return vb; +} + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) +{ + int retval = 0; + DECLARE_WAITQUEUE(wait, current); + + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + add_wait_queue(&vb->done, &wait); + while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { + if (non_blocking) { + retval = -EAGAIN; + break; + } + set_current_state(intr ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE); + if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) + schedule(); + set_current_state(TASK_RUNNING); + if (intr && signal_pending(current)) { + dprintk(1,"buffer waiton: -EINTR\n"); + retval = -EINTR; + break; + } + } + remove_wait_queue(&vb->done, &wait); + return retval; +} + +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + return CALL(q,iolock,q,vb,fbuf); +} + +/* --------------------------------------------------------------------- */ + + +void videobuf_queue_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + memset(q,0,sizeof(*q)); + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; + q->priv_data = priv; + + /* All buffer operations are mandatory */ + BUG_ON (!q->ops->buf_setup); + BUG_ON (!q->ops->buf_prepare); + BUG_ON (!q->ops->buf_queue); + BUG_ON (!q->ops->buf_release); + + mutex_init(&q->lock); + INIT_LIST_HEAD(&q->stream); +} + +int videobuf_queue_is_busy(struct videobuf_queue *q) +{ + int i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + if (q->streaming) { + dprintk(1,"busy: streaming active\n"); + return 1; + } + if (q->reading) { + dprintk(1,"busy: pending read #1\n"); + return 1; + } + if (q->read_buf) { + dprintk(1,"busy: pending read #2\n"); + return 1; + } + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (CALL(q,is_mmapped,q->bufs[i])) { + dprintk(1,"busy: buffer #%d mapped\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_QUEUED) { + dprintk(1,"busy: buffer #%d queued\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_ACTIVE) { + dprintk(1,"busy: buffer #%d avtive\n",i); + return 1; + } + } + return 0; +} + +void videobuf_queue_cancel(struct videobuf_queue *q) +{ + unsigned long flags=0; + int i; + + /* remove queued buffers from list */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (q->bufs[i]->state == STATE_QUEUED) { + list_del(&q->bufs[i]->queue); + q->bufs[i]->state = STATE_ERROR; + } + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + /* free all buffers + clear queue */ + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + } + INIT_LIST_HEAD(&q->stream); +} + +/* --------------------------------------------------------------------- */ + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q) +{ + enum v4l2_field field = q->field; + + BUG_ON(V4L2_FIELD_ANY == field); + + if (V4L2_FIELD_ALTERNATE == field) { + if (V4L2_FIELD_TOP == q->last) { + field = V4L2_FIELD_BOTTOM; + q->last = V4L2_FIELD_BOTTOM; + } else { + field = V4L2_FIELD_TOP; + q->last = V4L2_FIELD_TOP; + } + } + return field; +} + +static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, + struct videobuf_buffer *vb, enum v4l2_buf_type type) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + b->index = vb->i; + b->type = type; + + b->memory = vb->memory; + switch (b->memory) { + case V4L2_MEMORY_MMAP: + b->m.offset = vb->boff; + b->length = vb->bsize; + break; + case V4L2_MEMORY_USERPTR: + b->m.userptr = vb->baddr; + b->length = vb->bsize; + break; + case V4L2_MEMORY_OVERLAY: + b->m.offset = vb->boff; + break; + } + + b->flags = 0; + if (CALL(q,is_mmapped,vb)) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + switch (vb->state) { + case STATE_PREPARED: + case STATE_QUEUED: + case STATE_ACTIVE: + b->flags |= V4L2_BUF_FLAG_QUEUED; + break; + case STATE_DONE: + case STATE_ERROR: + b->flags |= V4L2_BUF_FLAG_DONE; + break; + case STATE_NEEDS_INIT: + case STATE_IDLE: + /* nothing */ + break; + } + + if (vb->input != UNSET) { + b->flags |= V4L2_BUF_FLAG_INPUT; + b->input = vb->input; + } + + b->field = vb->field; + b->timestamp = vb->ts; + b->bytesused = vb->size; + b->sequence = vb->field_count >> 1; +} + +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req) +{ + unsigned int size,count; + int retval; + + if (req->type != q->type) { + dprintk(1,"reqbufs: queue type invalid\n"); + return -EINVAL; + } + if (req->count < 1) { + dprintk(1,"reqbufs: count invalid (%d)\n",req->count); + return -EINVAL; + } + if (req->memory != V4L2_MEMORY_MMAP && + req->memory != V4L2_MEMORY_USERPTR && + req->memory != V4L2_MEMORY_OVERLAY) { + dprintk(1,"reqbufs: memory type invalid\n"); + return -EINVAL; + } + + if (q->streaming) { + dprintk(1,"reqbufs: streaming already exists\n"); + return -EBUSY; + } + if (!list_empty(&q->stream)) { + dprintk(1,"reqbufs: stream running\n"); + return -EBUSY; + } + + mutex_lock(&q->lock); + count = req->count; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = 0; + q->ops->buf_setup(q,&count,&size); + size = PAGE_ALIGN(size); + dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", + count, size, (count*size)>>PAGE_SHIFT); + + retval = videobuf_mmap_setup(q,count,size,req->memory); + if (retval < 0) { + dprintk(1,"reqbufs: mmap setup returned %d\n",retval); + goto done; + } + + req->count = count; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) +{ + if (unlikely(b->type != q->type)) { + dprintk(1,"querybuf: Wrong type.\n"); + return -EINVAL; + } + if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { + dprintk(1,"querybuf: index out of range.\n"); + return -EINVAL; + } + if (unlikely(NULL == q->bufs[b->index])) { + dprintk(1,"querybuf: buffer is null.\n"); + return -EINVAL; + } + videobuf_status(q,b,q->bufs[b->index],q->type); + return 0; +} + +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b) +{ + struct videobuf_buffer *buf; + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"qbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"qbuf: Wrong type.\n"); + goto done; + } + if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { + dprintk(1,"qbuf: index out of range.\n"); + goto done; + } + buf = q->bufs[b->index]; + if (NULL == buf) { + dprintk(1,"qbuf: buffer is null.\n"); + goto done; + } + MAGIC_CHECK(buf->magic,MAGIC_BUFFER); + if (buf->memory != b->memory) { + dprintk(1,"qbuf: memory type is wrong.\n"); + goto done; + } + if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { + dprintk(1,"qbuf: buffer is already queued or active.\n"); + goto done; + } + + if (b->flags & V4L2_BUF_FLAG_INPUT) { + if (b->input >= q->inputs) { + dprintk(1,"qbuf: wrong input.\n"); + goto done; + } + buf->input = b->input; + } else { + buf->input = UNSET; + } + + switch (b->memory) { + case V4L2_MEMORY_MMAP: + if (0 == buf->baddr) { + dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); + goto done; + } + break; + case V4L2_MEMORY_USERPTR: + if (b->length < buf->bsize) { + dprintk(1,"qbuf: buffer length is not enough\n"); + goto done; + } + if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) + q->ops->buf_release(q,buf); + buf->baddr = b->m.userptr; + break; + case V4L2_MEMORY_OVERLAY: + buf->boff = b->m.offset; + break; + default: + dprintk(1,"qbuf: wrong memory type\n"); + goto done; + } + + dprintk(1,"qbuf: requesting next field\n"); + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,buf,field); + if (0 != retval) { + dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); + goto done; + } + + list_add_tail(&buf->stream,&q->stream); + if (q->streaming) { + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + } + dprintk(1,"qbuf: succeded\n"); + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking) +{ + struct videobuf_buffer *buf; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"dqbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"dqbuf: Wrong type.\n"); + goto done; + } + if (list_empty(&q->stream)) { + dprintk(1,"dqbuf: stream running\n"); + goto done; + } + buf = list_entry(q->stream.next, struct videobuf_buffer, stream); + retval = videobuf_waiton(buf, nonblocking, 1); + if (retval < 0) { + dprintk(1,"dqbuf: waiton returned %d\n",retval); + goto done; + } + switch (buf->state) { + case STATE_ERROR: + dprintk(1,"dqbuf: state is error\n"); + retval = -EIO; + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + case STATE_DONE: + dprintk(1,"dqbuf: state is done\n"); + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + default: + dprintk(1,"dqbuf: state invalid\n"); + retval = -EINVAL; + goto done; + } + list_del(&buf->stream); + memset(b,0,sizeof(*b)); + videobuf_status(q,b,buf,q->type); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamon(struct videobuf_queue *q) +{ + struct videobuf_buffer *buf; + struct list_head *list; + unsigned long flags=0; + int retval; + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) + goto done; + retval = 0; + if (q->streaming) + goto done; + q->streaming = 1; + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + list_for_each(list,&q->stream) { + buf = list_entry(list, struct videobuf_buffer, stream); + if (buf->state == STATE_PREPARED) + q->ops->buf_queue(q,buf); + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamoff(struct videobuf_queue *q) +{ + int retval = -EINVAL; + + mutex_lock(&q->lock); + if (!q->streaming) + goto done; + videobuf_queue_cancel(q); + q->streaming = 0; + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, + char __user *data, + size_t count, loff_t *ppos) +{ + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + /* setup stuff */ + q->read_buf = videobuf_alloc(q); + if (NULL == q->read_buf) + return -ENOMEM; + + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->baddr = (unsigned long)data; + q->read_buf->bsize = count; + + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + if (0 != retval) + goto done; + + /* start capture & wait */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + retval = videobuf_waiton(q->read_buf,0,0); + if (0 == retval) { + CALL(q,sync,q,q->read_buf); + if (STATE_ERROR == q->read_buf->state) + retval = -EIO; + else + retval = q->read_buf->size; + } + + done: + /* cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + return retval; +} + +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking) +{ + enum v4l2_field field; + unsigned long flags=0; + unsigned size, nbufs; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + + nbufs = 1; size = 0; + q->ops->buf_setup(q,&nbufs,&size); + + if (NULL == q->read_buf && + count >= size && + !nonblocking) { + retval = videobuf_read_zerocopy(q,data,count,ppos); + if (retval >= 0 || retval == -EIO) + /* ok, all done */ + goto done; + /* fallback to kernel bounce buffer on failures */ + } + + if (NULL == q->read_buf) { + /* need to capture a new frame */ + retval = -ENOMEM; + q->read_buf = videobuf_alloc(q); + + dprintk(1,"video alloc=0x%p\n", q->read_buf); + if (NULL == q->read_buf) + goto done; + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->bsize = count; /* preferred size */ + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + + if (0 != retval) { + kfree (q->read_buf); + q->read_buf = NULL; + goto done; + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_off = 0; + } + + /* wait until capture is done */ + retval = videobuf_waiton(q->read_buf, nonblocking, 1); + if (0 != retval) + goto done; + + CALL(q,sync,q,q->read_buf); + + if (STATE_ERROR == q->read_buf->state) { + /* catch I/O errors */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + retval = -EIO; + goto done; + } + + /* Copy to userspace */ + retval=CALL(q,copy_to_user,q,data,count,nonblocking); + if (retval<0) + goto done; + + q->read_off += retval; + if (q->read_off == q->read_buf->size) { + /* all data copied, cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_read_start(struct videobuf_queue *q) +{ + enum v4l2_field field; + unsigned long flags=0; + int count = 0, size = 0; + int err, i; + + q->ops->buf_setup(q,&count,&size); + if (count < 2) + count = 2; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = PAGE_ALIGN(size); + + err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); + if (err) + return err; + + for (i = 0; i < count; i++) { + field = videobuf_next_field(q); + err = q->ops->buf_prepare(q,q->bufs[i],field); + if (err) + return err; + list_add_tail(&q->bufs[i]->stream, &q->stream); + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < count; i++) + q->ops->buf_queue(q,q->bufs[i]); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->reading = 1; + return 0; +} + +void videobuf_read_stop(struct videobuf_queue *q) +{ + int i; + + videobuf_queue_cancel(q); + videobuf_mmap_free(q); + INIT_LIST_HEAD(&q->stream); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + q->read_buf = NULL; + q->reading = 0; +} + +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking) +{ + int rc, retval; + unsigned long flags=0; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + dprintk(2,"%s\n",__FUNCTION__); + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->streaming) + goto done; + if (!q->reading) { + retval = videobuf_read_start(q); + if (retval < 0) + goto done; + } + + retval = 0; + while (count > 0) { + /* get / wait for data */ + if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + rc = videobuf_waiton(q->read_buf, nonblocking, 1); + if (rc < 0) { + if (0 == retval) + retval = rc; + break; + } + + if (q->read_buf->state == STATE_DONE) { + rc = CALL (q,copy_stream, q, data, count, + retval, vbihack, nonblocking); + if (rc < 0) { + retval = rc; + break; + } + retval += rc; + count -= rc; + q->read_off += rc; + } else { + /* some error */ + q->read_off = q->read_buf->size; + if (0 == retval) + retval = -EIO; + } + + /* requeue buffer when done with copying */ + if (q->read_off == q->read_buf->size) { + list_add_tail(&q->read_buf->stream, + &q->stream); + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_buf = NULL; + } + if (retval < 0) + break; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait) +{ + struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; + + mutex_lock(&q->lock); + if (q->streaming) { + if (!list_empty(&q->stream)) + buf = list_entry(q->stream.next, + struct videobuf_buffer, stream); + } else { + if (!q->reading) + videobuf_read_start(q); + if (!q->reading) { + rc = POLLERR; + } else if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + buf = q->read_buf; + } + if (!buf) + rc = POLLERR; + + if (0 == rc) { + poll_wait(file, &buf->done, wait); + if (buf->state == STATE_DONE || + buf->state == STATE_ERROR) + rc = POLLIN|POLLRDNORM; + } + mutex_unlock(&q->lock); + return rc; +} + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory) +{ + unsigned int i; + int err; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + err = videobuf_mmap_free(q); + if (0 != err) + return err; + + /* Allocate and initialize buffers */ + for (i = 0; i < bcount; i++) { + q->bufs[i] = videobuf_alloc(q); + + q->bufs[i]->i = i; + q->bufs[i]->input = UNSET; + q->bufs[i]->memory = memory; + q->bufs[i]->bsize = bsize; + switch (memory) { + case V4L2_MEMORY_MMAP: + q->bufs[i]->boff = bsize * i; + break; + case V4L2_MEMORY_USERPTR: + case V4L2_MEMORY_OVERLAY: + /* nothing */ + break; + } + } + + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + bcount,bsize); + + return 0; +} + +int videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + int rc; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + rc = CALL(q,mmap_free,q); + if (rc<0) + return rc; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + + return rc; +} + +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval=CALL(q,mmap_mapper,q,vma); + mutex_unlock(&q->lock); + + return retval; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count) +{ + struct v4l2_requestbuffers req; + int rc,i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + memset(&req,0,sizeof(req)); + req.type = q->type; + req.count = count; + req.memory = V4L2_MEMORY_MMAP; + rc = videobuf_reqbufs(q,&req); + if (rc < 0) + return rc; + + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_waiton); +EXPORT_SYMBOL_GPL(videobuf_iolock); + +EXPORT_SYMBOL_GPL(videobuf_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_cancel); +EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); + +EXPORT_SYMBOL_GPL(videobuf_next_field); +EXPORT_SYMBOL_GPL(videobuf_reqbufs); +EXPORT_SYMBOL_GPL(videobuf_querybuf); +EXPORT_SYMBOL_GPL(videobuf_qbuf); +EXPORT_SYMBOL_GPL(videobuf_dqbuf); +EXPORT_SYMBOL_GPL(videobuf_cgmbuf); +EXPORT_SYMBOL_GPL(videobuf_streamon); +EXPORT_SYMBOL_GPL(videobuf_streamoff); + +EXPORT_SYMBOL_GPL(videobuf_read_start); +EXPORT_SYMBOL_GPL(videobuf_read_stop); +EXPORT_SYMBOL_GPL(videobuf_read_stream); +EXPORT_SYMBOL_GPL(videobuf_read_one); +EXPORT_SYMBOL_GPL(videobuf_poll_stream); + +EXPORT_SYMBOL_GPL(videobuf_mmap_setup); +EXPORT_SYMBOL_GPL(videobuf_mmap_free); +EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c new file mode 100644 index 000000000000..3345877c47d4 --- /dev/null +++ b/drivers/media/video/videobuf-dma-sg.c @@ -0,0 +1,772 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x19721112 +#define MAGIC_SG_MEM 0x17890714 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +struct scatterlist* +videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) +{ + struct scatterlist *sglist; + struct page *pg; + int i; + + sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { + pg = vmalloc_to_page(virt); + if (NULL == pg) + goto err; + BUG_ON(PageHighMem(pg)); + sglist[i].page = pg; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + err: + kfree(sglist); + return NULL; +} + +struct scatterlist* +videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) +{ + struct scatterlist *sglist; + int i = 0; + + if (NULL == pages[0]) + return NULL; + sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + + if (NULL == pages[0]) + goto nopage; + if (PageHighMem(pages[0])) + /* DMA to highmem pages might not work */ + goto highmem; + sglist[0].page = pages[0]; + sglist[0].offset = offset; + sglist[0].length = PAGE_SIZE - offset; + for (i = 1; i < nr_pages; i++) { + if (NULL == pages[i]) + goto nopage; + if (PageHighMem(pages[i])) + goto highmem; + sglist[i].page = pages[i]; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + nopage: + dprintk(2,"sgl: oops - no page\n"); + kfree(sglist); + return NULL; + + highmem: + dprintk(2,"sgl: oops - highmem page\n"); + kfree(sglist); + return NULL; +} + +/* --------------------------------------------------------------------- */ + +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return &mem->dma; +} + +void videobuf_dma_init(struct videobuf_dmabuf *dma) +{ + memset(dma,0,sizeof(*dma)); + dma->magic = MAGIC_DMABUF; +} + +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size) +{ + unsigned long first,last; + int err, rw = 0; + + dma->direction = direction; + switch (dma->direction) { + case PCI_DMA_FROMDEVICE: rw = READ; break; + case PCI_DMA_TODEVICE: rw = WRITE; break; + default: BUG(); + } + + first = (data & PAGE_MASK) >> PAGE_SHIFT; + last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; + dma->offset = data & ~PAGE_MASK; + dma->nr_pages = last-first+1; + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), + GFP_KERNEL); + if (NULL == dma->pages) + return -ENOMEM; + dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", + data,size,dma->nr_pages); + + dma->varea = (void *) data; + + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, + data & PAGE_MASK, dma->nr_pages, + rw == READ, 1, /* force */ + dma->pages, NULL); + up_read(¤t->mm->mmap_sem); + if (err != dma->nr_pages) { + dma->nr_pages = (err >= 0) ? err : 0; + dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); + return err < 0 ? err : -EINVAL; + } + return 0; +} + +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages) +{ + dprintk(1,"init kernel [%d pages]\n",nr_pages); + dma->direction = direction; + dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == dma->vmalloc) { + dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); + return -ENOMEM; + } + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)dma->vmalloc, + nr_pages << PAGE_SHIFT); + memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages) +{ + dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", + nr_pages,(unsigned long)addr); + dma->direction = direction; + if (0 == addr) + return -EINVAL; + + dma->bus_addr = addr; + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(0 == dma->nr_pages); + + if (dma->pages) { + dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, + dma->offset); + } + if (dma->vmalloc) { + dma->sglist = videobuf_vmalloc_to_sg + (dma->vmalloc,dma->nr_pages); + } + if (dma->bus_addr) { + dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + if (NULL != dma->sglist) { + dma->sglen = 1; + sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; + dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; + sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; + } + } + if (NULL == dma->sglist) { + dprintk(1,"scatterlist is NULL\n"); + return -ENOMEM; + } + if (!dma->bus_addr) { + if (ops && ops->vb_map_sg) { + dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->nr_pages, dma->direction); + } + if (0 == dma->sglen) { + printk(KERN_WARNING + "%s: videobuf_map_sg failed\n",__FUNCTION__); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return -EIO; + } + } + return 0; +} + +int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(!dma->sglen); + + if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + + return 0; +} + +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + if (!dma->sglen) + return 0; + + if (!dma->bus_addr && ops && ops->vb_unmap_sg) + ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return 0; +} + +int videobuf_dma_free(struct videobuf_dmabuf *dma) +{ + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(dma->sglen); + + if (dma->pages) { + int i; + for (i=0; i < dma->nr_pages; i++) + page_cache_release(dma->pages[i]); + kfree(dma->pages); + dma->pages = NULL; + } + + vfree(dma->vmalloc); + dma->vmalloc = NULL; + dma->varea = NULL; + + if (dma->bus_addr) { + dma->bus_addr = 0; + } + dma->direction = PCI_DMA_NONE; + return 0; +} + +/* --------------------------------------------------------------------- */ + +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_map(&q,dma)); +} + +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_unmap(&q,dma)); +} + +/* --------------------------------------------------------------------- */ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_pci_sg_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +/* + * Get a anonymous page for the mapping. Make sure we can DMA to that + * memory location with 32bit PCI devices (i.e. don't use highmem for + * now ...). Bounce buffers don't work very well for the data rates + * video capture has. + */ +static struct page* +videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, + int *type) +{ + struct page *page; + + dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", + vaddr,vma->vm_start,vma->vm_end); + if (vaddr > vma->vm_end) + return NOPAGE_SIGBUS; + page = alloc_page(GFP_USER | __GFP_DMA32); + if (!page) + return NOPAGE_OOM; + clear_user_page(page_address(page), vaddr, page); + if (type) + *type = VM_FAULT_MINOR; + return page; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, + .nopage = videobuf_vm_nopage, +}; + +/* --------------------------------------------------------------------- + * PCI handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_SG_MEM; + + videobuf_dma_init(&mem->dma); + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int err,pages; + dma_addr_t bus; + struct videbuf_pci_sg_memory *mem=vb->priv; + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_USERPTR: + if (0 == vb->baddr) { + /* no userspace addr -- kernel bounce buffer */ + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_kernel( &mem->dma, + PCI_DMA_FROMDEVICE, + pages ); + if (0 != err) + return err; + } else { + /* dma directly to userspace */ + err = videobuf_dma_init_user( &mem->dma, + PCI_DMA_FROMDEVICE, + vb->baddr,vb->bsize ); + if (0 != err) + return err; + } + break; + case V4L2_MEMORY_OVERLAY: + if (NULL == fbuf) + return -EINVAL; + /* FIXME: need sanity checks for vb->boff */ + /* + * Using a double cast to avoid compiler warnings when + * building for PAE. Compiler doesn't like direct casting + * of a 32 bit ptr to 64 bit integer. + */ + bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE, + bus, pages); + if (0 != err) + return err; + break; + default: + BUG(); + } + err = videobuf_dma_map(q,&mem->dma); + if (0 != err) + return err; + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return videobuf_dma_sync(q,&mem->dma); +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_mapping *map; + unsigned int first,last,size,i; + int retval; + + retval = -EINVAL; + if (!(vma->vm_flags & VM_WRITE)) { + dprintk(1,"mmap app bug: PROT_WRITE please\n"); + goto done; + } + if (!(vma->vm_flags & VM_SHARED)) { + dprintk(1,"mmap app bug: MAP_SHARED please\n"); + goto done; + } + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + goto done; + } + + /* look for last buffer to map */ + for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { + if (NULL == q->bufs[last]) + continue; + if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) + continue; + mem=q->bufs[last]->priv; + if (mem->map) { + retval = -EBUSY; + goto done; + } + size += q->bufs[last]->bsize; + if (size == (vma->vm_end - vma->vm_start)) + break; + } + if (VIDEO_MAX_FRAME == last) { + dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", + (vma->vm_end - vma->vm_start)); + goto done; + } + + /* create mapping + update buffer list */ + retval = -ENOMEM; + map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + goto done; + for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { + mem=q->bufs[i]->priv; + mem->map = map; + q->bufs[i]->baddr = vma->vm_start + size; + } + map->count = 1; + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ + vma->vm_private_data = map; + dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", + map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); + retval = 0; + + done: + return retval; +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->dma.vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops pci_ops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void *videobuf_pci_alloc (size_t size) +{ + struct videobuf_queue q; + + /* Required to make generic handler to call __videobuf_alloc */ + q.int_ops=&pci_ops; + + q.msize=size; + + return videobuf_alloc (&q); +} + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + struct videobuf_dma_sg_ops *priv_ops; + + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&pci_ops; + + /* FIXME: the code bellow should be removed after having a proper + * memory allocation method for vivi and tm6000 + */ + q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); + BUG_ON (!q->priv_ops); + + priv_ops=q->priv_ops; + + /* Sets default methods for handling Scatter Gather mapping */ + priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; +} + +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops) +{ + kfree (q->priv_ops); + + q->priv_ops=ops; + + if (!ops) + return; + + /* If not specified, defaults to PCI map sg */ + if (!ops->vb_map_sg) + ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + + if (!ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; + if (!ops->vb_unmap_sg) + ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; +} + + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); + +EXPORT_SYMBOL_GPL(videobuf_to_dma); +EXPORT_SYMBOL_GPL(videobuf_dma_init); +EXPORT_SYMBOL_GPL(videobuf_dma_init_user); +EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); +EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); +EXPORT_SYMBOL_GPL(videobuf_dma_map); +EXPORT_SYMBOL_GPL(videobuf_dma_sync); +EXPORT_SYMBOL_GPL(videobuf_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_dma_free); + +EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); +EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_pci_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); +EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h new file mode 100644 index 000000000000..0ac21ae44f69 --- /dev/null +++ b/include/media/videobuf-core.h @@ -0,0 +1,236 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include +#ifdef CONFIG_VIDEO_V4L1_COMPAT +#include +#endif +#include + +#define UNSET (-1U) + + +struct videobuf_buffer; +struct videobuf_queue; + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage video4linux buffers. + * + * struct videobuf_buffer holds the data structures used by the helper + * functions, additionally some commonly used fields for v4l buffers + * (width, height, lists, waitqueue) are in there. That struct should + * be used as first element in the drivers buffer struct. + * + * about the mmap helpers (videobuf_mmap_*): + * + * The mmaper function allows to map any subset of contingous buffers. + * This includes one mmap() call for all buffers (which the original + * video4linux API uses) as well as one mmap() for every single buffer + * (which v4l2 uses). + * + * If there is a valid mapping for a buffer, buffer->baddr/bsize holds + * userspace address + size which can be feeded into the + * videobuf_dma_init_user function listed above. + * + */ + +struct videobuf_mapping { + unsigned int count; + unsigned long start; + unsigned long end; + struct videobuf_queue *q; +}; + +enum videobuf_state { + STATE_NEEDS_INIT = 0, + STATE_PREPARED = 1, + STATE_QUEUED = 2, + STATE_ACTIVE = 3, + STATE_DONE = 4, + STATE_ERROR = 5, + STATE_IDLE = 6, +}; + +struct videobuf_buffer { + unsigned int i; + u32 magic; + + /* info about the buffer */ + unsigned int width; + unsigned int height; + unsigned int bytesperline; /* use only if != 0 */ + unsigned long size; + unsigned int input; + enum v4l2_field field; + enum videobuf_state state; + struct list_head stream; /* QBUF/DQBUF list */ + + /* touched by irq handler */ + struct list_head queue; + wait_queue_head_t done; + unsigned int field_count; + struct timeval ts; + + /* Memory type */ + enum v4l2_memory memory; + + /* buffer size */ + size_t bsize; + + /* buffer offset (mmap + overlay) */ + size_t boff; + + /* buffer addr (userland ptr!) */ + unsigned long baddr; + + /* Private pointer to allow specific methods to store their data */ + int privsize; + void *priv; +}; + +struct videobuf_queue_ops { + int (*buf_setup)(struct videobuf_queue *q, + unsigned int *count, unsigned int *size); + int (*buf_prepare)(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field); + void (*buf_queue)(struct videobuf_queue *q, + struct videobuf_buffer *vb); + void (*buf_release)(struct videobuf_queue *q, + struct videobuf_buffer *vb); +}; + +#define MAGIC_QTYPE_OPS 0x12261003 + +/* Helper operations - device type dependent */ +struct videobuf_qtype_ops { + u32 magic; + + void* (*alloc) (size_t size); + int (*iolock) (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + int (*mmap) (struct videobuf_queue *q, + unsigned int *count, + unsigned int *size, + enum v4l2_memory memory); + int (*sync) (struct videobuf_queue* q, + struct videobuf_buffer *buf); + int (*copy_to_user) (struct videobuf_queue *q, + char __user *data, + size_t count, + int nonblocking); + int (*copy_stream) (struct videobuf_queue *q, + char __user *data, + size_t count, + size_t pos, + int vbihack, + int nonblocking); + int (*mmap_free) (struct videobuf_queue *q); + int (*mmap_mapper) (struct videobuf_queue *q, + struct vm_area_struct *vma); + int (*is_mmapped) (struct videobuf_buffer *buf); +}; + +struct videobuf_queue { + struct mutex lock; + spinlock_t *irqlock; + void *dev; /* on pci, points to struct pci_dev */ + + enum v4l2_buf_type type; + unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ + unsigned int msize; + enum v4l2_field field; + enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ + struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; + struct videobuf_queue_ops *ops; + struct videobuf_qtype_ops *int_ops; + + /* capture via mmap() + ioctl(QBUF/DQBUF) */ + unsigned int streaming; + struct list_head stream; + + /* capture via read() */ + unsigned int reading; + unsigned int read_off; + struct videobuf_buffer *read_buf; + + /* driver private data */ + void *priv_data; + + /*FIXME: should be removed after completing the vb conversion */ + void *priv_ops; +}; + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + +void *videobuf_alloc(struct videobuf_queue* q); + +void videobuf_queue_init(struct videobuf_queue *q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); +int videobuf_queue_is_busy(struct videobuf_queue *q); +void videobuf_queue_cancel(struct videobuf_queue *q); + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q); +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req); +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b); +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking); +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count); +#endif +int videobuf_streamon(struct videobuf_queue *q); +int videobuf_streamoff(struct videobuf_queue *q); + +int videobuf_read_start(struct videobuf_queue *q); +void videobuf_read_stop(struct videobuf_queue *q); +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking); +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking); +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait); + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory); +int videobuf_mmap_free(struct videobuf_queue *q); +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma); + +/* --------------------------------------------------------------------- */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h new file mode 100644 index 000000000000..62a3709905f3 --- /dev/null +++ b/include/media/videobuf-dma-sg.h @@ -0,0 +1,142 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include + +/* --------------------------------------------------------------------- */ + +/* + * Return a scatterlist for some page-aligned vmalloc()'ed memory + * block (NULL on errors). Memory for the scatterlist is allocated + * using kmalloc. The caller must free the memory. + */ +struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); + +/* + * Return a scatterlist for a an array of userpages (NULL on errors). + * Memory for the scatterlist is allocated using kmalloc. The caller + * must free the memory. + */ +struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, + int offset); + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage buffers (both userland + * and kernel) for DMA. + * + * videobuf_dma_init_*() + * creates a buffer. The userland version takes a userspace + * pointer + length. The kernel version just wants the size and + * does memory allocation too using vmalloc_32(). + * + * videobuf_dma_*() + * see Documentation/DMA-mapping.txt, these functions to + * basically the same. The map function does also build a + * scatterlist for the buffer (and unmap frees it ...) + * + * videobuf_dma_free() + * no comment ... + * + */ + +struct videobuf_dmabuf { + u32 magic; + + /* for userland buffer */ + int offset; + struct page **pages; + + /* for kernel buffers */ + void *vmalloc; + + /* Stores the userspace pointer to vmalloc area */ + void *varea; + + /* for overlay buffers (pci-pci dma) */ + dma_addr_t bus_addr; + + /* common */ + struct scatterlist *sglist; + int sglen; + int nr_pages; + int direction; +}; + +struct videbuf_pci_sg_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + struct videobuf_dmabuf dma; +}; + +/* FIXME: To be removed soon */ +typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, + int direction); + +/* FIXME: To be removed soon */ +struct videobuf_dma_sg_ops +{ + vb_map_sg_t *vb_map_sg; + vb_map_sg_t *vb_dma_sync_sg; + vb_map_sg_t *vb_unmap_sg; + +}; + +void videobuf_dma_init(struct videobuf_dmabuf *dma); +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size); +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages); +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages); +int videobuf_dma_free(struct videobuf_dmabuf *dma); + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf); + +void *videobuf_pci_alloc (size_t size); + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + + /*FIXME: these variants are used only on *-alsa code, where videobuf is + * used without queue + */ +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); + +/* FIXME: temporary routine for vivi and tm6000, while lacking implementation + * of videobuf-vmalloc + */ +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops); + -- cgit v1.2.3 From c1accaa21bdef38ec0f36eaaf7ce3384fff9d0c5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:37:49 -0300 Subject: V4L/DVB (6252): Adapt drivers to use the newer videobuf modules PCI-dependent videobuf_foo methods were renamed as videobuf_pci_foo. Also, videobuf_dmabuf is now part of videobuf-dma-sg private struct. So, to access it, a subroutine call is needed. This patch renames all occurences of those function calls to be consistent with the video-buf split. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- Documentation/dvb/faq.txt | 2 +- drivers/media/Kconfig | 6 ++++- drivers/media/common/Kconfig | 2 +- drivers/media/common/saa7146_core.c | 2 +- drivers/media/common/saa7146_fops.c | 5 ++-- drivers/media/common/saa7146_vbi.c | 9 ++++--- drivers/media/common/saa7146_video.c | 9 ++++--- drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 3 ++- drivers/media/video/bt8xx/Kconfig | 2 +- drivers/media/video/bt8xx/bttv-driver.c | 17 +++++++----- drivers/media/video/bt8xx/bttv-risc.c | 35 +++++++++++++----------- drivers/media/video/bt8xx/bttv-vbi.c | 5 ++-- drivers/media/video/bt8xx/bttvp.h | 2 +- drivers/media/video/cafe_ccic.c | 2 +- drivers/media/video/cx88/Kconfig | 2 +- drivers/media/video/cx88/cx88-alsa.c | 24 ++++++++++------- drivers/media/video/cx88/cx88-blackbird.c | 2 +- drivers/media/video/cx88/cx88-core.c | 6 +++-- drivers/media/video/cx88/cx88-dvb.c | 2 +- drivers/media/video/cx88/cx88-mpeg.c | 3 ++- drivers/media/video/cx88/cx88-vbi.c | 3 ++- drivers/media/video/cx88/cx88-video.c | 38 +++++++-------------------- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/Kconfig | 2 +- drivers/media/video/saa7134/saa7134-core.c | 8 +++--- drivers/media/video/saa7134/saa7134-dvb.c | 2 +- drivers/media/video/saa7134/saa7134-empress.c | 2 +- drivers/media/video/saa7134/saa7134-ts.c | 6 +++-- drivers/media/video/saa7134/saa7134-vbi.c | 6 +++-- drivers/media/video/saa7134/saa7134-video.c | 34 +++++------------------- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/video-buf-dvb.c | 6 +++-- include/media/saa7146_vv.h | 2 +- 34 files changed, 125 insertions(+), 130 deletions(-) (limited to 'include') diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt index dbcedf5833ee..2511a335abd6 100644 --- a/Documentation/dvb/faq.txt +++ b/Documentation/dvb/faq.txt @@ -150,7 +150,7 @@ Some very frequently asked questions about linuxtv-dvb - saa7146_vv: SAA7146 video and vbi functions. These are only needed for full-featured cards. - - video-buf: capture helper module for the saa7146_vv driver. This + - videobuf-dma-sg: capture helper module for the saa7146_vv driver. This one is responsible to handle capture buffers. - dvb-ttpci: The main driver for AV7110 based, full-featured diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 3f8cfa873de5..28ee65c53917 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -126,8 +126,12 @@ config TUNER_SIMPLE endif # VIDEO_TUNER_CUSTOMIZE -config VIDEO_BUF +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG depends on PCI + select VIDEOBUF_GEN tristate config VIDEO_BUF_DVB diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 5c63c8e24ee7..c5092ef1082f 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -5,5 +5,5 @@ config VIDEO_SAA7146 config VIDEO_SAA7146_VV tristate depends on VIDEO_DEV - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_SAA7146 diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 1c962a2b44df..365a22118a09 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -100,7 +100,7 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) * general helper functions ****************************************************************************/ -/* this is videobuf_vmalloc_to_sg() from video-buf.c +/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c make sure virt has been allocated with vmalloc_32(), otherwise the BUG() may be triggered on highmem machines */ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index b4770aecc01d..67d1b1b1b254 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -53,13 +53,14 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, struct saa7146_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); DEB_EE(("dev:%p, buf:%p\n",dev,buf)); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 063608462ebe..6103484e4442 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -165,7 +165,7 @@ static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf /* we don't wait here for the first field anymore. this is different from the video capture and might cause that the first buffer is only half filled (with only one field). but since this is some sort of streaming data, this is not that negative. - but by doing this, we can use the whole engine from video-buf.c... */ + but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ /* WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); @@ -239,6 +239,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e saa7146_dma_free(dev,q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -250,7 +252,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e err = videobuf_iolock(q,&buf->vb, NULL); if (err) goto oops; - err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen); + err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], + dma->sglist, dma->sglen); if (0 != err) return err; } @@ -404,7 +407,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) fh->vbi_fmt.start[1] = 312; fh->vbi_fmt.count[1] = 16; - videobuf_queue_init(&fh->vbi_q, &vbi_qops, + videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, // FIXME: does this really work? diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 664280c78ff2..29dbc602a484 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -594,8 +594,9 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) { struct pci_dev *pci = dev->pci; - struct scatterlist *list = buf->vb.dma.sglist; - int length = buf->vb.dma.sglen; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + struct scatterlist *list = dma->sglist; + int length = dma->sglen; struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); @@ -655,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu /* if we have a user buffer, the first page may not be aligned to a page boundary. */ - pt1->offset = buf->vb.dma.sglist->offset; + pt1->offset = list->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; @@ -1411,7 +1412,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file) sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; - videobuf_queue_init(&fh->video_q, &video_qops, + videobuf_queue_pci_init(&fh->video_q, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 5d74925748c0..c4f424422f70 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEO_BUF + select VIDEOBUF_DMA_SG default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9e99d2e1c1bd..cb300241eb89 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -87,7 +87,8 @@ obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_VIDEO_BUF) += video-buf.o +obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o +obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 58eae887a629..2ca162b390a2 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -4,7 +4,7 @@ config VIDEO_BT848 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 0711c9507843..4ab4e14b5c64 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -2582,7 +2582,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); @@ -3048,7 +3048,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mutex_lock(&fh->cap.lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); } else { @@ -3141,9 +3141,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, retval = -EIO; /* fall through */ case STATE_DONE: - videobuf_dma_sync(&fh->cap,&buf->vb.dma); + { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + videobuf_dma_sync(&fh->cap,dma); bttv_dma_free(&fh->cap,btv,buf); break; + } default: retval = -EINVAL; break; @@ -3337,7 +3340,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new); retval = bttv_switch_overlay(btv,fh,new); @@ -3696,7 +3699,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) mutex_unlock(&fh->cap.lock); return POLLERR; } - fh->cap.read_buf = videobuf_alloc(fh->cap.msize); + fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize); if (NULL == fh->cap.read_buf) { mutex_unlock(&fh->cap.lock); return POLLERR; @@ -3763,13 +3766,13 @@ static int bttv_open(struct inode *inode, struct file *file) fh->ov.setup_ok = 0; v4l2_prio_open(&btv->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &bttv_video_qops, + videobuf_queue_pci_init(&fh->cap, &bttv_video_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer), fh); - videobuf_queue_init(&fh->vbi, &bttv_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index e7104d9cb4bd..58986f1a5f1a 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -574,10 +574,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, void bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); buf->vb.state = STATE_NEEDS_INIT; @@ -699,6 +701,7 @@ int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) { const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); dprintk(KERN_DEBUG "bttv%d: buffer field: %s format: %s size: %dx%d\n", @@ -716,25 +719,25 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) switch (buf->vb.field) { case V4L2_FIELD_TOP: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, /* offset */ 0,bpl, /* padding */ 0,/* skip_lines */ 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, 0,bpl,0,0,buf->vb.height); break; case V4L2_FIELD_INTERLACED: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,bpl,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpl,bpl,bpl,0,buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,0,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpf,bpl,0,0,buf->vb.height >> 1); break; default: @@ -767,7 +770,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,/* both_fields */ 0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->top, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -776,7 +779,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->bottom, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -789,14 +792,14 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,ypadding,lines, uoffset,voffset, buf->fmt->hshift, buf->fmt->vshift, cpadding); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, ypadding,buf->vb.width,ypadding,lines, uoffset+cpadding, voffset+cpadding, @@ -812,7 +815,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,0,lines, uoffset >> 1, voffset >> 1, @@ -820,7 +823,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->fmt->vshift, 0); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, lines * ypadding,buf->vb.width,0,lines, lines * ypadding + (uoffset >> 1), lines * ypadding + (voffset >> 1), @@ -839,10 +842,10 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->vb.field = V4L2_FIELD_SEQ_TB; bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 1,tvnorm,&buf->crop); - bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->top, dma->sglist, /* offset */ 0, RAW_BPL, /* padding */ 0, /* skip_lines */ 0, RAW_LINES); - bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->bottom, dma->sglist, buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); } diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 007485aa4f01..346ce019bdcb 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -150,13 +150,14 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, if (redo_dma_risc) { unsigned int bpl, padding, offset; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); bpl = 2044; /* max. vbipack */ padding = VBI_BPL - bpl; if (fh->vbi_fmt.fmt.count[0] > 0) { rc = bttv_risc_packed(btv, &buf->top, - buf->vb.dma.sglist, + dma->sglist, /* offset */ 0, bpl, padding, skip_lines0, fh->vbi_fmt.fmt.count[0]); @@ -168,7 +169,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; rc = bttv_risc_packed(btv, &buf->bottom, - buf->vb.dma.sglist, + dma->sglist, offset, bpl, padding, skip_lines1, fh->vbi_fmt.fmt.count[1]); diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 5b25faca1504..0b92c35a8435 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ccb37006bb18..b63cab336920 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1197,7 +1197,7 @@ static int cafe_setup_siobuf(struct cafe_camera *cam, int index) buf->v4lbuf.field = V4L2_FIELD_NONE; buf->v4lbuf.memory = V4L2_MEMORY_MMAP; /* - * Offset: must be 32-bit even on a 64-bit system. video-buf + * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg * just uses the length times the index, but the spec warns * against doing just that - vma merging problems. So we * leave a gap between each pair of buffers. diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index f750a543c961..c68ba74d44ec 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -4,7 +4,7 @@ config VIDEO_CX88 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index f4abed454fd4..90c36c5705c3 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -72,7 +72,7 @@ struct cx88_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf dma_risc; + struct videobuf_dmabuf *dma_risc; struct cx88_buffer *buf; @@ -282,11 +282,12 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) BUG_ON(!chip->dma_size); dprintk(2,"Freeing buffer\n"); - videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc); - videobuf_dma_free(&chip->dma_risc); + videobuf_pci_dma_unmap(chip->pci, chip->dma_risc); + videobuf_dma_free(chip->dma_risc); btcx_riscmem_free(chip->pci,&chip->buf->risc); kfree(chip->buf); + chip->dma_risc = NULL; chip->dma_size = 0; return 0; @@ -366,6 +367,8 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, struct snd_pcm_hw_params * hw_params) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct videobuf_dmabuf *dma; + struct cx88_buffer *buf; int ret; @@ -381,7 +384,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, BUG_ON(!chip->dma_size); BUG_ON(chip->num_periods & (chip->num_periods-1)); - buf = kzalloc(sizeof(*buf), GFP_KERNEL); + buf = videobuf_pci_alloc(sizeof(*buf)); if (NULL == buf) return -ENOMEM; @@ -392,17 +395,18 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.height = chip->num_periods; buf->vb.size = chip->dma_size; - videobuf_dma_init(&buf->vb.dma); - ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE, + dma=videobuf_to_dma(&buf->vb); + videobuf_dma_init(dma); + ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + ret = videobuf_pci_dma_map(chip->pci,dma); if (ret < 0) goto error; - ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist, + ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist, buf->vb.width, buf->vb.height, 1); if (ret < 0) goto error; @@ -414,9 +418,9 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.state = STATE_PREPARED; chip->buf = buf; - chip->dma_risc = buf->vb.dma; + chip->dma_risc = dma; - substream->runtime->dma_area = chip->dma_risc.vmalloc; + substream->runtime->dma_area = chip->dma_risc->vmalloc; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; return 0; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index fcaf4f51293f..6d6f5048d762 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1111,7 +1111,7 @@ static int mpeg_open(struct inode *inode, struct file *file) file->private_data = fh; fh->dev = dev; - videobuf_queue_init(&fh->mpegq, &blackbird_qops, + videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 716154828ff0..85609b41f86e 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -213,10 +213,12 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 00d0e43785a0..d16e5c6d21c0 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -710,7 +710,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); - videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d302793fcfb9..a652f294d23d 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -237,6 +237,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, struct cx88_buffer *buf, enum v4l2_field field) { int size = dev->ts_packet_size * dev->ts_packet_count; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc; dprintk(1, "%s: %p\n", __FUNCTION__, buf); @@ -252,7 +253,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_databuffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->vb.width, buf->vb.height, 0); } buf->vb.state = STATE_PREPARED; diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 72c1d19fa79f..aa40505c4b3a 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -172,6 +172,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, return -EINVAL; if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; buf->vb.size = size; @@ -180,7 +181,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->vb.width * buf->vb.height, buf->vb.width, 0, buf->vb.height); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 705c29b002ea..1439b7268532 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -534,6 +534,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc, init_buffer = 0; BUG_ON(NULL == fh->fmt); @@ -566,30 +567,30 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, switch (buf->vb.field) { case V4L2_FIELD_TOP: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, UNSET, + dma->sglist, 0, UNSET, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, UNSET, 0, + dma->sglist, UNSET, 0, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, buf->bpl, + dma->sglist, 0, buf->bpl, buf->bpl, buf->bpl, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->bpl * (buf->vb.height >> 1), buf->bpl, 0, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_BT: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->bpl * (buf->vb.height >> 1), 0, buf->bpl, 0, buf->vb.height >> 1); @@ -752,13 +753,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 240; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - videobuf_queue_init(&fh->vidq, &cx8800_video_qops, + videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx88_buffer), fh); - videobuf_queue_init(&fh->vbiq, &cx8800_vbi_qops, + videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -1104,28 +1105,9 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv, #ifdef CONFIG_VIDEO_V4L1_COMPAT static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { - struct cx8800_fh *fh = priv; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - int err; + struct cx8800_fh *fh = priv; - q = get_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; + return videobuf_cgmbuf (get_queue(fh), mbuf, 8); } #endif diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 0e4f8e278671..875a9abab2a2 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 9f1417a4f7d2..82bc4ef414ac 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -1,7 +1,7 @@ config VIDEO_SAA7134 tristate "Philips SAA7134 support" depends on VIDEO_DEV && PCI && I2C - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select CRC32 diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 80108ddf4834..a1d986e01a30 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -236,9 +236,10 @@ int saa7134_buffer_startpage(struct saa7134_buf *buf) unsigned long saa7134_buffer_base(struct saa7134_buf *buf) { unsigned long base; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); base = saa7134_buffer_startpage(buf) * 4096; - base += buf->vb.dma.sglist[0].offset; + base += dma->sglist[0].offset; return base; } @@ -286,11 +287,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index bbab252cbeee..38d87332cc5d 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -850,7 +850,7 @@ static int dvb_init(struct saa7134_dev *dev) dev->ts.nr_bufs = 32; dev->ts.nr_packets = 32*4; dev->dvb.name = dev->name; - videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 7ed4eaf05e13..a16df57af63a 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -400,7 +400,7 @@ static int empress_init(struct saa7134_dev *dev) printk(KERN_INFO "%s: registered device video%d [mpeg]\n", dev->name,dev->empress_dev->minor & 0x1f); - videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 7780b2cce80d..5b1d1dafb5a5 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -92,6 +92,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -101,8 +103,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 0044079f5da2..81a2aedeff5c 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -137,6 +137,8 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -146,8 +148,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9c317ed6b210..cf40a9690a50 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1037,6 +1037,8 @@ static int buffer_prepare(struct videobuf_queue *q, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.size = size; @@ -1048,8 +1050,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; @@ -1309,13 +1311,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 576; v4l2_prio_open(&dev->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &video_qops, + videobuf_queue_pci_init(&fh->cap, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct saa7134_buf), fh); - videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -2137,29 +2139,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } #ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - - q = saa7134_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = gbuffers; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; - } + return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers); #endif case VIDIOC_REQBUFS: return videobuf_reqbufs(saa7134_queue(fh),arg); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index fd12942b3a10..dae608f9bf3b 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index d2af82dc8faf..9631ead297ee 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include /* ------------------------------------------------------------------ */ @@ -45,6 +45,7 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer *buf; unsigned long flags; int err; + struct videobuf_dmabuf *dma; dprintk("dvb thread started\n"); set_freezable(); @@ -65,8 +66,9 @@ static int videobuf_dvb_thread(void *data) try_to_freeze(); /* feed buffer data to demux */ + dma=videobuf_to_dma(buf); if (buf->state == STATE_DONE) - dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc, + dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); /* requeue buffer */ diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index cce20ed5cf6c..e49f7e156061 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ -- cgit v1.2.3 From 87b9ad070cf76c0f1e8cf836f7eb86e9ac94e34a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Aug 2007 23:31:33 -0300 Subject: V4L/DVB (6254): Add videobuf-vmalloc Adds a newer videobuf-vmalloc module. This module uses the same videobuf controls, but implements memory allocation based on vmalloc methods. With this method, an USB driver can use video-buf, without needing to request memory from the DMA-safe area. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 4 + drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 1 + drivers/media/video/videobuf-vmalloc.c | 384 +++++++++++++++++++++++++++++++++ include/media/videobuf-vmalloc.h | 44 ++++ 5 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 drivers/media/video/videobuf-vmalloc.c create mode 100644 include/media/videobuf-vmalloc.h (limited to 'include') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 28ee65c53917..fc3ea4c67ccb 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -134,6 +134,10 @@ config VIDEOBUF_DMA_SG select VIDEOBUF_GEN tristate +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + config VIDEO_BUF_DVB tristate diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c4f424422f70..2e571eb9313a 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEOBUF_DMA_SG + select VIDEOBUF_VMALLOC default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index cb300241eb89..c8140aec1a16 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o +obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c new file mode 100644 index 000000000000..993d5285e18e --- /dev/null +++ b/drivers/media/video/videobuf-vmalloc.c @@ -0,0 +1,384 @@ +/* + * helper functions for vmalloc video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x17760309 +#define MAGIC_VMAL_MEM 0x18221223 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + + +/***************************************************************************/ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_vmalloc_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, +}; + +/* --------------------------------------------------------------------- + * vmalloc handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_VMAL_MEM; + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int pages; + + struct videbuf_vmalloc_memory *mem=vb->priv; + + + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + + /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ + if ((vb->memory != V4L2_MEMORY_MMAP) && + (vb->memory != V4L2_MEMORY_USERPTR) ) { + printk(KERN_ERR "Method currently unsupported.\n"); + return -EINVAL; + } + + /* FIXME: should be tested with kernel mmap mem */ + mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); + if (NULL == mem->vmalloc) { + dprintk(1,"vmalloc (%d pages) failed\n",pages); + return -ENOMEM; + } + + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)mem->vmalloc, + pages << PAGE_SHIFT); + + /* It seems that some kernel versions need to do remap *after* + the mmap() call + */ + if (mem->vma) { + int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0); + kfree(mem->vma); + mem->vma=NULL; + if (retval<0) { + dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n", + mem->vmalloc,retval); + return retval; + } + } + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + return 0; +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + unsigned int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_mapping *map; + unsigned int first; + int retval; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) + return -EINVAL; + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == offset) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + return -EINVAL; + } + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + /* create mapping + update buffer list */ + map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + return -ENOMEM; + + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + + q->bufs[first]->baddr = vma->vm_start; + + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_private_data = map; + + /* Try to remap memory */ + retval=remap_vmalloc_range(vma, mem->vmalloc,0); + if (retval<0) { + dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); + if (!mem->vma) { + kfree(map); + mem->map=NULL; + return -ENOMEM; + } + memcpy(mem->vma,vma,sizeof(*vma)); + } + + dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", + map,q,vma->vm_start,vma->vm_end, + (long int) q->bufs[first]->bsize, + vma->vm_pgoff,first); + + videobuf_vm_open(vma); + + return (0); +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + BUG_ON (!mem->vmalloc); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops qops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&qops; +} + +EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return mem->vmalloc; +} +EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + vfree(mem->vmalloc); + + return; +} +EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h new file mode 100644 index 000000000000..5fff68df6689 --- /dev/null +++ b/include/media/videobuf-vmalloc.h @@ -0,0 +1,44 @@ +/* + * helper functions for vmalloc capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * 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 + */ + +#include + +/* --------------------------------------------------------------------- */ + +struct videbuf_vmalloc_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + + void *vmalloc; + + /* remap_vmalloc_range seems to need to run after mmap() on some cases */ + struct vm_area_struct *vma; +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf); -- cgit v1.2.3 From 79618cf41337ccedb9abeee059ce76aac7962739 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:31:15 -0300 Subject: V4L/DVB (6256): Remove the obsolete video-buf module Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/video-buf.c | 1424 --------------------------------------- include/media/video-buf.h | 289 -------- 2 files changed, 1713 deletions(-) delete mode 100644 drivers/media/video/video-buf.c delete mode 100644 include/media/video-buf.h (limited to 'include') diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c deleted file mode 100644 index f6f31e1773d1..000000000000 --- a/drivers/media/video/video-buf.c +++ /dev/null @@ -1,1424 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001-2004 Gerd Knorr [SUSE Labs] - * (c) 2006 Mauro Carvalho Chehab - * (c) 2006 Ted Walther and John Sokol - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAGIC_DMABUF 0x19721112 -#define MAGIC_BUFFER 0x20040302 -#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ - { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } - -static int debug = 0; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt , ## arg) - -struct scatterlist* -videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sglist[i].page = pg; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - err: - kfree(sglist); - return NULL; -} - -struct scatterlist* -videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) -{ - struct scatterlist *sglist; - int i = 0; - - if (NULL == pages[0]) - return NULL; - sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - - if (NULL == pages[0]) - goto nopage; - if (PageHighMem(pages[0])) - /* DMA to highmem pages might not work */ - goto highmem; - sglist[0].page = pages[0]; - sglist[0].offset = offset; - sglist[0].length = PAGE_SIZE - offset; - for (i = 1; i < nr_pages; i++) { - if (NULL == pages[i]) - goto nopage; - if (PageHighMem(pages[i])) - goto highmem; - sglist[i].page = pages[i]; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - nopage: - dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); - return NULL; - - highmem: - dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_dma_init(struct videobuf_dmabuf *dma) -{ - memset(dma,0,sizeof(*dma)); - dma->magic = MAGIC_DMABUF; -} - -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) -{ - unsigned long first,last; - int err, rw = 0; - - dma->direction = direction; - switch (dma->direction) { - case PCI_DMA_FROMDEVICE: rw = READ; break; - case PCI_DMA_TODEVICE: rw = WRITE; break; - default: BUG(); - } - - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma->offset = data & ~PAGE_MASK; - dma->nr_pages = last-first+1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), - GFP_KERNEL); - if (NULL == dma->pages) - return -ENOMEM; - dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", - data,size,dma->nr_pages); - - dma->varea = (void *) data; - - down_read(¤t->mm->mmap_sem); - err = get_user_pages(current,current->mm, - data & PAGE_MASK, dma->nr_pages, - rw == READ, 1, /* force */ - dma->pages, NULL); - up_read(¤t->mm->mmap_sem); - if (err != dma->nr_pages) { - dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); - return err < 0 ? err : -EINVAL; - } - return 0; -} - -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages) -{ - dprintk(1,"init kernel [%d pages]\n",nr_pages); - dma->direction = direction; - dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); - if (NULL == dma->vmalloc) { - dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); - return -ENOMEM; - } - dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vmalloc, - nr_pages << PAGE_SHIFT); - memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages) -{ - dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", - nr_pages,(unsigned long)addr); - dma->direction = direction; - if (0 == addr) - return -EINVAL; - - dma->bus_addr = addr; - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(0 == dma->nr_pages); - - if (dma->pages) { - dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, - dma->offset); - } - if (dma->vmalloc) { - dma->sglist = videobuf_vmalloc_to_sg - (dma->vmalloc,dma->nr_pages); - } - if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); - if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; - } - } - if (NULL == dma->sglist) { - dprintk(1,"scatterlist is NULL\n"); - return -ENOMEM; - } - if (!dma->bus_addr) { - if (q->ops->vb_map_sg) { - dma->sglen = q->ops->vb_map_sg(dev,dma->sglist, - dma->nr_pages, dma->direction); - } - if (0 == dma->sglen) { - printk(KERN_WARNING - "%s: videobuf_map_sg failed\n",__FUNCTION__); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return -EIO; - } - } - return 0; -} - -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(!dma->sglen); - - if (!dma->bus_addr && q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - - return 0; -} - -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - if (!dma->sglen) - return 0; - - if (!dma->bus_addr && q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return 0; -} - -int videobuf_dma_free(struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(dma->sglen); - - if (dma->pages) { - int i; - for (i=0; i < dma->nr_pages; i++) - page_cache_release(dma->pages[i]); - kfree(dma->pages); - dma->pages = NULL; - } - - vfree(dma->vmalloc); - dma->vmalloc = NULL; - dma->varea = NULL; - - if (dma->bus_addr) { - dma->bus_addr = 0; - } - dma->direction = PCI_DMA_NONE; - return 0; -} - -/* --------------------------------------------------------------------- */ - -void* videobuf_alloc(unsigned int size) -{ - struct videobuf_buffer *vb; - - vb = kzalloc(size,GFP_KERNEL); - if (NULL != vb) { - videobuf_dma_init(&vb->dma); - init_waitqueue_head(&vb->done); - vb->magic = MAGIC_BUFFER; - } - return vb; -} - -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) -{ - int retval = 0; - DECLARE_WAITQUEUE(wait, current); - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - add_wait_queue(&vb->done, &wait); - while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { - if (non_blocking) { - retval = -EAGAIN; - break; - } - set_current_state(intr ? TASK_INTERRUPTIBLE - : TASK_UNINTERRUPTIBLE); - if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) - schedule(); - set_current_state(TASK_RUNNING); - if (intr && signal_pending(current)) { - dprintk(1,"buffer waiton: -EINTR\n"); - retval = -EINTR; - break; - } - } - remove_wait_queue(&vb->done, &wait); - return retval; -} - -int -videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - int err,pages; - dma_addr_t bus; - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - if (0 == vb->baddr) { - /* no userspace addr -- kernel bounce buffer */ - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE, - pages); - if (0 != err) - return err; - } else { - /* dma directly to userspace */ - err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE, - vb->baddr,vb->bsize); - if (0 != err) - return err; - } - break; - case V4L2_MEMORY_OVERLAY: - if (NULL == fbuf) - return -EINVAL; - /* FIXME: need sanity checks for vb->boff */ - /* - * Using a double cast to avoid compiler warnings when - * building for PAE. Compiler doesn't like direct casting - * of a 32 bit ptr to 64 bit integer. - */ - bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE, - bus, pages); - if (0 != err) - return err; - break; - default: - BUG(); - } - err = videobuf_dma_map(q,&vb->dma); - if (0 != err) - return err; - - return 0; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_queue_pci(struct videobuf_queue* q) -{ - /* If not specified, defaults to PCI map sg */ - if (!q->ops->vb_map_sg) - q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_map(&q,dma)); -} - -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_unmap(&q,dma)); -} - -void videobuf_queue_init(struct videobuf_queue* q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv) -{ - memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; - q->priv_data = priv; - - videobuf_queue_pci(q); - - mutex_init(&q->lock); - INIT_LIST_HEAD(&q->stream); -} - -int -videobuf_queue_is_busy(struct videobuf_queue *q) -{ - int i; - - if (q->streaming) { - dprintk(1,"busy: streaming active\n"); - return 1; - } - if (q->reading) { - dprintk(1,"busy: pending read #1\n"); - return 1; - } - if (q->read_buf) { - dprintk(1,"busy: pending read #2\n"); - return 1; - } - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->map) { - dprintk(1,"busy: buffer #%d mapped\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_QUEUED) { - dprintk(1,"busy: buffer #%d queued\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_ACTIVE) { - dprintk(1,"busy: buffer #%d avtive\n",i); - return 1; - } - } - return 0; -} - -void -videobuf_queue_cancel(struct videobuf_queue *q) -{ - unsigned long flags=0; - int i; - - /* remove queued buffers from list */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->state == STATE_QUEUED) { - list_del(&q->bufs[i]->queue); - q->bufs[i]->state = STATE_ERROR; - } - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - /* free all buffers + clear queue */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - } - INIT_LIST_HEAD(&q->stream); -} - -/* --------------------------------------------------------------------- */ - -enum v4l2_field -videobuf_next_field(struct videobuf_queue *q) -{ - enum v4l2_field field = q->field; - - BUG_ON(V4L2_FIELD_ANY == field); - - if (V4L2_FIELD_ALTERNATE == field) { - if (V4L2_FIELD_TOP == q->last) { - field = V4L2_FIELD_BOTTOM; - q->last = V4L2_FIELD_BOTTOM; - } else { - field = V4L2_FIELD_TOP; - q->last = V4L2_FIELD_TOP; - } - } - return field; -} - -void -videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type) -{ - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - - b->index = vb->i; - b->type = type; - - b->memory = vb->memory; - switch (b->memory) { - case V4L2_MEMORY_MMAP: - b->m.offset = vb->boff; - b->length = vb->bsize; - break; - case V4L2_MEMORY_USERPTR: - b->m.userptr = vb->baddr; - b->length = vb->bsize; - break; - case V4L2_MEMORY_OVERLAY: - b->m.offset = vb->boff; - break; - } - - b->flags = 0; - if (vb->map) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (vb->state) { - case STATE_PREPARED: - case STATE_QUEUED: - case STATE_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case STATE_DONE: - case STATE_ERROR: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case STATE_NEEDS_INIT: - case STATE_IDLE: - /* nothing */ - break; - } - - if (vb->input != UNSET) { - b->flags |= V4L2_BUF_FLAG_INPUT; - b->input = vb->input; - } - - b->field = vb->field; - b->timestamp = vb->ts; - b->bytesused = vb->size; - b->sequence = vb->field_count >> 1; -} - -int -videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req) -{ - unsigned int size,count; - int retval; - - if (req->type != q->type) { - dprintk(1,"reqbufs: queue type invalid\n"); - return -EINVAL; - } - if (req->count < 1) { - dprintk(1,"reqbufs: count invalid (%d)\n",req->count); - return -EINVAL; - } - if (req->memory != V4L2_MEMORY_MMAP && - req->memory != V4L2_MEMORY_USERPTR && - req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1,"reqbufs: memory type invalid\n"); - return -EINVAL; - } - - if (q->streaming) { - dprintk(1,"reqbufs: streaming already exists\n"); - return -EBUSY; - } - if (!list_empty(&q->stream)) { - dprintk(1,"reqbufs: stream running\n"); - return -EBUSY; - } - - mutex_lock(&q->lock); - count = req->count; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = 0; - q->ops->buf_setup(q,&count,&size); - size = PAGE_ALIGN(size); - dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", - count, size, (count*size)>>PAGE_SHIFT); - - retval = videobuf_mmap_setup(q,count,size,req->memory); - if (retval < 0) { - dprintk(1,"reqbufs: mmap setup returned %d\n",retval); - goto done; - } - - req->count = count; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - if (unlikely(b->type != q->type)) { - dprintk(1,"querybuf: Wrong type.\n"); - return -EINVAL; - } - if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { - dprintk(1,"querybuf: index out of range.\n"); - return -EINVAL; - } - if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1,"querybuf: buffer is null.\n"); - return -EINVAL; - } - videobuf_status(b,q->bufs[b->index],q->type); - return 0; -} - -int -videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b) -{ - struct videobuf_buffer *buf; - enum v4l2_field field; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"qbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"qbuf: Wrong type.\n"); - goto done; - } - if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { - dprintk(1,"qbuf: index out of range.\n"); - goto done; - } - buf = q->bufs[b->index]; - if (NULL == buf) { - dprintk(1,"qbuf: buffer is null.\n"); - goto done; - } - MAGIC_CHECK(buf->magic,MAGIC_BUFFER); - if (buf->memory != b->memory) { - dprintk(1,"qbuf: memory type is wrong.\n"); - goto done; - } - if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { - dprintk(1,"qbuf: buffer is already queued or active.\n"); - goto done; - } - - if (b->flags & V4L2_BUF_FLAG_INPUT) { - if (b->input >= q->inputs) { - dprintk(1,"qbuf: wrong input.\n"); - goto done; - } - buf->input = b->input; - } else { - buf->input = UNSET; - } - - switch (b->memory) { - case V4L2_MEMORY_MMAP: - if (0 == buf->baddr) { - dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); - goto done; - } - break; - case V4L2_MEMORY_USERPTR: - if (b->length < buf->bsize) { - dprintk(1,"qbuf: buffer length is not enough\n"); - goto done; - } - if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) - q->ops->buf_release(q,buf); - buf->baddr = b->m.userptr; - break; - case V4L2_MEMORY_OVERLAY: - buf->boff = b->m.offset; - break; - default: - dprintk(1,"qbuf: wrong memory type\n"); - goto done; - } - - dprintk(1,"qbuf: requesting next field\n"); - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,buf,field); - if (0 != retval) { - dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); - goto done; - } - - list_add_tail(&buf->stream,&q->stream); - if (q->streaming) { - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - } - dprintk(1,"qbuf: succeded\n"); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking) -{ - struct videobuf_buffer *buf; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"dqbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"dqbuf: Wrong type.\n"); - goto done; - } - if (list_empty(&q->stream)) { - dprintk(1,"dqbuf: stream running\n"); - goto done; - } - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(buf, nonblocking, 1); - if (retval < 0) { - dprintk(1,"dqbuf: waiton returned %d\n",retval); - goto done; - } - switch (buf->state) { - case STATE_ERROR: - dprintk(1,"dqbuf: state is error\n"); - retval = -EIO; - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - case STATE_DONE: - dprintk(1,"dqbuf: state is done\n"); - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - default: - dprintk(1,"dqbuf: state invalid\n"); - retval = -EINVAL; - goto done; - } - list_del(&buf->stream); - memset(b,0,sizeof(*b)); - videobuf_status(b,buf,q->type); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamon(struct videobuf_queue *q) -{ - struct videobuf_buffer *buf; - struct list_head *list; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) - goto done; - retval = 0; - if (q->streaming) - goto done; - q->streaming = 1; - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - list_for_each(list,&q->stream) { - buf = list_entry(list, struct videobuf_buffer, stream); - if (buf->state == STATE_PREPARED) - q->ops->buf_queue(q,buf); - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamoff(struct videobuf_queue *q) -{ - int retval = -EINVAL; - - mutex_lock(&q->lock); - if (!q->streaming) - goto done; - videobuf_queue_cancel(q); - q->streaming = 0; - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -static ssize_t -videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, - size_t count, loff_t *ppos) -{ - enum v4l2_field field; - unsigned long flags=0; - int retval; - - /* setup stuff */ - q->read_buf = videobuf_alloc(q->msize); - if (NULL == q->read_buf) - return -ENOMEM; - - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->baddr = (unsigned long)data; - q->read_buf->bsize = count; - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) - goto done; - - /* start capture & wait */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - retval = videobuf_waiton(q->read_buf,0,0); - if (0 == retval) { - videobuf_dma_sync(q,&q->read_buf->dma); - if (STATE_ERROR == q->read_buf->state) - retval = -EIO; - else - retval = q->read_buf->size; - } - - done: - /* cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - return retval; -} - -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags=0; - unsigned size, nbufs, bytes; - int retval; - - mutex_lock(&q->lock); - - nbufs = 1; size = 0; - q->ops->buf_setup(q,&nbufs,&size); - if (NULL == q->read_buf && - count >= size && - !nonblocking) { - retval = videobuf_read_zerocopy(q,data,count,ppos); - if (retval >= 0 || retval == -EIO) - /* ok, all done */ - goto done; - /* fallback to kernel bounce buffer on failures */ - } - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc(q->msize); - dprintk(1,"video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) { - kfree (q->read_buf); - q->read_buf = NULL; - goto done; - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - videobuf_dma_sync(q,&q->read_buf->dma); - - if (STATE_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* copy to userspace */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - retval = -EFAULT; - if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes)) - goto done; - - retval = bytes; - q->read_off += bytes; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_read_start(struct videobuf_queue *q) -{ - enum v4l2_field field; - unsigned long flags=0; - int count = 0, size = 0; - int err, i; - - q->ops->buf_setup(q,&count,&size); - if (count < 2) - count = 2; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = PAGE_ALIGN(size); - - err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err) - return err; - for (i = 0; i < count; i++) { - field = videobuf_next_field(q); - err = q->ops->buf_prepare(q,q->bufs[i],field); - if (err) - return err; - list_add_tail(&q->bufs[i]->stream, &q->stream); - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < count; i++) - q->ops->buf_queue(q,q->bufs[i]); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->reading = 1; - return 0; -} - -void videobuf_read_stop(struct videobuf_queue *q) -{ - int i; - - videobuf_queue_cancel(q); - videobuf_mmap_free(q); - INIT_LIST_HEAD(&q->stream); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - q->read_buf = NULL; - q->reading = 0; -} - -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking) -{ - unsigned int *fc, bytes; - int err, retval; - unsigned long flags=0; - - dprintk(2,"%s\n",__FUNCTION__); - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->streaming) - goto done; - if (!q->reading) { - retval = videobuf_read_start(q); - if (retval < 0) - goto done; - } - - retval = 0; - while (count > 0) { - /* get / wait for data */ - if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - err = videobuf_waiton(q->read_buf, nonblocking, 1); - if (err < 0) { - if (0 == retval) - retval = err; - break; - } - - if (q->read_buf->state == STATE_DONE) { - if (vbihack) { - /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc = (unsigned int*)q->read_buf->dma.vmalloc; - fc += (q->read_buf->size>>2) -1; - *fc = q->read_buf->field_count >> 1; - dprintk(1,"vbihack: %d\n",*fc); - } - - /* copy stuff */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - if (copy_to_user(data + retval, - q->read_buf->dma.vmalloc + q->read_off, - bytes)) { - if (0 == retval) - retval = -EFAULT; - break; - } - count -= bytes; - retval += bytes; - q->read_off += bytes; - } else { - /* some error */ - q->read_off = q->read_buf->size; - if (0 == retval) - retval = -EIO; - } - - /* requeue buffer when done with copying */ - if (q->read_off == q->read_buf->size) { - list_add_tail(&q->read_buf->stream, - &q->stream); - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_buf = NULL; - } - if (retval < 0) - break; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) -{ - struct videobuf_buffer *buf = NULL; - unsigned int rc = 0; - - mutex_lock(&q->lock); - if (q->streaming) { - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); - } else { - if (!q->reading) - videobuf_read_start(q); - if (!q->reading) { - rc = POLLERR; - } else if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - buf = q->read_buf; - } - if (!buf) - rc = POLLERR; - - if (0 == rc) { - poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) - rc = POLLIN|POLLRDNORM; - } - mutex_unlock(&q->lock); - return rc; -} - -/* --------------------------------------------------------------------- */ - -static void -videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - map->count++; -} - -static void -videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - - map->count--; - if (0 == map->count) { - dprintk(1,"munmap %p q=%p\n",map,q); - mutex_lock(&q->lock); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]) - ; - if (q->bufs[i]->map != map) - continue; - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); - } - mutex_unlock(&q->lock); - kfree(map); - } - return; -} - -/* - * Get a anonymous page for the mapping. Make sure we can DMA to that - * memory location with 32bit PCI devices (i.e. don't use highmem for - * now ...). Bounce buffers don't work very well for the data rates - * video capture has. - */ -static struct page* -videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, - int *type) -{ - struct page *page; - - dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", - vaddr,vma->vm_start,vma->vm_end); - if (vaddr > vma->vm_end) - return NOPAGE_SIGBUS; - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return NOPAGE_OOM; - clear_user_page(page_address(page), vaddr, page); - if (type) - *type = VM_FAULT_MINOR; - return page; -} - -static struct vm_operations_struct videobuf_vm_ops = -{ - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .nopage = videobuf_vm_nopage, -}; - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - err = videobuf_mmap_free(q); - if (0 != err) - return err; - - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc(q->msize); - q->bufs[i]->i = i; - q->bufs[i]->input = UNSET; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = bsize * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - /* nothing */ - break; - } - } - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - bcount,bsize); - return 0; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int i; - - for (i = 0; i < VIDEO_MAX_FRAME; i++) - if (q->bufs[i] && q->bufs[i]->map) - return -EBUSY; - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - return 0; -} - -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma) -{ - struct videobuf_mapping *map; - unsigned int first,last,size,i; - int retval; - - mutex_lock(&q->lock); - retval = -EINVAL; - if (!(vma->vm_flags & VM_WRITE)) { - dprintk(1,"mmap app bug: PROT_WRITE please\n"); - goto done; - } - if (!(vma->vm_flags & VM_SHARED)) { - dprintk(1,"mmap app bug: MAP_SHARED please\n"); - goto done; - } - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (NULL == q->bufs[first]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) - continue; - if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - if (VIDEO_MAX_FRAME == first) { - dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - goto done; - } - - /* look for last buffer to map */ - for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { - if (NULL == q->bufs[last]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) - continue; - if (q->bufs[last]->map) { - retval = -EBUSY; - goto done; - } - size += q->bufs[last]->bsize; - if (size == (vma->vm_end - vma->vm_start)) - break; - } - if (VIDEO_MAX_FRAME == last) { - dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", - (vma->vm_end - vma->vm_start)); - goto done; - } - - /* create mapping + update buffer list */ - retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); - if (NULL == map) - goto done; - for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - q->bufs[i]->map = map; - q->bufs[i]->baddr = vma->vm_start + size; - } - map->count = 1; - map->start = vma->vm_start; - map->end = vma->vm_end; - map->q = q; - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ - vma->vm_private_data = map; - dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -/* --------------------------------------------------------------------- */ - -EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); - -EXPORT_SYMBOL_GPL(videobuf_dma_init); -EXPORT_SYMBOL_GPL(videobuf_dma_init_user); -EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); -EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); -EXPORT_SYMBOL_GPL(videobuf_dma_map); -EXPORT_SYMBOL_GPL(videobuf_dma_sync); -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); -EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); - -EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_waiton); -EXPORT_SYMBOL_GPL(videobuf_iolock); - -EXPORT_SYMBOL_GPL(videobuf_queue_init); -EXPORT_SYMBOL_GPL(videobuf_queue_cancel); -EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); - -EXPORT_SYMBOL_GPL(videobuf_next_field); -EXPORT_SYMBOL_GPL(videobuf_status); -EXPORT_SYMBOL_GPL(videobuf_reqbufs); -EXPORT_SYMBOL_GPL(videobuf_querybuf); -EXPORT_SYMBOL_GPL(videobuf_qbuf); -EXPORT_SYMBOL_GPL(videobuf_dqbuf); -EXPORT_SYMBOL_GPL(videobuf_streamon); -EXPORT_SYMBOL_GPL(videobuf_streamoff); - -EXPORT_SYMBOL_GPL(videobuf_read_start); -EXPORT_SYMBOL_GPL(videobuf_read_stop); -EXPORT_SYMBOL_GPL(videobuf_read_stream); -EXPORT_SYMBOL_GPL(videobuf_read_one); -EXPORT_SYMBOL_GPL(videobuf_poll_stream); - -EXPORT_SYMBOL_GPL(videobuf_mmap_setup); -EXPORT_SYMBOL_GPL(videobuf_mmap_free); -EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/include/media/video-buf.h b/include/media/video-buf.h deleted file mode 100644 index d6f079476db3..000000000000 --- a/include/media/video-buf.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as file operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * 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. - */ - -#include -#include - -#define UNSET (-1U) - -/* --------------------------------------------------------------------- */ - -/* - * Return a scatterlist for some page-aligned vmalloc()'ed memory - * block (NULL on errors). Memory for the scatterlist is allocated - * using kmalloc. The caller must free the memory. - */ -struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); - -/* - * Return a scatterlist for a an array of userpages (NULL on errors). - * Memory for the scatterlist is allocated using kmalloc. The caller - * must free the memory. - */ -struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, - int offset); - -struct videobuf_buffer; -struct videobuf_queue; - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage buffers (both userland - * and kernel) for DMA. - * - * videobuf_dma_init_*() - * creates a buffer. The userland version takes a userspace - * pointer + length. The kernel version just wants the size and - * does memory allocation too using vmalloc_32(). - * - * videobuf_dma_*() - * see Documentation/DMA-mapping.txt, these functions to - * basically the same. The map function does also build a - * scatterlist for the buffer (and unmap frees it ...) - * - * videobuf_dma_free() - * no comment ... - * - */ - -struct videobuf_dmabuf { - u32 magic; - - /* for userland buffer */ - int offset; - struct page **pages; - - /* for kernel buffers */ - void *vmalloc; - - /* Stores the userspace pointer to vmalloc area */ - void *varea; - - /* for overlay buffers (pci-pci dma) */ - dma_addr_t bus_addr; - - /* common */ - struct scatterlist *sglist; - int sglen; - int nr_pages; - int direction; -}; - -void videobuf_dma_init(struct videobuf_dmabuf *dma); -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size); -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages); -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages); -int videobuf_dma_free(struct videobuf_dmabuf *dma); - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); - - /*FIXME: these variants are used only on *-alsa code, where videobuf is - * used without queue - */ -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage video4linux buffers. - * - * struct videobuf_buffer holds the data structures used by the helper - * functions, additionally some commonly used fields for v4l buffers - * (width, height, lists, waitqueue) are in there. That struct should - * be used as first element in the drivers buffer struct. - * - * about the mmap helpers (videobuf_mmap_*): - * - * The mmaper function allows to map any subset of contingous buffers. - * This includes one mmap() call for all buffers (which the original - * video4linux API uses) as well as one mmap() for every single buffer - * (which v4l2 uses). - * - * If there is a valid mapping for a buffer, buffer->baddr/bsize holds - * userspace address + size which can be feeded into the - * videobuf_dma_init_user function listed above. - * - */ - -struct videobuf_mapping { - unsigned int count; - unsigned long start; - unsigned long end; - struct videobuf_queue *q; -}; - -enum videobuf_state { - STATE_NEEDS_INIT = 0, - STATE_PREPARED = 1, - STATE_QUEUED = 2, - STATE_ACTIVE = 3, - STATE_DONE = 4, - STATE_ERROR = 5, - STATE_IDLE = 6, -}; - -struct videobuf_buffer { - unsigned int i; - u32 magic; - - /* info about the buffer */ - unsigned int width; - unsigned int height; - unsigned int bytesperline; /* use only if != 0 */ - unsigned long size; - unsigned int input; - enum v4l2_field field; - enum videobuf_state state; - struct videobuf_dmabuf dma; - struct list_head stream; /* QBUF/DQBUF list */ - - /* for mmap'ed buffers */ - enum v4l2_memory memory; - size_t boff; /* buffer offset (mmap + overlay) */ - size_t bsize; /* buffer size */ - unsigned long baddr; /* buffer addr (userland ptr!) */ - struct videobuf_mapping *map; - - /* touched by irq handler */ - struct list_head queue; - wait_queue_head_t done; - unsigned int field_count; - struct timeval ts; -}; - -typedef int (vb_map_sg_t)(void *dev,struct scatterlist *sglist,int nr_pages, - int direction); - - -struct videobuf_queue_ops { - int (*buf_setup)(struct videobuf_queue *q, - unsigned int *count, unsigned int *size); - int (*buf_prepare)(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); - void (*buf_queue)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - void (*buf_release)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - - /* Helper operations - device dependent. - * If null, videobuf_init defaults all to PCI handling - */ - - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; -}; - -struct videobuf_queue { - struct mutex lock; - spinlock_t *irqlock; - void *dev; /* on pci, points to struct pci_dev */ - - enum v4l2_buf_type type; - unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ - unsigned int msize; - enum v4l2_field field; - enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ - struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; - struct videobuf_queue_ops *ops; - - /* capture via mmap() + ioctl(QBUF/DQBUF) */ - unsigned int streaming; - struct list_head stream; - - /* capture via read() */ - unsigned int reading; - unsigned int read_off; - struct videobuf_buffer *read_buf; - - /* driver private data */ - void *priv_data; -}; - -void* videobuf_alloc(unsigned int size); -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); -int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - -/* Maps fops to PCI stuff */ -void videobuf_queue_pci(struct videobuf_queue* q); - -void videobuf_queue_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv); -int videobuf_queue_is_busy(struct videobuf_queue *q); -void videobuf_queue_cancel(struct videobuf_queue *q); - -enum v4l2_field videobuf_next_field(struct videobuf_queue *q); -void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type); -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req); -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); -int videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b); -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking); -int videobuf_streamon(struct videobuf_queue *q); -int videobuf_streamoff(struct videobuf_queue *q); - -int videobuf_read_start(struct videobuf_queue *q); -void videobuf_read_stop(struct videobuf_queue *q); -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking); -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking); -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int videobuf_mmap_free(struct videobuf_queue *q); -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma); - -/* --------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3 From ba366a23b68029fc8560acf1ad8735eed910f962 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 18:12:08 -0300 Subject: V4L/DVB (6257): Rename video-buf-dvb to videobuf-dvb to be consistent with the other patches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 2 +- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/video-buf-dvb.c | 256 ---------------------------------- drivers/media/video/videobuf-dvb.c | 256 ++++++++++++++++++++++++++++++++++ include/media/video-buf-dvb.h | 37 ----- include/media/videobuf-dvb.h | 37 +++++ 7 files changed, 296 insertions(+), 296 deletions(-) delete mode 100644 drivers/media/video/video-buf-dvb.c create mode 100644 drivers/media/video/videobuf-dvb.c delete mode 100644 include/media/video-buf-dvb.h create mode 100644 include/media/videobuf-dvb.h (limited to 'include') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c8140aec1a16..b5a064163e03 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -90,7 +90,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o -obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o +obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 875a9abab2a2..b3fe2d59cd13 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -32,7 +32,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #include "btcx-risc.h" diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index dae608f9bf3b..cb617c8dbb71 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -42,7 +42,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #define UNSET (-1U) diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c deleted file mode 100644 index 9631ead297ee..000000000000 --- a/drivers/media/video/video-buf-dvb.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * - * some helper function for simple DVB cards which simply DMA the - * complete transport stream and let the computer sort everything else - * (i.e. we are using the software demux, ...). Also uses the - * video-buf to manage DMA buffers. - * - * (c) 2004 Gerd Knorr [SUSE Labs] - * - * 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. - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* ------------------------------------------------------------------ */ - -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages"); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg) - -/* ------------------------------------------------------------------ */ - -static int videobuf_dvb_thread(void *data) -{ - struct videobuf_dvb *dvb = data; - struct videobuf_buffer *buf; - unsigned long flags; - int err; - struct videobuf_dmabuf *dma; - - dprintk("dvb thread started\n"); - set_freezable(); - videobuf_read_start(&dvb->dvbq); - - for (;;) { - /* fetch next buffer */ - buf = list_entry(dvb->dvbq.stream.next, - struct videobuf_buffer, stream); - list_del(&buf->stream); - err = videobuf_waiton(buf,0,1); - - /* no more feeds left or stop_feed() asked us to quit */ - if (0 == dvb->nfeeds) - break; - if (kthread_should_stop()) - break; - try_to_freeze(); - - /* feed buffer data to demux */ - dma=videobuf_to_dma(buf); - if (buf->state == STATE_DONE) - dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, - buf->size); - - /* requeue buffer */ - list_add_tail(&buf->stream,&dvb->dvbq.stream); - spin_lock_irqsave(dvb->dvbq.irqlock,flags); - dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf); - spin_unlock_irqrestore(dvb->dvbq.irqlock,flags); - } - - videobuf_read_stop(&dvb->dvbq); - dprintk("dvb thread stopped\n"); - - /* Hmm, linux becomes *very* unhappy without this ... */ - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return 0; -} - -static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct videobuf_dvb *dvb = demux->priv; - int rc; - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&dvb->lock); - dvb->nfeeds++; - rc = dvb->nfeeds; - - if (NULL != dvb->thread) - goto out; - dvb->thread = kthread_run(videobuf_dvb_thread, - dvb, "%s dvb", dvb->name); - if (IS_ERR(dvb->thread)) { - rc = PTR_ERR(dvb->thread); - dvb->thread = NULL; - } - -out: - mutex_unlock(&dvb->lock); - return rc; -} - -static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct videobuf_dvb *dvb = demux->priv; - int err = 0; - - mutex_lock(&dvb->lock); - dvb->nfeeds--; - if (0 == dvb->nfeeds && NULL != dvb->thread) { - // FIXME: cx8802_cancel_buffers(dev); - err = kthread_stop(dvb->thread); - dvb->thread = NULL; - } - mutex_unlock(&dvb->lock); - return err; -} - -/* ------------------------------------------------------------------ */ - -int videobuf_dvb_register(struct videobuf_dvb *dvb, - struct module *module, - void *adapter_priv, - struct device *device) -{ - int result; - - mutex_init(&dvb->lock); - - /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", - dvb->name, result); - goto fail_adapter; - } - dvb->adapter.priv = adapter_priv; - - /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", - dvb->name, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dvb; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = videobuf_dvb_start_feed; - dvb->demux.stop_feed = videobuf_dvb_stop_feed; - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", - dvb->name, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", - dvb->name, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - dvb->name, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - dvb->name, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", - dvb->name, result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: - return result; -} - -void videobuf_dvb_unregister(struct videobuf_dvb *dvb) -{ - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -} - -EXPORT_SYMBOL(videobuf_dvb_register); -EXPORT_SYMBOL(videobuf_dvb_unregister); - -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ - diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c new file mode 100644 index 000000000000..880317e04a02 --- /dev/null +++ b/drivers/media/video/videobuf-dvb.c @@ -0,0 +1,256 @@ +/* + * + * some helper function for simple DVB cards which simply DMA the + * complete transport stream and let the computer sort everything else + * (i.e. we are using the software demux, ...). Also uses the + * video-buf to manage DMA buffers. + * + * (c) 2004 Gerd Knorr [SUSE Labs] + * + * 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. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* ------------------------------------------------------------------ */ + +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"enable debug messages"); + +#define dprintk(fmt, arg...) if (debug) \ + printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg) + +/* ------------------------------------------------------------------ */ + +static int videobuf_dvb_thread(void *data) +{ + struct videobuf_dvb *dvb = data; + struct videobuf_buffer *buf; + unsigned long flags; + int err; + struct videobuf_dmabuf *dma; + + dprintk("dvb thread started\n"); + set_freezable(); + videobuf_read_start(&dvb->dvbq); + + for (;;) { + /* fetch next buffer */ + buf = list_entry(dvb->dvbq.stream.next, + struct videobuf_buffer, stream); + list_del(&buf->stream); + err = videobuf_waiton(buf,0,1); + + /* no more feeds left or stop_feed() asked us to quit */ + if (0 == dvb->nfeeds) + break; + if (kthread_should_stop()) + break; + try_to_freeze(); + + /* feed buffer data to demux */ + dma=videobuf_to_dma(buf); + if (buf->state == STATE_DONE) + dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, + buf->size); + + /* requeue buffer */ + list_add_tail(&buf->stream,&dvb->dvbq.stream); + spin_lock_irqsave(dvb->dvbq.irqlock,flags); + dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf); + spin_unlock_irqrestore(dvb->dvbq.irqlock,flags); + } + + videobuf_read_stop(&dvb->dvbq); + dprintk("dvb thread stopped\n"); + + /* Hmm, linux becomes *very* unhappy without this ... */ + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + return 0; +} + +static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct videobuf_dvb *dvb = demux->priv; + int rc; + + if (!demux->dmx.frontend) + return -EINVAL; + + mutex_lock(&dvb->lock); + dvb->nfeeds++; + rc = dvb->nfeeds; + + if (NULL != dvb->thread) + goto out; + dvb->thread = kthread_run(videobuf_dvb_thread, + dvb, "%s dvb", dvb->name); + if (IS_ERR(dvb->thread)) { + rc = PTR_ERR(dvb->thread); + dvb->thread = NULL; + } + +out: + mutex_unlock(&dvb->lock); + return rc; +} + +static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct videobuf_dvb *dvb = demux->priv; + int err = 0; + + mutex_lock(&dvb->lock); + dvb->nfeeds--; + if (0 == dvb->nfeeds && NULL != dvb->thread) { + // FIXME: cx8802_cancel_buffers(dev); + err = kthread_stop(dvb->thread); + dvb->thread = NULL; + } + mutex_unlock(&dvb->lock); + return err; +} + +/* ------------------------------------------------------------------ */ + +int videobuf_dvb_register(struct videobuf_dvb *dvb, + struct module *module, + void *adapter_priv, + struct device *device) +{ + int result; + + mutex_init(&dvb->lock); + + /* register adapter */ + result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", + dvb->name, result); + goto fail_adapter; + } + dvb->adapter.priv = adapter_priv; + + /* register frontend */ + result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", + dvb->name, result); + goto fail_frontend; + } + + /* register demux stuff */ + dvb->demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dvb; + dvb->demux.filternum = 256; + dvb->demux.feednum = 256; + dvb->demux.start_feed = videobuf_dvb_start_feed; + dvb->demux.stop_feed = videobuf_dvb_stop_feed; + result = dvb_dmx_init(&dvb->demux); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", + dvb->name, result); + goto fail_dmx; + } + + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", + dvb->name, result); + goto fail_dmxdev; + } + + dvb->fe_hw.source = DMX_FRONTEND_0; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + dvb->name, result); + goto fail_fe_hw; + } + + dvb->fe_mem.source = DMX_MEMORY_FE; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + dvb->name, result); + goto fail_fe_mem; + } + + result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", + dvb->name, result); + goto fail_fe_conn; + } + + /* register network adapter */ + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + return 0; + +fail_fe_conn: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); +fail_fe_mem: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); +fail_fe_hw: + dvb_dmxdev_release(&dvb->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb->demux); +fail_dmx: + dvb_unregister_frontend(dvb->frontend); +fail_frontend: + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +fail_adapter: + return result; +} + +void videobuf_dvb_unregister(struct videobuf_dvb *dvb) +{ + dvb_net_release(&dvb->net); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + dvb_unregister_frontend(dvb->frontend); + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +} + +EXPORT_SYMBOL(videobuf_dvb_register); +EXPORT_SYMBOL(videobuf_dvb_unregister); + +/* ------------------------------------------------------------------ */ +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ + diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h deleted file mode 100644 index 8233cafdeef6..000000000000 --- a/include/media/video-buf-dvb.h +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include -#include - -struct videobuf_dvb { - /* filling that the job of the driver */ - char *name; - struct dvb_frontend *frontend; - struct videobuf_queue dvbq; - - /* video-buf-dvb state info */ - struct mutex lock; - struct task_struct *thread; - int nfeeds; - - /* videobuf_dvb_(un)register manges this */ - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; -}; - -int videobuf_dvb_register(struct videobuf_dvb *dvb, - struct module *module, - void *adapter_priv, - struct device *device); -void videobuf_dvb_unregister(struct videobuf_dvb *dvb); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/include/media/videobuf-dvb.h b/include/media/videobuf-dvb.h new file mode 100644 index 000000000000..8233cafdeef6 --- /dev/null +++ b/include/media/videobuf-dvb.h @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +struct videobuf_dvb { + /* filling that the job of the driver */ + char *name; + struct dvb_frontend *frontend; + struct videobuf_queue dvbq; + + /* video-buf-dvb state info */ + struct mutex lock; + struct task_struct *thread; + int nfeeds; + + /* videobuf_dvb_(un)register manges this */ + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net net; +}; + +int videobuf_dvb_register(struct videobuf_dvb *dvb, + struct module *module, + void *adapter_priv, + struct device *device); +void videobuf_dvb_unregister(struct videobuf_dvb *dvb); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ -- cgit v1.2.3 From 851c0c96b2212f48fe51afc1589541b5eae3a544 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 18:25:44 -0300 Subject: V4L/DVB (6266): videobuf cleanup: mmap check is common to all videobuf. Make it at core Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 4 ++-- drivers/media/video/videobuf-dma-sg.c | 24 +++++------------------ drivers/media/video/videobuf-vmalloc.c | 36 ++++++++++------------------------ include/media/videobuf-core.h | 4 +++- include/media/videobuf-dma-sg.h | 1 - include/media/videobuf-vmalloc.h | 3 --- 6 files changed, 20 insertions(+), 52 deletions(-) (limited to 'include') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index eb3b98400c1b..3bd06bb633a7 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -149,7 +149,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (CALL(q,is_mmapped,q->bufs[i])) { + if (q->bufs[i]->map) { dprintk(1,"busy: buffer #%d mapped\n",i); return 1; } @@ -238,7 +238,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, } b->flags = 0; - if (CALL(q,is_mmapped,vb)) + if (vb->map) b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 3345877c47d4..0939ede831ab 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -374,9 +374,9 @@ videobuf_vm_close(struct vm_area_struct *vma) MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - if (mem->map != map) + if (q->bufs[i]->map != map) continue; - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; q->ops->buf_release(q,q->bufs[i]); } @@ -520,8 +520,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -572,8 +571,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, continue; if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) continue; - mem=q->bufs[last]->priv; - if (mem->map) { + if (q->bufs[last]->map) { retval = -EBUSY; goto done; } @@ -593,8 +591,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, if (NULL == map) goto done; for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - mem=q->bufs[i]->priv; - mem->map = map; + q->bufs[i]->map = map; q->bufs[i]->baddr = vma->vm_start + size; } map->count = 1; @@ -613,16 +610,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return retval; } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_pci_sg_memory *mem=buf->priv; - - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -678,7 +665,6 @@ static struct videobuf_qtype_ops pci_ops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index fd059cde63f4..c9d6ae0d3b49 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -62,7 +62,6 @@ videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; - struct videbuf_vmalloc_memory *mem; int i; dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, @@ -75,19 +74,13 @@ videobuf_vm_close(struct vm_area_struct *vma) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - mem=q->bufs[i]->priv; - if (!mem) - continue; - - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - if (mem->map != map) + if (q->bufs[i]->map != map) continue; q->ops->buf_release(q,q->bufs[i]); - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } mutex_unlock(&q->lock); @@ -191,8 +184,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -227,12 +219,9 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, (vma->vm_pgoff << PAGE_SHIFT)); return -EINVAL; } - mem=q->bufs[first]->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); /* create mapping + update buffer list */ - map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + map = q->bufs[first]->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); if (NULL == map) return -ENOMEM; @@ -246,14 +235,19 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; vma->vm_private_data = map; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + /* Try to remap memory */ retval=remap_vmalloc_range(vma, mem->vmalloc,0); if (retval<0) { dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); if (!mem->vma) { kfree(map); - mem->map=NULL; + q->bufs[first]->map=NULL; return -ENOMEM; } memcpy(mem->vma,vma,sizeof(*vma)); @@ -269,15 +263,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return (0); } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_vmalloc_memory *mem=buf->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -335,7 +320,6 @@ static struct videobuf_qtype_ops qops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 0ac21ae44f69..96949e31eaf8 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -97,6 +97,9 @@ struct videobuf_buffer { /* buffer addr (userland ptr!) */ unsigned long baddr; + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + /* Private pointer to allow specific methods to store their data */ int privsize; void *priv; @@ -143,7 +146,6 @@ struct videobuf_qtype_ops { int (*mmap_free) (struct videobuf_queue *q); int (*mmap_mapper) (struct videobuf_queue *q, struct vm_area_struct *vma); - int (*is_mmapped) (struct videobuf_buffer *buf); }; struct videobuf_queue { diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 62a3709905f3..206d9027b39f 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -86,7 +86,6 @@ struct videbuf_pci_sg_memory u32 magic; /* for mmap'ed buffers */ - struct videobuf_mapping *map; struct videobuf_dmabuf dma; }; diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h index 5fff68df6689..26a8958d23d1 100644 --- a/include/media/videobuf-vmalloc.h +++ b/include/media/videobuf-vmalloc.h @@ -21,9 +21,6 @@ struct videbuf_vmalloc_memory { u32 magic; - /* for mmap'ed buffers */ - struct videobuf_mapping *map; - void *vmalloc; /* remap_vmalloc_range seems to need to run after mmap() on some cases */ -- cgit v1.2.3 From 5ddff43435394c1c2540fcdeed00cb54862c31bf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 11:43:49 -0300 Subject: V4L/DVB (6290): remove videobuf_set_pci_ops Before the videobuf redesign, a procedure for re-using videobuf without PCI scatter/gather where provided by changing the pci-dependent operations by other operations. With the newer approach, those methods are obsolete and can safelly be removed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-dma-sg.c | 62 +++-------------------------------- include/media/videobuf-core.h | 3 -- include/media/videobuf-dma-sg.h | 19 ----------- 3 files changed, 4 insertions(+), 80 deletions(-) (limited to 'include') diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 05dd38343fa3..a38efe10feb4 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -220,7 +220,6 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); @@ -247,10 +246,8 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) return -ENOMEM; } if (!dma->bus_addr) { - if (ops && ops->vb_map_sg) { - dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->sglen = pci_map_sg(dev,dma->sglist, dma->nr_pages, dma->direction); - } if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__FUNCTION__); @@ -266,30 +263,24 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(!dma->sglen); - if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - + pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction); return 0; } int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); if (!dma->sglen) return 0; - if (!dma->bus_addr && ops && ops->vb_unmap_sg) - ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); + pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction); + kfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; @@ -325,12 +316,8 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_map(&q,dma)); } @@ -338,12 +325,8 @@ int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_unmap(&q,dma)); } @@ -712,46 +695,10 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - struct videobuf_dma_sg_ops *priv_ops; - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); q->int_ops=&pci_ops; - - /* FIXME: the code bellow should be removed after having a proper - * memory allocation method for vivi and tm6000 - */ - q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); - BUG_ON (!q->priv_ops); - - priv_ops=q->priv_ops; - - /* Sets default methods for handling Scatter Gather mapping */ - priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; } -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops) -{ - kfree (q->priv_ops); - - q->priv_ops=ops; - - if (!ops) - return; - - /* If not specified, defaults to PCI map sg */ - if (!ops->vb_map_sg) - ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!ops->vb_unmap_sg) - ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - - /* --------------------------------------------------------------------- */ EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); @@ -771,7 +718,6 @@ EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); EXPORT_SYMBOL_GPL(videobuf_pci_alloc); EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); -EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); /* * Local variables: diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 96949e31eaf8..9bae5a2eda66 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -173,9 +173,6 @@ struct videobuf_queue { /* driver private data */ void *priv_data; - - /*FIXME: should be removed after completing the vb conversion */ - void *priv_ops; }; int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 206d9027b39f..38105031db23 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -89,19 +89,6 @@ struct videbuf_pci_sg_memory struct videobuf_dmabuf dma; }; -/* FIXME: To be removed soon */ -typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, - int direction); - -/* FIXME: To be removed soon */ -struct videobuf_dma_sg_ops -{ - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; - -}; - void videobuf_dma_init(struct videobuf_dmabuf *dma); int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size); @@ -133,9 +120,3 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); -/* FIXME: temporary routine for vivi and tm6000, while lacking implementation - * of videobuf-vmalloc - */ -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops); - -- cgit v1.2.3 From d4cae5a50021271b9ef4e5e39e71e177d12fa8cb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 12:20:02 -0300 Subject: V4L/DVB (6292): videobuf_core init always require callback implementation In the past, videobuf_queue_init were used to initialize PCI DMA videobuffers. This patch renames it, to avoid confusion with the previous kernel API, doing: s/videobuf_queue_init/void videobuf_queue_core_init/ Also, the operations is now part of the function parameter. The function will also add a test if this is defined, otherwise producing BUG. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 23 ++++++++++++++--------- drivers/media/video/videobuf-dma-sg.c | 4 ++-- drivers/media/video/videobuf-vmalloc.c | 4 ++-- include/media/videobuf-core.h | 5 +++-- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index aa402abc4b0c..f5c5ea8b6b08 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -108,23 +108,25 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, /* --------------------------------------------------------------------- */ -void videobuf_queue_init(struct videobuf_queue* q, +void videobuf_queue_core_init(struct videobuf_queue* q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv) + void *priv, + struct videobuf_qtype_ops *int_ops) { memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; q->priv_data = priv; + q->int_ops = int_ops; /* All buffer operations are mandatory */ BUG_ON (!q->ops->buf_setup); @@ -132,6 +134,9 @@ void videobuf_queue_init(struct videobuf_queue* q, BUG_ON (!q->ops->buf_queue); BUG_ON (!q->ops->buf_release); + /* Having implementations for abstract methods are mandatory */ + BUG_ON (!q->int_ops); + mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); } @@ -966,7 +971,7 @@ EXPORT_SYMBOL_GPL(videobuf_iolock); EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_core_init); EXPORT_SYMBOL_GPL(videobuf_queue_cancel); EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index a38efe10feb4..8bb7fdd306d6 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -695,8 +695,8 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&pci_ops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &pci_ops); } /* --------------------------------------------------------------------- */ diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index c9d6ae0d3b49..2e3689a12a28 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -333,8 +333,8 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&qops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &qops); } EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 9bae5a2eda66..9fa09fb800a1 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -181,14 +181,15 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, void *videobuf_alloc(struct videobuf_queue* q); -void videobuf_queue_init(struct videobuf_queue *q, +void videobuf_queue_core_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv); + void *priv, + struct videobuf_qtype_ops *int_ops); int videobuf_queue_is_busy(struct videobuf_queue *q); void videobuf_queue_cancel(struct videobuf_queue *q); -- cgit v1.2.3 From 54bd5b66c87d14e250f108aad1228b905d6882f6 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 8 Oct 2007 16:26:13 -0300 Subject: V4L/DVB (6293): V4L: convert struct class_device to struct device The currently used "struct class_device" will be removed from the kernel. Here is a patch that converts all users in drivers/media/video/ to struct device. Reviewed-by: Thierry Merle Reviewed-by: Mike Isely Reviewed-by: Luca Risolia Signed-off-by: Kay Sievers Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 11 +- drivers/media/video/et61x251/et61x251_core.c | 58 ++++--- drivers/media/video/ov511.c | 81 +++++---- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 210 +++++++++++++----------- drivers/media/video/pwc/pwc-if.c | 31 ++-- drivers/media/video/sn9c102/sn9c102_core.c | 112 +++++++------ drivers/media/video/stv680.c | 51 +++--- drivers/media/video/usbvision/usbvision-video.c | 119 +++++++------- drivers/media/video/videodev.c | 40 ++--- include/media/v4l2-dev.h | 14 +- 10 files changed, 387 insertions(+), 340 deletions(-) (limited to 'include') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 4ab4e14b5c64..49278537eec4 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -154,13 +154,14 @@ MODULE_LICENSE("GPL"); /* ----------------------------------------------------------------------- */ /* sysfs */ -static ssize_t show_card(struct class_device *cd, char *buf) +static ssize_t show_card(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = to_video_device(cd); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } -static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); +static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); /* ----------------------------------------------------------------------- */ /* dvb auto-load setup */ @@ -4615,9 +4616,9 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - if (class_device_create_file(&btv->video_dev->class_dev, - &class_device_attr_card)<0) { - printk(KERN_ERR "bttv%d: class_device_create_file 'card' " + if (device_create_file(&btv->video_dev->class_dev, + &dev_attr_card)<0) { + printk(KERN_ERR "bttv%d: device_create_file 'card' " "failed\n", btv->c.nr); goto err; } diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 31062a981e36..d5fef4c01c87 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -706,7 +706,8 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -729,7 +730,8 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_reg(struct device* cd, + struct device_attribute *attr, const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -761,7 +763,8 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -792,7 +795,8 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -830,7 +834,8 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -855,7 +860,8 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -887,7 +893,8 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -923,7 +930,8 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -966,42 +974,40 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - et61x251_show_reg, et61x251_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - et61x251_show_val, et61x251_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - et61x251_show_i2c_reg, et61x251_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - et61x251_show_i2c_val, et61x251_store_i2c_val); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, + et61x251_show_reg, et61x251_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, + et61x251_show_val, et61x251_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + et61x251_show_i2c_reg, et61x251_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + et61x251_show_i2c_val, et61x251_store_i2c_val); static int et61x251_create_sysfs(struct et61x251_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index e5edff1059a2..9eb2562347a8 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5554,41 +5554,46 @@ error: * sysfs ***************************************************************************/ -static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) +static inline struct usb_ov511 *cd_to_ov(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_custom_id(struct class_device *cd, char *buf) +static ssize_t show_custom_id(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%d\n", ov->customid); } -static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); +static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", ov->desc); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_bridge(struct class_device *cd, char *buf) +static ssize_t show_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); -static ssize_t show_sensor(struct class_device *cd, char *buf) +static ssize_t show_sensor(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); } -static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); +static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5598,9 +5603,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) sensor_get_brightness(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5610,9 +5616,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) sensor_get_saturation(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5622,9 +5629,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) sensor_get_contrast(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5634,9 +5642,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) sensor_get_hue(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_exposure(struct class_device *cd, char *buf) +static ssize_t show_exposure(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned char exp = 0; @@ -5646,49 +5655,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf) sensor_get_exposure(ov, &exp); return sprintf(buf, "%d\n", exp >> 8); } -static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); +static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); static int ov_create_sysfs(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_custom_id); + rc = video_device_create_file(vdev, &dev_attr_custom_id); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err_id; - rc = video_device_create_file(vdev, &class_device_attr_bridge); + rc = video_device_create_file(vdev, &dev_attr_bridge); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_sensor); + rc = video_device_create_file(vdev, &dev_attr_sensor); if (rc) goto err_bridge; - rc = video_device_create_file(vdev, &class_device_attr_brightness); + rc = video_device_create_file(vdev, &dev_attr_brightness); if (rc) goto err_sensor; - rc = video_device_create_file(vdev, &class_device_attr_saturation); + rc = video_device_create_file(vdev, &dev_attr_saturation); if (rc) goto err_bright; - rc = video_device_create_file(vdev, &class_device_attr_contrast); + rc = video_device_create_file(vdev, &dev_attr_contrast); if (rc) goto err_sat; - rc = video_device_create_file(vdev, &class_device_attr_hue); + rc = video_device_create_file(vdev, &dev_attr_hue); if (rc) goto err_contrast; - rc = video_device_create_file(vdev, &class_device_attr_exposure); + rc = video_device_create_file(vdev, &dev_attr_exposure); if (rc) goto err_hue; return 0; err_hue: - video_device_remove_file(vdev, &class_device_attr_hue); + video_device_remove_file(vdev, &dev_attr_hue); err_contrast: - video_device_remove_file(vdev, &class_device_attr_contrast); + video_device_remove_file(vdev, &dev_attr_contrast); err_sat: - video_device_remove_file(vdev, &class_device_attr_saturation); + video_device_remove_file(vdev, &dev_attr_saturation); err_bright: - video_device_remove_file(vdev, &class_device_attr_brightness); + video_device_remove_file(vdev, &dev_attr_brightness); err_sensor: - video_device_remove_file(vdev, &class_device_attr_sensor); + video_device_remove_file(vdev, &dev_attr_sensor); err_bridge: - video_device_remove_file(vdev, &class_device_attr_bridge); + video_device_remove_file(vdev, &dev_attr_bridge); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err_id: - video_device_remove_file(vdev, &class_device_attr_custom_id); + video_device_remove_file(vdev, &dev_attr_custom_id); err: return rc; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7ab79baa1c8c..b20dc4421d59 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -33,16 +33,16 @@ struct pvr2_sysfs { struct pvr2_channel channel; - struct class_device *class_dev; + struct device *class_dev; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc *debugifc; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item *item_first; struct pvr2_sysfs_ctl_item *item_last; - struct class_device_attribute attr_v4l_minor_number; - struct class_device_attribute attr_v4l_radio_minor_number; - struct class_device_attribute attr_unit_number; - struct class_device_attribute attr_bus_info; + struct device_attribute attr_v4l_minor_number; + struct device_attribute attr_v4l_radio_minor_number; + struct device_attribute attr_unit_number; + struct device_attribute attr_bus_info; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; @@ -51,22 +51,22 @@ struct pvr2_sysfs { #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc { - struct class_device_attribute attr_debugcmd; - struct class_device_attribute attr_debuginfo; + struct device_attribute attr_debugcmd; + struct device_attribute attr_debuginfo; int debugcmd_created_ok; int debuginfo_created_ok; }; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item { - struct class_device_attribute attr_name; - struct class_device_attribute attr_type; - struct class_device_attribute attr_min; - struct class_device_attribute attr_max; - struct class_device_attribute attr_enum; - struct class_device_attribute attr_bits; - struct class_device_attribute attr_val; - struct class_device_attribute attr_custom; + struct device_attribute attr_name; + struct device_attribute attr_type; + struct device_attribute attr_min; + struct device_attribute attr_max; + struct device_attribute attr_enum; + struct device_attribute attr_bits; + struct device_attribute attr_val; + struct device_attribute attr_custom; struct pvr2_ctrl *cptr; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; @@ -80,13 +80,13 @@ struct pvr2_sysfs_class { struct class class; }; -static ssize_t show_name(int id,struct class_device *class_dev,char *buf) +static ssize_t show_name(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -99,14 +99,14 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_type(int id,struct class_device *class_dev,char *buf) +static ssize_t show_type(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; enum pvr2_ctl_type tp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -126,13 +126,13 @@ static ssize_t show_type(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_min(int id,struct class_device *class_dev,char *buf) +static ssize_t show_min(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -143,13 +143,13 @@ static ssize_t show_min(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_max(int id,struct class_device *class_dev,char *buf) +static ssize_t show_max(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -160,14 +160,14 @@ static ssize_t show_max(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_norm(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -184,14 +184,14 @@ static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_custom(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -208,14 +208,14 @@ static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) +static ssize_t show_enum(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; unsigned int bcnt,ccnt,ecnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -233,14 +233,14 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) return bcnt; } -static ssize_t show_bits(int id,struct class_device *class_dev,char *buf) +static ssize_t show_bits(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int valid_bits,msk; unsigned int bcnt,ccnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -278,23 +278,23 @@ static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, return ret; } -static ssize_t store_val_norm(int id,struct class_device *class_dev, +static ssize_t store_val_norm(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,0,sfp,buf,count); if (!ret) ret = count; return ret; } -static ssize_t store_val_custom(int id,struct class_device *class_dev, +static ssize_t store_val_custom(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,1,sfp,buf,count); if (!ret) ret = count; return ret; @@ -304,7 +304,7 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, Mike Isely 30-April-2005 This next batch of horrible preprocessor hackery is needed because the - kernel's class_device_attribute mechanism fails to pass the actual + kernel's device_attribute mechanism fails to pass the actual attribute through to the show / store functions, which means we have no way to package up any attribute-specific parameters, like for example the control id. So we work around this brain-damage by encoding the control @@ -314,11 +314,13 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, */ #define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, char *buf) \ { return sf_name(ctl_id,class_dev,buf); } #define CREATE_STORE_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, const char *buf, size_t count) \ { return sf_name(ctl_id,class_dev,buf,count); } #define CREATE_BATCH(ctl_id) \ @@ -395,17 +397,27 @@ CREATE_BATCH(58) CREATE_BATCH(59) struct pvr2_sysfs_func_set { - ssize_t (*show_name)(struct class_device *,char *); - ssize_t (*show_type)(struct class_device *,char *); - ssize_t (*show_min)(struct class_device *,char *); - ssize_t (*show_max)(struct class_device *,char *); - ssize_t (*show_enum)(struct class_device *,char *); - ssize_t (*show_bits)(struct class_device *,char *); - ssize_t (*show_val_norm)(struct class_device *,char *); - ssize_t (*store_val_norm)(struct class_device *, + ssize_t (*show_name)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_type)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_min)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_max)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_enum)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_bits)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_val_norm)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_norm)(struct device *, + struct device_attribute *attr, const char *,size_t); - ssize_t (*show_val_custom)(struct class_device *,char *); - ssize_t (*store_val_custom)(struct class_device *, + ssize_t (*show_val_custom)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_custom)(struct device *, + struct device_attribute *attr, const char *,size_t); }; @@ -597,9 +609,9 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *,char *); -static ssize_t debugcmd_show(struct class_device *,char *); -static ssize_t debugcmd_store(struct class_device *,const char *,size_t count); +static ssize_t debuginfo_show(struct device *,char *); +static ssize_t debugcmd_show(struct device *,char *); +static ssize_t debugcmd_store(struct device *,const char *,size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { @@ -616,16 +628,16 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) dip->attr_debuginfo.attr.mode = S_IRUGO; dip->attr_debuginfo.show = debuginfo_show; sfp->debugifc = dip; - ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); + ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debugcmd_created_ok = !0; } - ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); + ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debuginfo_created_ok = !0; @@ -637,11 +649,11 @@ static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) { if (!sfp->debugifc) return; if (sfp->debugifc->debuginfo_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debuginfo); } if (sfp->debugifc->debugcmd_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debugcmd); } kfree(sfp->debugifc); @@ -683,7 +695,7 @@ static void pvr2_sysfs_class_release(struct class *class) } -static void pvr2_sysfs_release(struct class_device *class_dev) +static void pvr2_sysfs_release(struct device *class_dev) { pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); kfree(class_dev); @@ -698,32 +710,33 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); if (sfp->bus_info_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_bus_info); } if (sfp->v4l_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_minor_number); } if (sfp->v4l_radio_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); } if (sfp->unit_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_unit_number); } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); - sfp->class_dev->class_data = NULL; - class_device_unregister(sfp->class_dev); + sfp->class_dev->driver_data = NULL; + device_unregister(sfp->class_dev); sfp->class_dev = NULL; } -static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) +static ssize_t v4l_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -731,21 +744,23 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) } -static ssize_t bus_info_show(struct class_device *class_dev,char *buf) +static ssize_t bus_info_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_bus_info(sfp->channel.hdw)); } -static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, +static ssize_t v4l_radio_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -753,10 +768,11 @@ static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, } -static ssize_t unit_number_show(struct class_device *class_dev,char *buf) +static ssize_t unit_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_get_unit_number(sfp->channel.hdw)); @@ -767,7 +783,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, struct pvr2_sysfs_class *class_ptr) { struct usb_device *usb_dev; - struct class_device *class_dev; + struct device *class_dev; int ret; usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); @@ -779,23 +795,23 @@ static void class_dev_create(struct pvr2_sysfs *sfp, class_dev->class = &class_ptr->class; if (pvr2_hdw_get_sn(sfp->channel.hdw)) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu", pvr2_hdw_get_sn(sfp->channel.hdw)); } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c", pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); } else { kfree(class_dev); return; } - class_dev->dev = &usb_dev->dev; + class_dev->parent = &usb_dev->dev; sfp->class_dev = class_dev; - class_dev->class_data = sfp; - ret = class_device_register(class_dev); + class_dev->driver_data = sfp; + ret = device_register(class_dev); if (ret) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); kfree(class_dev); return; @@ -805,10 +821,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_minor_number.show = v4l_minor_number_show; sfp->attr_v4l_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_minor_number_created_ok = !0; @@ -818,10 +834,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; sfp->attr_v4l_radio_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_radio_minor_number_created_ok = !0; @@ -831,9 +847,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_unit_number.attr.mode = S_IRUGO; sfp->attr_unit_number.show = unit_number_show; sfp->attr_unit_number.store = NULL; - ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); + ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->unit_number_created_ok = !0; @@ -843,10 +859,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_bus_info.attr.mode = S_IRUGO; sfp->attr_bus_info.show = bus_info_show; sfp->attr_bus_info.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_bus_info); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->bus_info_created_ok = !0; @@ -886,7 +902,7 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp, +static int pvr2_sysfs_hotplug(struct device *cd,char **envp, int numenvp,char *buf,int size) { /* Even though we don't do anything here, we still need this function @@ -902,8 +918,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); clp->class.name = "pvrusb2"; clp->class.class_release = pvr2_sysfs_class_release; - clp->class.release = pvr2_sysfs_release; - clp->class.uevent = pvr2_sysfs_hotplug; + clp->class.dev_release = pvr2_sysfs_release; + clp->class.dev_uevent = pvr2_sysfs_hotplug; if (class_register(&clp->class)) { pvr2_sysfs_trace( "Registration failed for pvr2_sysfs_class id=%p",clp); @@ -921,32 +937,32 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *class_dev,char *buf) +static ssize_t debuginfo_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; pvr2_hdw_trigger_module_log(sfp->channel.hdw); return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_show(struct class_device *class_dev,char *buf) +static ssize_t debugcmd_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_store(struct class_device *class_dev, - const char *buf,size_t count) +static ssize_t debugcmd_store(struct device *class_dev, + const char *buf, size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 0ff5718bf9b9..0b67d4ec0318 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -996,20 +996,22 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f /********* * sysfs *********/ -static struct pwc_device *cd_to_pwc(struct class_device *cd) +static struct pwc_device *cd_to_pwc(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf) +static ssize_t show_pan_tilt(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); } -static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, - size_t count) +static ssize_t store_pan_tilt(struct device *class_dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct pwc_device *pdev = cd_to_pwc(class_dev); int pan, tilt; @@ -1025,10 +1027,11 @@ static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, return ret; return strlen(buf); } -static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); +static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, + store_pan_tilt); -static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf) +static ssize_t show_snapshot_button_status(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); int status = pdev->snapshot_button_status; @@ -1036,26 +1039,26 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char return sprintf(buf, "%d\n", status); } -static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); +static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, + NULL); static int pwc_create_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = video_device_create_file(vdev, &class_device_attr_button); + rc = video_device_create_file(vdev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = video_device_create_file(vdev,&class_device_attr_pan_tilt); + rc = video_device_create_file(vdev, &dev_attr_pan_tilt); if (rc) goto err_button; } return 0; err_button: - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_button); err: return rc; } @@ -1064,8 +1067,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_remove_file(vdev, &class_device_attr_pan_tilt); - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_pan_tilt); + video_device_remove_file(vdev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index e0accf1b8713..6991e06f7651 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1029,7 +1029,8 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1053,7 +1054,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1086,7 +1088,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1118,7 +1121,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1157,7 +1161,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1183,7 +1188,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1216,7 +1222,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1253,7 +1260,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1298,7 +1306,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_green(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; enum sn9c102_bridge bridge; @@ -1329,16 +1338,16 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) case BRIDGE_SN9C102: if (value > 0x0f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; case BRIDGE_SN9C103: case BRIDGE_SN9C105: case BRIDGE_SN9C120: if (value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; } @@ -1347,7 +1356,8 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_blue(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1357,15 +1367,16 @@ sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } static ssize_t -sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_red(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1375,14 +1386,16 @@ sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } -static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_frame_header(struct device* cd, + struct device_attribute *attr, + char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1401,72 +1414,63 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - sn9c102_show_reg, sn9c102_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - sn9c102_show_val, sn9c102_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); -static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); -static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); -static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, - sn9c102_show_frame_header, NULL); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_val, sn9c102_store_i2c_val); +static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); +static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); +static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); +static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); static int sn9c102_create_sysfs(struct sn9c102_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; - if ((err = class_device_create_file(classdev, - &class_device_attr_frame_header))) + if ((err = device_create_file(classdev, &dev_attr_frame_header))) goto err_val; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_frame_header; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = class_device_create_file(classdev, - &class_device_attr_green))) + if ((err = device_create_file(classdev, &dev_attr_green))) goto err_i2c_val; } else { - if ((err = class_device_create_file(classdev, - &class_device_attr_blue))) + if ((err = device_create_file(classdev, &dev_attr_blue))) goto err_i2c_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_red))) + if ((err = device_create_file(classdev, &dev_attr_red))) goto err_blue; } return 0; err_blue: - class_device_remove_file(classdev, &class_device_attr_blue); + device_remove_file(classdev, &dev_attr_blue); err_i2c_val: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_val); + device_remove_file(classdev, &dev_attr_i2c_val); err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_frame_header: - class_device_remove_file(classdev, &class_device_attr_frame_header); + device_remove_file(classdev, &dev_attr_frame_header); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 4dc5bc714b95..9e009a7ab863 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -499,13 +499,14 @@ exit: * sysfs ***************************************************************************/ #define stv680_file(name, variable, field) \ -static ssize_t show_##name(struct class_device *class_dev, char *buf) \ +static ssize_t show_##name(struct device *class_dev, \ + struct device_attribute *attr, char *buf) \ { \ struct video_device *vdev = to_video_device(class_dev); \ struct usb_stv *stv = video_get_drvdata(vdev); \ return sprintf(buf, field, stv->variable); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); stv680_file(model, camera_name, "%s\n"); stv680_file(in_use, user, "%d\n"); @@ -520,53 +521,53 @@ static int stv680_create_sysfs_files(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_in_use); + rc = video_device_create_file(vdev, &dev_attr_in_use); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_streaming); + rc = video_device_create_file(vdev, &dev_attr_streaming); if (rc) goto err_inuse; - rc = video_device_create_file(vdev, &class_device_attr_palette); + rc = video_device_create_file(vdev, &dev_attr_palette); if (rc) goto err_stream; - rc = video_device_create_file(vdev, &class_device_attr_frames_total); + rc = video_device_create_file(vdev, &dev_attr_frames_total); if (rc) goto err_pal; - rc = video_device_create_file(vdev, &class_device_attr_frames_read); + rc = video_device_create_file(vdev, &dev_attr_frames_read); if (rc) goto err_framtot; - rc = video_device_create_file(vdev, &class_device_attr_packets_dropped); + rc = video_device_create_file(vdev, &dev_attr_packets_dropped); if (rc) goto err_framread; - rc = video_device_create_file(vdev, &class_device_attr_decoding_errors); + rc = video_device_create_file(vdev, &dev_attr_decoding_errors); if (rc) goto err_dropped; return 0; err_dropped: - video_device_remove_file(vdev, &class_device_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_packets_dropped); err_framread: - video_device_remove_file(vdev, &class_device_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_frames_read); err_framtot: - video_device_remove_file(vdev, &class_device_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_total); err_pal: - video_device_remove_file(vdev, &class_device_attr_palette); + video_device_remove_file(vdev, &dev_attr_palette); err_stream: - video_device_remove_file(vdev, &class_device_attr_streaming); + video_device_remove_file(vdev, &dev_attr_streaming); err_inuse: - video_device_remove_file(vdev, &class_device_attr_in_use); + video_device_remove_file(vdev, &dev_attr_in_use); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err: return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &class_device_attr_model); - video_device_remove_file(vdev, &class_device_attr_in_use); - video_device_remove_file(vdev, &class_device_attr_streaming); - video_device_remove_file(vdev, &class_device_attr_palette); - video_device_remove_file(vdev, &class_device_attr_frames_total); - video_device_remove_file(vdev, &class_device_attr_frames_read); - video_device_remove_file(vdev, &class_device_attr_packets_dropped); - video_device_remove_file(vdev, &class_device_attr_decoding_errors); + video_device_remove_file(vdev, &dev_attr_model); + video_device_remove_file(vdev, &dev_attr_in_use); + video_device_remove_file(vdev, &dev_attr_streaming); + video_device_remove_file(vdev, &dev_attr_palette); + video_device_remove_file(vdev, &dev_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_decoding_errors); } /******************************************************************** diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 2f9b2b9e3b09..e2f3c01cfa13 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -182,20 +182,22 @@ MODULE_ALIAS(DRIVER_ALIAS); #define YES_NO(x) ((x) ? "Yes" : "No") -static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) +static inline struct usb_usbvision *cd_to_usbvision(struct device *cd) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); return video_get_drvdata(vdev); } -static ssize_t show_version(struct class_device *cd, char *buf) +static ssize_t show_version(struct device *cd, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", USBVISION_VERSION_STRING); } -static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); +static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -203,9 +205,10 @@ static ssize_t show_model(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -217,9 +220,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -231,9 +235,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -245,9 +250,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -259,9 +265,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_streaming(struct class_device *cd, char *buf) +static ssize_t show_streaming(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -269,9 +276,10 @@ static ssize_t show_streaming(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); } -static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); +static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); -static ssize_t show_compression(struct class_device *cd, char *buf) +static ssize_t show_compression(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -279,16 +287,17 @@ static ssize_t show_compression(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); } -static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); +static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); -static ssize_t show_device_bridge(struct class_device *cd, char *buf) +static ssize_t show_device_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) { @@ -296,40 +305,40 @@ static void usbvision_create_sysfs(struct video_device *vdev) if (!vdev) return; do { - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_version); + res = device_create_file(&vdev->class_dev, + &dev_attr_version); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_model); + res = device_create_file(&vdev->class_dev, + &dev_attr_model); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_hue); + res = device_create_file(&vdev->class_dev, + &dev_attr_hue); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_contrast); + res = device_create_file(&vdev->class_dev, + &dev_attr_contrast); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_brightness); + res = device_create_file(&vdev->class_dev, + &dev_attr_brightness); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_saturation); + res = device_create_file(&vdev->class_dev, + &dev_attr_saturation); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_streaming); + res = device_create_file(&vdev->class_dev, + &dev_attr_streaming); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_compression); + res = device_create_file(&vdev->class_dev, + &dev_attr_compression); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_bridge); + res = device_create_file(&vdev->class_dev, + &dev_attr_bridge); if (res>=0) return; } while (0); @@ -340,24 +349,24 @@ static void usbvision_create_sysfs(struct video_device *vdev) static void usbvision_remove_sysfs(struct video_device *vdev) { if (vdev) { - class_device_remove_file(&vdev->class_dev, - &class_device_attr_version); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_model); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_hue); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_contrast); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_brightness); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_saturation); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_streaming); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_compression); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_bridge); + device_remove_file(&vdev->class_dev, + &dev_attr_version); + device_remove_file(&vdev->class_dev, + &dev_attr_model); + device_remove_file(&vdev->class_dev, + &dev_attr_hue); + device_remove_file(&vdev->class_dev, + &dev_attr_contrast); + device_remove_file(&vdev->class_dev, + &dev_attr_brightness); + device_remove_file(&vdev->class_dev, + &dev_attr_saturation); + device_remove_file(&vdev->class_dev, + &dev_attr_streaming); + device_remove_file(&vdev->class_dev, + &dev_attr_compression); + device_remove_file(&vdev->class_dev, + &dev_attr_bridge); } } diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0334b9aaf12a..0fbe8a1a91b3 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -54,15 +54,14 @@ * sysfs stuff */ -static ssize_t show_name(struct class_device *cd, char *buf) +static ssize_t show_name(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, - class_dev); - return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name); + class_dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - struct video_device *video_device_alloc(void) { struct video_device *vfd; @@ -76,10 +75,9 @@ void video_device_release(struct video_device *vfd) kfree(vfd); } -static void video_release(struct class_device *cd) +static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); + struct video_device *vfd = container_of(cd, struct video_device, class_dev); #if 1 /* needed until all drivers are fixed */ @@ -89,9 +87,15 @@ static void video_release(struct class_device *cd) vfd->release(vfd); } +static struct device_attribute video_device_attrs[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR_NULL +}; + static struct class video_class = { .name = VIDEO_NAME, - .release = video_release, + .dev_attrs = video_device_attrs, + .dev_release = video_release, }; /* @@ -1753,22 +1757,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) /* sysfs class */ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); if (vfd->dev) - vfd->class_dev.dev = vfd->dev; + vfd->class_dev.parent = vfd->dev; vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); - sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base); - ret = class_device_register(&vfd->class_dev); + sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); + ret = device_register(&vfd->class_dev); if (ret < 0) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); goto fail_minor; } - ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name); - if (ret < 0) { - printk(KERN_ERR "%s: class_device_create_file 'name' failed\n", - __FUNCTION__); - goto fail_classdev; - } #if 1 /* needed until all drivers are fixed */ @@ -1779,8 +1777,6 @@ int video_register_device(struct video_device *vfd, int type, int nr) #endif return 0; -fail_classdev: - class_device_unregister(&vfd->class_dev); fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; @@ -1804,7 +1800,7 @@ void video_unregister_device(struct video_device *vfd) panic("videodev: bad unregister"); video_device[vfd->minor]=NULL; - class_device_unregister(&vfd->class_dev); + device_unregister(&vfd->class_dev); mutex_unlock(&videodev_lock); } diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 8b79e2cf77fa..e75d5e6c4cea 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -86,8 +86,11 @@ struct video_device /* device ops */ const struct file_operations *fops; + /* sysfs */ + struct device class_dev; /* v4l device */ + struct device *dev; /* device parent */ + /* device info */ - struct device *dev; char name[32]; int type; /* v4l1 */ int type2; /* v4l2 */ @@ -332,7 +335,6 @@ void *priv; /* for videodev.c intenal usage -- please don't touch */ int users; /* video_exclusive_{open|close} ... */ struct mutex lock; /* ... helper function uses these */ - struct class_device class_dev; /* sysfs */ }; /* Class-dev to video-device */ @@ -360,18 +362,18 @@ extern int video_usercopy(struct inode *inode, struct file *file, static inline int __must_check video_device_create_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - int ret = class_device_create_file(&vfd->class_dev, attr); + int ret = device_create_file(&vfd->class_dev, attr); if (ret < 0) printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); return ret; } static inline void video_device_remove_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - class_device_remove_file(&vfd->class_dev, attr); + device_remove_file(&vfd->class_dev, attr); } #endif /* CONFIG_VIDEO_V4L1_COMPAT */ -- cgit v1.2.3