]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Oct 2008 22:43:52 +0000 (15:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Oct 2008 22:43:52 +0000 (15:43 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (94 commits)
  USB: remove err() macro from more usb drivers
  USB: remove err() macro from usb misc drivers
  USB: remove err() macro from usb core code
  USB: remove err() macro from usb class drivers
  USB: remove use of err() in drivers/usb/serial
  USB: remove info() macro from usb mtd drivers
  USB: remove info() macro from usb input drivers
  USB: remove info() macro from usb network drivers
  USB: remove info() macro from remaining usb drivers
  USB: remove info() macro from usb/misc drivers
  USB: remove info() macro from usb/serial drivers
  USB: remove warn macro from HID core
  USB: remove warn() macro from usb drivers
  USB: remove warn() macro from usb net drivers
  USB: remove warn() macro from usb media drivers
  USB: remove warn() macro from usb input drivers
  usb/fsl_qe_udc: clear data toggle on clear halt request
  usb/fsl_qe_udc: fix response to get status request
  fsl_usb2_udc: Fix oops on probe failure.
  fsl_usb2_udc: Add a wmb before priming endpoint.
  ...

156 files changed:
Documentation/filesystems/ext4.txt
Documentation/video4linux/CARDLIST.au0828
Documentation/video4linux/CARDLIST.tuner
arch/x86/mm/highmem_32.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_agpsupport.c
drivers/gpu/drm/drm_cache.c [new file with mode: 0644]
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c [new file with mode: 0644]
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_memory.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_debug.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_proc.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_tiling.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_opregion.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_reg.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_suspend.c [new file with mode: 0644]
drivers/gpu/drm/mga/mga_drv.c
drivers/gpu/drm/mga/mga_drv.h
drivers/gpu/drm/mga/mga_irq.c
drivers/gpu/drm/mga/mga_state.c
drivers/gpu/drm/r128/r128_drv.c
drivers/gpu/drm/r128/r128_drv.h
drivers/gpu/drm/r128/r128_irq.c
drivers/gpu/drm/r128/r128_state.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_irq.c
drivers/gpu/drm/radeon/radeon_state.c
drivers/gpu/drm/sis/sis_mm.c
drivers/gpu/drm/via/via_drv.c
drivers/gpu/drm/via/via_drv.h
drivers/gpu/drm/via/via_irq.c
drivers/gpu/drm/via/via_mm.c
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx22702.h
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/cx24116.h
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/cx24123.h
drivers/media/dvb/frontends/s5h1409.c
drivers/media/dvb/frontends/s5h1409.h
drivers/media/dvb/frontends/s5h1411.c
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/frontends/z0194a.h
drivers/media/dvb/siano/sms-cards.c
drivers/media/radio/Kconfig
drivers/media/radio/radio-si470x.c
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/bt866.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/m5602_bridge.h
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.c
drivers/media/video/gspca/m5602/m5602_mt9m111.h
drivers/media/video/gspca/m5602/m5602_ov9650.c
drivers/media/video/gspca/m5602/m5602_ov9650.h
drivers/media/video/gspca/m5602/m5602_po1030.c
drivers/media/video/gspca/m5602/m5602_po1030.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/m5602/m5602_s5k4aa.h
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/m5602/m5602_s5k83a.h
drivers/media/video/gspca/m5602/m5602_sensor.h
drivers/media/video/gspca/t613.c
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ks0127.c
drivers/media/video/saa7110.c
drivers/media/video/saa7111.c
drivers/media/video/saa7114.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7185.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/stk-webcam.c
drivers/media/video/stk-webcam.h
drivers/media/video/tveeprom.c
drivers/media/video/videobuf-dvb.c
drivers/media/video/vivi.c
drivers/media/video/vpx3220.c
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_driver.c
fs/Kconfig
fs/Makefile
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/ext4_sb.h
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/super.c
fs/jbd2/commit.c
fs/jbd2/transaction.c
include/drm/drm.h
include/drm/drmP.h
include/drm/drm_pciids.h
include/drm/i915_drm.h
include/linux/dvb/frontend.h
include/linux/i2c-id.h
include/linux/jbd2.h
include/linux/writeback.h
include/media/soc_camera_platform.h
include/media/tuner.h
include/media/v4l2-i2c-drv-legacy.h
include/media/v4l2-i2c-drv.h
include/media/videobuf-dvb.h
mm/page-writeback.c
mm/shmem.c

index eb154ef36c2a4b708004ff08660f2a7ebe971fa7..174eaff7ded9f1e7f9ef71882b446d87cea8c359 100644 (file)
@@ -2,19 +2,24 @@
 Ext4 Filesystem
 ===============
 
-This is a development version of the ext4 filesystem, an advanced level
-of the ext3 filesystem which incorporates scalability and reliability
-enhancements for supporting large filesystems (64 bit) in keeping with
-increasing disk capacities and state-of-the-art feature requirements.
+Ext4 is an an advanced level of the ext3 filesystem which incorporates
+scalability and reliability enhancements for supporting large filesystems
+(64 bit) in keeping with increasing disk capacities and state-of-the-art
+feature requirements.
 
-Mailing list: linux-ext4@vger.kernel.org
+Mailing list:  linux-ext4@vger.kernel.org
+Web site:      http://ext4.wiki.kernel.org
 
 
 1. Quick usage instructions:
 ===========================
 
+Note: More extensive information for getting started with ext4 can be
+      found at the ext4 wiki site at the URL:
+      http://ext4.wiki.kernel.org/index.php/Ext4_Howto
+
   - Compile and install the latest version of e2fsprogs (as of this
-    writing version 1.41) from:
+    writing version 1.41.3) from:
 
     http://sourceforge.net/project/showfiles.php?group_id=2406
        
@@ -36,11 +41,9 @@ Mailing list: linux-ext4@vger.kernel.org
 
        # mke2fs -t ext4 /dev/hda1
 
-    Or configure an existing ext3 filesystem to support extents and set
-    the test_fs flag to indicate that it's ok for an in-development
-    filesystem to touch this filesystem:
+    Or to configure an existing ext3 filesystem to support extents: 
 
-       # tune2fs -O extents -E test_fs /dev/hda1
+       # tune2fs -O extents /dev/hda1
 
     If the filesystem was created with 128 byte inodes, it can be
     converted to use 256 byte for greater efficiency via:
@@ -104,8 +107,8 @@ exist yet so I'm not sure they're in the near-term roadmap.
 The big performance win will come with mballoc, delalloc and flex_bg
 grouping of bitmaps and inode tables.  Some test results available here:
 
- - http://www.bullopensource.org/ext4/20080530/ffsb-write-2.6.26-rc2.html
- - http://www.bullopensource.org/ext4/20080530/ffsb-readwrite-2.6.26-rc2.html
+ - http://www.bullopensource.org/ext4/20080818-ffsb/ffsb-write-2.6.27-rc1.html
+ - http://www.bullopensource.org/ext4/20080818-ffsb/ffsb-readwrite-2.6.27-rc1.html
 
 3. Options
 ==========
@@ -214,9 +217,6 @@ noreservation
 bsddf          (*)     Make 'df' act like BSD.
 minixdf                        Make 'df' act like Minix.
 
-check=none             Don't do extra checking of bitmaps on mount.
-nocheck
-
 debug                  Extra debugging information is sent to syslog.
 
 errors=remount-ro(*)   Remount the filesystem read-only on an error.
@@ -253,8 +253,6 @@ nobh                        (a) cache disk block mapping information
                        "nobh" option tries to avoid associating buffer
                        heads (supported only for "writeback" mode).
 
-mballoc                (*)     Use the multiple block allocator for block allocation
-nomballoc              disabled multiple block allocator for block allocation.
 stripe=n               Number of filesystem blocks that mballoc will try
                        to use for allocation size and alignment. For RAID5/6
                        systems this should be the number of data
index aa05e5bb22fbf4ac4f7041d1d4cc01150e763209..d5cb4ea287b21dff9086d1d43c77a1874c033931 100644 (file)
@@ -1,5 +1,5 @@
   0 -> Unknown board                            (au0828)
-  1 -> Hauppauge HVR950Q                        (au0828)        [2040:7200,2040:7210,2040:7217,2040:721b,2040:721f,2040:7280,0fd9:0008]
+  1 -> Hauppauge HVR950Q                        (au0828)        [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008]
   2 -> Hauppauge HVR850                         (au0828)        [2040:7240]
   3 -> DViCO FusionHDTV USB                     (au0828)        [0fe9:d620]
   4 -> Hauppauge HVR950Q rev xxF8               (au0828)        [2040:7201,2040:7211,2040:7281]
index 30bbdda68d03bc17dd91b215764ef3aa71f5e614..691d2f37dc57f49267f263d89bb11e985ada7cf7 100644 (file)
@@ -75,3 +75,4 @@ tuner=73 - Samsung TCPG 6121P30A
 tuner=75 - Philips TEA5761 FM Radio
 tuner=76 - Xceive 5000 tuner
 tuner=77 - TCL tuner MF02GIP-5N-E
+tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
index 165c871ba9af0211e0c939e0bc2212750d4bf39f..bcc079c282dd33112a48b250ec227610c39697cb 100644 (file)
@@ -137,6 +137,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
 
        return (void*) vaddr;
 }
+EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
 
 struct page *kmap_atomic_to_page(void *ptr)
 {
index 610d6fd5bb505a0dc568935477a9159a11a4ae1b..9097500de5f466249417c13cb4a4b804679726a5 100644 (file)
@@ -6,7 +6,7 @@
 #
 menuconfig DRM
        tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
-       depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG
+       depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && SHMEM
        help
          Kernel-level support for the Direct Rendering Infrastructure (DRI)
          introduced in XFree86 4.0. If you say Y here, you need to select
@@ -87,6 +87,7 @@ config DRM_MGA
 config DRM_SIS
        tristate "SiS video cards"
        depends on DRM && AGP
+       depends on FB_SIS || FB_SIS=n
        help
          Choose this option if you have a SiS 630 or compatible video
           chipset. If M is selected the module will be called sis. AGP
index e9f9a97ae00a9fb188920cf5c5be1751cfae4484..74da99495e21d8cbce22853d5e943d2b5e37e647 100644 (file)
@@ -4,8 +4,9 @@
 
 ccflags-y := -Iinclude/drm
 
-drm-y       := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
-               drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
+drm-y       := drm_auth.o drm_bufs.o drm_cache.o \
+               drm_context.o drm_dma.o drm_drawable.o \
+               drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
                drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
                drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
                drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
index aefa5ac4c0b1fdcec03418ca610e7ae781d1c8c4..3d33b8252b58dadb1a0102824889a9abb482bf2d 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "drmP.h"
 #include <linux/module.h>
+#include <asm/agp.h>
 
 #if __OS_HAS_AGP
 
@@ -452,4 +453,53 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
        return agp_unbind_memory(handle);
 }
 
-#endif                         /* __OS_HAS_AGP */
+/**
+ * Binds a collection of pages into AGP memory at the given offset, returning
+ * the AGP memory structure containing them.
+ *
+ * No reference is held on the pages during this time -- it is up to the
+ * caller to handle that.
+ */
+DRM_AGP_MEM *
+drm_agp_bind_pages(struct drm_device *dev,
+                  struct page **pages,
+                  unsigned long num_pages,
+                  uint32_t gtt_offset,
+                  u32 type)
+{
+       DRM_AGP_MEM *mem;
+       int ret, i;
+
+       DRM_DEBUG("\n");
+
+       mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
+                                     type);
+       if (mem == NULL) {
+               DRM_ERROR("Failed to allocate memory for %ld pages\n",
+                         num_pages);
+               return NULL;
+       }
+
+       for (i = 0; i < num_pages; i++)
+               mem->memory[i] = phys_to_gart(page_to_phys(pages[i]));
+       mem->page_count = num_pages;
+
+       mem->is_flushed = true;
+       ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
+       if (ret != 0) {
+               DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
+               agp_free_memory(mem);
+               return NULL;
+       }
+
+       return mem;
+}
+EXPORT_SYMBOL(drm_agp_bind_pages);
+
+void drm_agp_chipset_flush(struct drm_device *dev)
+{
+       agp_flush_chipset(dev->agp->bridge);
+}
+EXPORT_SYMBOL(drm_agp_chipset_flush);
+
+#endif /* __OS_HAS_AGP */
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
new file mode 100644 (file)
index 0000000..0e994a0
--- /dev/null
@@ -0,0 +1,69 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+
+#if defined(CONFIG_X86)
+static void
+drm_clflush_page(struct page *page)
+{
+       uint8_t *page_virtual;
+       unsigned int i;
+
+       if (unlikely(page == NULL))
+               return;
+
+       page_virtual = kmap_atomic(page, KM_USER0);
+       for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
+               clflush(page_virtual + i);
+       kunmap_atomic(page_virtual, KM_USER0);
+}
+#endif
+
+void
+drm_clflush_pages(struct page *pages[], unsigned long num_pages)
+{
+
+#if defined(CONFIG_X86)
+       if (cpu_has_clflush) {
+               unsigned long i;
+
+               mb();
+               for (i = 0; i < num_pages; ++i)
+                       drm_clflush_page(*pages++);
+               mb();
+
+               return;
+       }
+
+       wbinvd();
+#endif
+}
+EXPORT_SYMBOL(drm_clflush_pages);
index 452c2d866ec566e7355d065f7065518444ae289f..96f416afc3f69b474fe685014573435600b85f4c 100644 (file)
@@ -116,7 +116,13 @@ static struct drm_ioctl_desc drm_ioctls[] = {
 
        DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
 
+       DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
+
        DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
 };
 
 #define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )
index 851a53f1accefa0ee1d84772a6ec5a182d609969..0d46627663b1e93e0d50729b41162ca32c5af1a0 100644 (file)
@@ -246,7 +246,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        memset(priv, 0, sizeof(*priv));
        filp->private_data = priv;
        priv->filp = filp;
-       priv->uid = current->euid;
+       priv->uid = current_euid();
        priv->pid = task_pid_nr(current);
        priv->minor = idr_find(&drm_minors_idr, minor_id);
        priv->ioctl_count = 0;
@@ -256,6 +256,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
        INIT_LIST_HEAD(&priv->lhead);
 
+       if (dev->driver->driver_features & DRIVER_GEM)
+               drm_gem_open(dev, priv);
+
        if (dev->driver->open) {
                ret = dev->driver->open(dev, priv);
                if (ret < 0)
@@ -400,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp)
                dev->driver->reclaim_buffers(dev, file_priv);
        }
 
+       if (dev->driver->driver_features & DRIVER_GEM)
+               drm_gem_release(dev, file_priv);
+
        drm_fasync(-1, filp, 0);
 
        mutex_lock(&dev->ctxlist_mutex);
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
new file mode 100644 (file)
index 0000000..ccd1afd
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * Copyright Â© 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include "drmP.h"
+
+/** @file drm_gem.c
+ *
+ * This file provides some of the base ioctls and library routines for
+ * the graphics memory manager implemented by each device driver.
+ *
+ * Because various devices have different requirements in terms of
+ * synchronization and migration strategies, implementing that is left up to
+ * the driver, and all that the general API provides should be generic --
+ * allocating objects, reading/writing data with the cpu, freeing objects.
+ * Even there, platform-dependent optimizations for reading/writing data with
+ * the CPU mean we'll likely hook those out to driver-specific calls.  However,
+ * the DRI2 implementation wants to have at least allocate/mmap be generic.
+ *
+ * The goal was to have swap-backed object allocation managed through
+ * struct file.  However, file descriptors as handles to a struct file have
+ * two major failings:
+ * - Process limits prevent more than 1024 or so being used at a time by
+ *   default.
+ * - Inability to allocate high fds will aggravate the X Server's select()
+ *   handling, and likely that of many GL client applications as well.
+ *
+ * This led to a plan of using our own integer IDs (called handles, following
+ * DRM terminology) to mimic fds, and implement the fd syscalls we need as
+ * ioctls.  The objects themselves will still include the struct file so
+ * that we can transition to fds if the required kernel infrastructure shows
+ * up at a later date, and as our interface with shmfs for memory allocation.
+ */
+
+/**
+ * Initialize the GEM device fields
+ */
+
+int
+drm_gem_init(struct drm_device *dev)
+{
+       spin_lock_init(&dev->object_name_lock);
+       idr_init(&dev->object_name_idr);
+       atomic_set(&dev->object_count, 0);
+       atomic_set(&dev->object_memory, 0);
+       atomic_set(&dev->pin_count, 0);
+       atomic_set(&dev->pin_memory, 0);
+       atomic_set(&dev->gtt_count, 0);
+       atomic_set(&dev->gtt_memory, 0);
+       return 0;
+}
+
+/**
+ * Allocate a GEM object of the specified size with shmfs backing store
+ */
+struct drm_gem_object *
+drm_gem_object_alloc(struct drm_device *dev, size_t size)
+{
+       struct drm_gem_object *obj;
+
+       BUG_ON((size & (PAGE_SIZE - 1)) != 0);
+
+       obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);
+
+       obj->dev = dev;
+       obj->filp = shmem_file_setup("drm mm object", size, 0);
+       if (IS_ERR(obj->filp)) {
+               kfree(obj);
+               return NULL;
+       }
+
+       kref_init(&obj->refcount);
+       kref_init(&obj->handlecount);
+       obj->size = size;
+       if (dev->driver->gem_init_object != NULL &&
+           dev->driver->gem_init_object(obj) != 0) {
+               fput(obj->filp);
+               kfree(obj);
+               return NULL;
+       }
+       atomic_inc(&dev->object_count);
+       atomic_add(obj->size, &dev->object_memory);
+       return obj;
+}
+EXPORT_SYMBOL(drm_gem_object_alloc);
+
+/**
+ * Removes the mapping from handle to filp for this object.
+ */
+static int
+drm_gem_handle_delete(struct drm_file *filp, int handle)
+{
+       struct drm_device *dev;
+       struct drm_gem_object *obj;
+
+       /* This is gross. The idr system doesn't let us try a delete and
+        * return an error code.  It just spews if you fail at deleting.
+        * So, we have to grab a lock around finding the object and then
+        * doing the delete on it and dropping the refcount, or the user
+        * could race us to double-decrement the refcount and cause a
+        * use-after-free later.  Given the frequency of our handle lookups,
+        * we may want to use ida for number allocation and a hash table
+        * for the pointers, anyway.
+        */
+       spin_lock(&filp->table_lock);
+
+       /* Check if we currently have a reference on the object */
+       obj = idr_find(&filp->object_idr, handle);
+       if (obj == NULL) {
+               spin_unlock(&filp->table_lock);
+               return -EINVAL;
+       }
+       dev = obj->dev;
+
+       /* Release reference and decrement refcount. */
+       idr_remove(&filp->object_idr, handle);
+       spin_unlock(&filp->table_lock);
+
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_handle_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+/**
+ * Create a handle for this object. This adds a handle reference
+ * to the object, which includes a regular reference count. Callers
+ * will likely want to dereference the object afterwards.
+ */
+int
+drm_gem_handle_create(struct drm_file *file_priv,
+                      struct drm_gem_object *obj,
+                      int *handlep)
+{
+       int     ret;
+
+       /*
+        * Get the user-visible handle using idr.
+        */
+again:
+       /* ensure there is space available to allocate a handle */
+       if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
+               return -ENOMEM;
+
+       /* do the allocation under our spinlock */
+       spin_lock(&file_priv->table_lock);
+       ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep);
+       spin_unlock(&file_priv->table_lock);
+       if (ret == -EAGAIN)
+               goto again;
+
+       if (ret != 0)
+               return ret;
+
+       drm_gem_object_handle_reference(obj);
+       return 0;
+}
+EXPORT_SYMBOL(drm_gem_handle_create);
+
+/** Returns a reference to the object named by the handle. */
+struct drm_gem_object *
+drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
+                     int handle)
+{
+       struct drm_gem_object *obj;
+
+       spin_lock(&filp->table_lock);
+
+       /* Check if we currently have a reference on the object */
+       obj = idr_find(&filp->object_idr, handle);
+       if (obj == NULL) {
+               spin_unlock(&filp->table_lock);
+               return NULL;
+       }
+
+       drm_gem_object_reference(obj);
+
+       spin_unlock(&filp->table_lock);
+
+       return obj;
+}
+EXPORT_SYMBOL(drm_gem_object_lookup);
+
+/**
+ * Releases the handle to an mm object.
+ */
+int
+drm_gem_close_ioctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       struct drm_gem_close *args = data;
+       int ret;
+
+       if (!(dev->driver->driver_features & DRIVER_GEM))
+               return -ENODEV;
+
+       ret = drm_gem_handle_delete(file_priv, args->handle);
+
+       return ret;
+}
+
+/**
+ * Create a global name for an object, returning the name.
+ *
+ * Note that the name does not hold a reference; when the object
+ * is freed, the name goes away.
+ */
+int
+drm_gem_flink_ioctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       struct drm_gem_flink *args = data;
+       struct drm_gem_object *obj;
+       int ret;
+
+       if (!(dev->driver->driver_features & DRIVER_GEM))
+               return -ENODEV;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EBADF;
+
+again:
+       if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0)
+               return -ENOMEM;
+
+       spin_lock(&dev->object_name_lock);
+       if (obj->name) {
+               args->name = obj->name;
+               spin_unlock(&dev->object_name_lock);
+               return 0;
+       }
+       ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
+                                &obj->name);
+       spin_unlock(&dev->object_name_lock);
+       if (ret == -EAGAIN)
+               goto again;
+
+       if (ret != 0) {
+               mutex_lock(&dev->struct_mutex);
+               drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       /*
+        * Leave the reference from the lookup around as the
+        * name table now holds one
+        */
+       args->name = (uint64_t) obj->name;
+
+       return 0;
+}
+
+/**
+ * Open an object using the global name, returning a handle and the size.
+ *
+ * This handle (of course) holds a reference to the object, so the object
+ * will not go away until the handle is deleted.
+ */
+int
+drm_gem_open_ioctl(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv)
+{
+       struct drm_gem_open *args = data;
+       struct drm_gem_object *obj;
+       int ret;
+       int handle;
+
+       if (!(dev->driver->driver_features & DRIVER_GEM))
+               return -ENODEV;
+
+       spin_lock(&dev->object_name_lock);
+       obj = idr_find(&dev->object_name_idr, (int) args->name);
+       if (obj)
+               drm_gem_object_reference(obj);
+       spin_unlock(&dev->object_name_lock);
+       if (!obj)
+               return -ENOENT;
+
+       ret = drm_gem_handle_create(file_priv, obj, &handle);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       args->handle = handle;
+       args->size = obj->size;
+
+       return 0;
+}
+
+/**
+ * Called at device open time, sets up the structure for handling refcounting
+ * of mm objects.
+ */
+void
+drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
+{
+       idr_init(&file_private->object_idr);
+       spin_lock_init(&file_private->table_lock);
+}
+
+/**
+ * Called at device close to release the file's
+ * handle references on objects.
+ */
+static int
+drm_gem_object_release_handle(int id, void *ptr, void *data)
+{
+       struct drm_gem_object *obj = ptr;
+
+       drm_gem_object_handle_unreference(obj);
+
+       return 0;
+}
+
+/**
+ * Called at close time when the filp is going away.
+ *
+ * Releases any remaining references on objects by this filp.
+ */
+void
+drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
+{
+       mutex_lock(&dev->struct_mutex);
+       idr_for_each(&file_private->object_idr,
+                    &drm_gem_object_release_handle, NULL);
+
+       idr_destroy(&file_private->object_idr);
+       mutex_unlock(&dev->struct_mutex);
+}
+
+/**
+ * Called after the last reference to the object has been lost.
+ *
+ * Frees the object
+ */
+void
+drm_gem_object_free(struct kref *kref)
+{
+       struct drm_gem_object *obj = (struct drm_gem_object *) kref;
+       struct drm_device *dev = obj->dev;
+
+       BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+
+       if (dev->driver->gem_free_object != NULL)
+               dev->driver->gem_free_object(obj);
+
+       fput(obj->filp);
+       atomic_dec(&dev->object_count);
+       atomic_sub(obj->size, &dev->object_memory);
+       kfree(obj);
+}
+EXPORT_SYMBOL(drm_gem_object_free);
+
+/**
+ * Called after the last handle to the object has been closed
+ *
+ * Removes any name for the object. Note that this must be
+ * called before drm_gem_object_free or we'll be touching
+ * freed memory
+ */
+void
+drm_gem_object_handle_free(struct kref *kref)
+{
+       struct drm_gem_object *obj = container_of(kref,
+                                                 struct drm_gem_object,
+                                                 handlecount);
+       struct drm_device *dev = obj->dev;
+
+       /* Remove any name for this object */
+       spin_lock(&dev->object_name_lock);
+       if (obj->name) {
+               idr_remove(&dev->object_name_idr, obj->name);
+               spin_unlock(&dev->object_name_lock);
+               /*
+                * The object name held a reference to this object, drop
+                * that now.
+                */
+               drm_gem_object_unreference(obj);
+       } else
+               spin_unlock(&dev->object_name_lock);
+
+}
+EXPORT_SYMBOL(drm_gem_object_handle_free);
+
index 53f0e5af1cc82fd2379b8a48db2afe0ea8d60298..4091b9e291f918be5f23a8391b48aa391d498f9c 100644 (file)
@@ -63,7 +63,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
            p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
                return -EINVAL;
 
-       p->irq = dev->irq;
+       p->irq = dev->pdev->irq;
 
        DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
                  p->irq);
@@ -71,25 +71,137 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
        return 0;
 }
 
+static void vblank_disable_fn(unsigned long arg)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       unsigned long irqflags;
+       int i;
+
+       if (!dev->vblank_disable_allowed)
+               return;
+
+       for (i = 0; i < dev->num_crtcs; i++) {
+               spin_lock_irqsave(&dev->vbl_lock, irqflags);
+               if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
+                   dev->vblank_enabled[i]) {
+                       DRM_DEBUG("disabling vblank on crtc %d\n", i);
+                       dev->last_vblank[i] =
+                               dev->driver->get_vblank_counter(dev, i);
+                       dev->driver->disable_vblank(dev, i);
+                       dev->vblank_enabled[i] = 0;
+               }
+               spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+       }
+}
+
+static void drm_vblank_cleanup(struct drm_device *dev)
+{
+       /* Bail if the driver didn't call drm_vblank_init() */
+       if (dev->num_crtcs == 0)
+               return;
+
+       del_timer(&dev->vblank_disable_timer);
+
+       vblank_disable_fn((unsigned long)dev);
+
+       drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
+                DRM_MEM_DRIVER);
+       drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
+                DRM_MEM_DRIVER);
+       drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
+                dev->num_crtcs, DRM_MEM_DRIVER);
+       drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
+                dev->num_crtcs, DRM_MEM_DRIVER);
+       drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) *
+                dev->num_crtcs, DRM_MEM_DRIVER);
+       drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
+                DRM_MEM_DRIVER);
+       drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) *
+                dev->num_crtcs, DRM_MEM_DRIVER);
+
+       dev->num_crtcs = 0;
+}
+
+int drm_vblank_init(struct drm_device *dev, int num_crtcs)
+{
+       int i, ret = -ENOMEM;
+
+       setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
+                   (unsigned long)dev);
+       spin_lock_init(&dev->vbl_lock);
+       atomic_set(&dev->vbl_signal_pending, 0);
+       dev->num_crtcs = num_crtcs;
+
+       dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs,
+                                  DRM_MEM_DRIVER);
+       if (!dev->vbl_queue)
+               goto err;
+
+       dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
+                                 DRM_MEM_DRIVER);
+       if (!dev->vbl_sigs)
+               goto err;
+
+       dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
+                                     DRM_MEM_DRIVER);
+       if (!dev->_vblank_count)
+               goto err;
+
+       dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs,
+                                        DRM_MEM_DRIVER);
+       if (!dev->vblank_refcount)
+               goto err;
+
+       dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int),
+                                        DRM_MEM_DRIVER);
+       if (!dev->vblank_enabled)
+               goto err;
+
+       dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
+       if (!dev->last_vblank)
+               goto err;
+
+       dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int),
+                                        DRM_MEM_DRIVER);
+       if (!dev->vblank_inmodeset)
+               goto err;
+
+       /* Zero per-crtc vblank stuff */
+       for (i = 0; i < num_crtcs; i++) {
+               init_waitqueue_head(&dev->vbl_queue[i]);
+               INIT_LIST_HEAD(&dev->vbl_sigs[i]);
+               atomic_set(&dev->_vblank_count[i], 0);
+               atomic_set(&dev->vblank_refcount[i], 0);
+       }
+
+       dev->vblank_disable_allowed = 0;
+
+       return 0;
+
+err:
+       drm_vblank_cleanup(dev);
+       return ret;
+}
+EXPORT_SYMBOL(drm_vblank_init);
+
 /**
  * Install IRQ handler.
  *
  * \param dev DRM device.
- * \param irq IRQ number.
  *
- * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
+ * Initializes the IRQ related data. Installs the handler, calling the driver
  * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
  * before and after the installation.
  */
-static int drm_irq_install(struct drm_device * dev)
+int drm_irq_install(struct drm_device *dev)
 {
-       int ret;
+       int ret = 0;
        unsigned long sh_flags = 0;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
-       if (dev->irq == 0)
+       if (dev->pdev->irq == 0)
                return -EINVAL;
 
        mutex_lock(&dev->struct_mutex);
@@ -107,18 +219,7 @@ static int drm_irq_install(struct drm_device * dev)
        dev->irq_enabled = 1;
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("irq=%d\n", dev->irq);
-
-       if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
-               init_waitqueue_head(&dev->vbl_queue);
-
-               spin_lock_init(&dev->vbl_lock);
-
-               INIT_LIST_HEAD(&dev->vbl_sigs);
-               INIT_LIST_HEAD(&dev->vbl_sigs2);
-
-               dev->vbl_pending = 0;
-       }
+       DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
        /* Before installing handler */
        dev->driver->irq_preinstall(dev);
@@ -127,8 +228,9 @@ static int drm_irq_install(struct drm_device * dev)
        if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
                sh_flags = IRQF_SHARED;
 
-       ret = request_irq(dev->irq, dev->driver->irq_handler,
+       ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler,
                          sh_flags, dev->devname, dev);
+
        if (ret < 0) {
                mutex_lock(&dev->struct_mutex);
                dev->irq_enabled = 0;
@@ -137,10 +239,16 @@ static int drm_irq_install(struct drm_device * dev)
        }
 
        /* After installing handler */
-       dev->driver->irq_postinstall(dev);
+       ret = dev->driver->irq_postinstall(dev);
+       if (ret < 0) {
+               mutex_lock(&dev->struct_mutex);
+               dev->irq_enabled = 0;
+               mutex_unlock(&dev->struct_mutex);
+       }
 
-       return 0;
+       return ret;
 }
+EXPORT_SYMBOL(drm_irq_install);
 
 /**
  * Uninstall the IRQ handler.
@@ -164,17 +272,18 @@ int drm_irq_uninstall(struct drm_device * dev)
        if (!irq_enabled)
                return -EINVAL;
 
-       DRM_DEBUG("irq=%d\n", dev->irq);
+       DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
        dev->driver->irq_uninstall(dev);
 
-       free_irq(dev->irq, dev);
+       free_irq(dev->pdev->irq, dev);
+
+       drm_vblank_cleanup(dev);
 
        dev->locked_tasklet_func = NULL;
 
        return 0;
 }
-
 EXPORT_SYMBOL(drm_irq_uninstall);
 
 /**
@@ -201,7 +310,7 @@ int drm_control(struct drm_device *dev, void *data,
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
-                   ctl->irq != dev->irq)
+                   ctl->irq != dev->pdev->irq)
                        return -EINVAL;
                return drm_irq_install(dev);
        case DRM_UNINST_HANDLER:
@@ -213,6 +322,174 @@ int drm_control(struct drm_device *dev, void *data,
        }
 }
 
+/**
+ * drm_vblank_count - retrieve "cooked" vblank counter value
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity.
+ */
+u32 drm_vblank_count(struct drm_device *dev, int crtc)
+{
+       return atomic_read(&dev->_vblank_count[crtc]);
+}
+EXPORT_SYMBOL(drm_vblank_count);
+
+/**
+ * drm_update_vblank_count - update the master vblank counter
+ * @dev: DRM device
+ * @crtc: counter to update
+ *
+ * Call back into the driver to update the appropriate vblank counter
+ * (specified by @crtc).  Deal with wraparound, if it occurred, and
+ * update the last read value so we can deal with wraparound on the next
+ * call if necessary.
+ *
+ * Only necessary when going from off->on, to account for frames we
+ * didn't get an interrupt for.
+ *
+ * Note: caller must hold dev->vbl_lock since this reads & writes
+ * device vblank fields.
+ */
+static void drm_update_vblank_count(struct drm_device *dev, int crtc)
+{
+       u32 cur_vblank, diff;
+
+       /*
+        * Interrupts were disabled prior to this call, so deal with counter
+        * wrap if needed.
+        * NOTE!  It's possible we lost a full dev->max_vblank_count events
+        * here if the register is small or we had vblank interrupts off for
+        * a long time.
+        */
+       cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+       diff = cur_vblank - dev->last_vblank[crtc];
+       if (cur_vblank < dev->last_vblank[crtc]) {
+               diff += dev->max_vblank_count;
+
+               DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
+                         crtc, dev->last_vblank[crtc], cur_vblank, diff);
+       }
+
+       DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
+                 crtc, diff);
+
+       atomic_add(diff, &dev->_vblank_count[crtc]);
+}
+
+/**
+ * drm_vblank_get - get a reference count on vblank events
+ * @dev: DRM device
+ * @crtc: which CRTC to own
+ *
+ * Acquire a reference count on vblank events to avoid having them disabled
+ * while in use.
+ *
+ * RETURNS
+ * Zero on success, nonzero on failure.
+ */
+int drm_vblank_get(struct drm_device *dev, int crtc)
+{
+       unsigned long irqflags;
+       int ret = 0;
+
+       spin_lock_irqsave(&dev->vbl_lock, irqflags);
+       /* Going from 0->1 means we have to enable interrupts again */
+       if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 &&
+           !dev->vblank_enabled[crtc]) {
+               ret = dev->driver->enable_vblank(dev, crtc);
+               DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
+               if (ret)
+                       atomic_dec(&dev->vblank_refcount[crtc]);
+               else {
+                       dev->vblank_enabled[crtc] = 1;
+                       drm_update_vblank_count(dev, crtc);
+               }
+       }
+       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_vblank_get);
+
+/**
+ * drm_vblank_put - give up ownership of vblank events
+ * @dev: DRM device
+ * @crtc: which counter to give up
+ *
+ * Release ownership of a given vblank counter, turning off interrupts
+ * if possible.
+ */
+void drm_vblank_put(struct drm_device *dev, int crtc)
+{
+       /* Last user schedules interrupt disable */
+       if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
+               mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
+}
+EXPORT_SYMBOL(drm_vblank_put);
+
+/**
+ * drm_modeset_ctl - handle vblank event counter changes across mode switch
+ * @DRM_IOCTL_ARGS: standard ioctl arguments
+ *
+ * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
+ * ioctls around modesetting so that any lost vblank events are accounted for.
+ *
+ * Generally the counter will reset across mode sets.  If interrupts are
+ * enabled around this call, we don't have to do anything since the counter
+ * will have already been incremented.
+ */
+int drm_modeset_ctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       struct drm_modeset_ctl *modeset = data;
+       unsigned long irqflags;
+       int crtc, ret = 0;
+
+       /* If drm_vblank_init() hasn't been called yet, just no-op */
+       if (!dev->num_crtcs)
+               goto out;
+
+       crtc = modeset->crtc;
+       if (crtc >= dev->num_crtcs) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * To avoid all the problems that might happen if interrupts
+        * were enabled/disabled around or between these calls, we just
+        * have the kernel take a reference on the CRTC (just once though
+        * to avoid corrupting the count if multiple, mismatch calls occur),
+        * so that interrupts remain enabled in the interim.
+        */
+       switch (modeset->cmd) {
+       case _DRM_PRE_MODESET:
+               if (!dev->vblank_inmodeset[crtc]) {
+                       dev->vblank_inmodeset[crtc] = 1;
+                       drm_vblank_get(dev, crtc);
+               }
+               break;
+       case _DRM_POST_MODESET:
+               if (dev->vblank_inmodeset[crtc]) {
+                       spin_lock_irqsave(&dev->vbl_lock, irqflags);
+                       dev->vblank_disable_allowed = 1;
+                       dev->vblank_inmodeset[crtc] = 0;
+                       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+                       drm_vblank_put(dev, crtc);
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+out:
+       return ret;
+}
+
 /**
  * Wait for VBLANK.
  *
@@ -232,14 +509,14 @@ int drm_control(struct drm_device *dev, void *data,
  *
  * If a signal is not requested, then calls vblank_wait().
  */
-int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int drm_wait_vblank(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
 {
        union drm_wait_vblank *vblwait = data;
-       struct timeval now;
        int ret = 0;
-       unsigned int flags, seq;
+       unsigned int flags, seq, crtc;
 
-       if ((!dev->irq) || (!dev->irq_enabled))
+       if ((!dev->pdev->irq) || (!dev->irq_enabled))
                return -EINVAL;
 
        if (vblwait->request.type &
@@ -251,13 +528,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
        }
 
        flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
+       crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
 
-       if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
-                                   DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
+       if (crtc >= dev->num_crtcs)
                return -EINVAL;
 
-       seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
-                         : &dev->vbl_received);
+       ret = drm_vblank_get(dev, crtc);
+       if (ret) {
+               DRM_ERROR("failed to acquire vblank counter, %d\n", ret);
+               return ret;
+       }
+       seq = drm_vblank_count(dev, crtc);
 
        switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
        case _DRM_VBLANK_RELATIVE:
@@ -266,7 +547,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
        case _DRM_VBLANK_ABSOLUTE:
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto done;
        }
 
        if ((flags & _DRM_VBLANK_NEXTONMISS) &&
@@ -276,8 +558,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
 
        if (flags & _DRM_VBLANK_SIGNAL) {
                unsigned long irqflags;
-               struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
-                                     ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+               struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
                struct drm_vbl_sig *vbl_sig;
 
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -298,22 +579,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
                        }
                }
 
-               if (dev->vbl_pending >= 100) {
+               if (atomic_read(&dev->vbl_signal_pending) >= 100) {
                        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-                       return -EBUSY;
+                       ret = -EBUSY;
+                       goto done;
                }
 
-               dev->vbl_pending++;
-
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
-               if (!
-                   (vbl_sig =
-                    drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
-                       return -ENOMEM;
+               vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
+                                    DRM_MEM_DRIVER);
+               if (!vbl_sig) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               ret = drm_vblank_get(dev, crtc);
+               if (ret) {
+                       drm_free(vbl_sig, sizeof(struct drm_vbl_sig),
+                                DRM_MEM_DRIVER);
+                       return ret;
                }
 
-               memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
+               atomic_inc(&dev->vbl_signal_pending);
 
                vbl_sig->sequence = vblwait->request.sequence;
                vbl_sig->info.si_signo = vblwait->request.signal;
@@ -327,20 +615,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
 
                vblwait->reply.sequence = seq;
        } else {
-               if (flags & _DRM_VBLANK_SECONDARY) {
-                       if (dev->driver->vblank_wait2)
-                               ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
-               } else if (dev->driver->vblank_wait)
-                       ret =
-                           dev->driver->vblank_wait(dev,
-                                                    &vblwait->request.sequence);
-
-               do_gettimeofday(&now);
-               vblwait->reply.tval_sec = now.tv_sec;
-               vblwait->reply.tval_usec = now.tv_usec;
+               DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
+                         vblwait->request.sequence, crtc);
+               DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
+                           ((drm_vblank_count(dev, crtc)
+                             - vblwait->request.sequence) <= (1 << 23)));
+
+               if (ret != -EINTR) {
+                       struct timeval now;
+
+                       do_gettimeofday(&now);
+
+                       vblwait->reply.tval_sec = now.tv_sec;
+                       vblwait->reply.tval_usec = now.tv_usec;
+                       vblwait->reply.sequence = drm_vblank_count(dev, crtc);
+                       DRM_DEBUG("returning %d to client\n",
+                                 vblwait->reply.sequence);
+               } else {
+                       DRM_DEBUG("vblank wait interrupted by signal\n");
+               }
        }
 
-      done:
+done:
+       drm_vblank_put(dev, crtc);
        return ret;
 }
 
@@ -348,44 +645,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
  * Send the VBLANK signals.
  *
  * \param dev DRM device.
+ * \param crtc CRTC where the vblank event occurred
  *
  * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
  *
  * If a signal is not requested, then calls vblank_wait().
  */
-void drm_vbl_send_signals(struct drm_device * dev)
+static void drm_vbl_send_signals(struct drm_device *dev, int crtc)
 {
+       struct drm_vbl_sig *vbl_sig, *tmp;
+       struct list_head *vbl_sigs;
+       unsigned int vbl_seq;
        unsigned long flags;
-       int i;
 
        spin_lock_irqsave(&dev->vbl_lock, flags);
 
-       for (i = 0; i < 2; i++) {
-               struct drm_vbl_sig *vbl_sig, *tmp;
-               struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
-               unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
-                                                  &dev->vbl_received);
+       vbl_sigs = &dev->vbl_sigs[crtc];
+       vbl_seq = drm_vblank_count(dev, crtc);
 
-               list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
-                       if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
-                               vbl_sig->info.si_code = vbl_seq;
-                               send_sig_info(vbl_sig->info.si_signo,
-                                             &vbl_sig->info, vbl_sig->task);
+       list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
+           if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
+               vbl_sig->info.si_code = vbl_seq;
+               send_sig_info(vbl_sig->info.si_signo,
+                             &vbl_sig->info, vbl_sig->task);
 
-                               list_del(&vbl_sig->head);
-
-                               drm_free(vbl_sig, sizeof(*vbl_sig),
-                                        DRM_MEM_DRIVER);
+               list_del(&vbl_sig->head);
 
-                               dev->vbl_pending--;
-                       }
-               }
+               drm_free(vbl_sig, sizeof(*vbl_sig),
+                        DRM_MEM_DRIVER);
+               atomic_dec(&dev->vbl_signal_pending);
+               drm_vblank_put(dev, crtc);
+           }
        }
 
        spin_unlock_irqrestore(&dev->vbl_lock, flags);
 }
 
-EXPORT_SYMBOL(drm_vbl_send_signals);
+/**
+ * drm_handle_vblank - handle a vblank event
+ * @dev: DRM device
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their vblank interrupt handlers to
+ * update the vblank counter and send any signals that may be pending.
+ */
+void drm_handle_vblank(struct drm_device *dev, int crtc)
+{
+       atomic_inc(&dev->_vblank_count[crtc]);
+       DRM_WAKEUP(&dev->vbl_queue[crtc]);
+       drm_vbl_send_signals(dev, crtc);
+}
+EXPORT_SYMBOL(drm_handle_vblank);
 
 /**
  * Tasklet wrapper function.
index 0177012845c60cc951380d4419f3dbb9a736b8be..803bc9e7ce3c8639f026d3479b5ec2217a84802d 100644 (file)
@@ -133,6 +133,7 @@ int drm_free_agp(DRM_AGP_MEM * handle, int pages)
 {
        return drm_agp_free_memory(handle) ? 0 : -EINVAL;
 }
+EXPORT_SYMBOL(drm_free_agp);
 
 /** Wrapper around agp_bind_memory() */
 int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
@@ -145,6 +146,7 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
 {
        return drm_agp_unbind_memory(handle);
 }
+EXPORT_SYMBOL(drm_unbind_agp);
 
 #else  /*  __OS_HAS_AGP  */
 static inline void *agp_remap(unsigned long offset, unsigned long size,
index dcff9e9b52e327016ee53590a98ea8b21d44d362..217ad7dc70765ef174ad159c8e769fa10392c531 100644 (file)
@@ -169,6 +169,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
 
        return child;
 }
+EXPORT_SYMBOL(drm_mm_get_block);
 
 /*
  * Put a block. Merge with the previous and / or next block if they are free.
@@ -217,6 +218,7 @@ void drm_mm_put_block(struct drm_mm_node * cur)
                drm_free(cur, sizeof(*cur), DRM_MEM_MM);
        }
 }
+EXPORT_SYMBOL(drm_mm_put_block);
 
 struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
                                  unsigned long size,
@@ -265,6 +267,7 @@ int drm_mm_clean(struct drm_mm * mm)
 
        return (head->next->next == head);
 }
+EXPORT_SYMBOL(drm_mm_search_free);
 
 int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 {
@@ -273,7 +276,7 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 
        return drm_mm_create_tail_node(mm, start, size);
 }
-
+EXPORT_SYMBOL(drm_mm_init);
 
 void drm_mm_takedown(struct drm_mm * mm)
 {
index 93b1e0475c93bef525c06ea89785dded441d4f39..d490db4c0de06a11ea3de7579681f3b76177c2a5 100644 (file)
@@ -49,6 +49,10 @@ static int drm_queues_info(char *buf, char **start, off_t offset,
                           int request, int *eof, void *data);
 static int drm_bufs_info(char *buf, char **start, off_t offset,
                         int request, int *eof, void *data);
+static int drm_gem_name_info(char *buf, char **start, off_t offset,
+                            int request, int *eof, void *data);
+static int drm_gem_object_info(char *buf, char **start, off_t offset,
+                              int request, int *eof, void *data);
 #if DRM_DEBUG_CODE
 static int drm_vma_info(char *buf, char **start, off_t offset,
                        int request, int *eof, void *data);
@@ -60,13 +64,16 @@ static int drm_vma_info(char *buf, char **start, off_t offset,
 static struct drm_proc_list {
        const char *name;       /**< file name */
        int (*f) (char *, char **, off_t, int, int *, void *);          /**< proc callback*/
+       u32 driver_features; /**< Required driver features for this entry */
 } drm_proc_list[] = {
-       {"name", drm_name_info},
-       {"mem", drm_mem_info},
-       {"vm", drm_vm_info},
-       {"clients", drm_clients_info},
-       {"queues", drm_queues_info},
-       {"bufs", drm_bufs_info},
+       {"name", drm_name_info, 0},
+       {"mem", drm_mem_info, 0},
+       {"vm", drm_vm_info, 0},
+       {"clients", drm_clients_info, 0},
+       {"queues", drm_queues_info, 0},
+       {"bufs", drm_bufs_info, 0},
+       {"gem_names", drm_gem_name_info, DRIVER_GEM},
+       {"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
        {"vma", drm_vma_info},
 #endif
@@ -90,8 +97,9 @@ static struct drm_proc_list {
 int drm_proc_init(struct drm_minor *minor, int minor_id,
                  struct proc_dir_entry *root)
 {
+       struct drm_device *dev = minor->dev;
        struct proc_dir_entry *ent;
-       int i, j;
+       int i, j, ret;
        char name[64];
 
        sprintf(name, "%d", minor_id);
@@ -102,23 +110,42 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
        }
 
        for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+               u32 features = drm_proc_list[i].driver_features;
+
+               if (features != 0 &&
+                   (dev->driver->driver_features & features) != features)
+                       continue;
+
                ent = create_proc_entry(drm_proc_list[i].name,
                                        S_IFREG | S_IRUGO, minor->dev_root);
                if (!ent) {
                        DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
                                  name, drm_proc_list[i].name);
-                       for (j = 0; j < i; j++)
-                               remove_proc_entry(drm_proc_list[i].name,
-                                                 minor->dev_root);
-                       remove_proc_entry(name, root);
-                       minor->dev_root = NULL;
-                       return -1;
+                       ret = -1;
+                       goto fail;
                }
                ent->read_proc = drm_proc_list[i].f;
                ent->data = minor;
        }
 
+       if (dev->driver->proc_init) {
+               ret = dev->driver->proc_init(minor);
+               if (ret) {
+                       DRM_ERROR("DRM: Driver failed to initialize "
+                                 "/proc/dri.\n");
+                       goto fail;
+               }
+       }
+
        return 0;
+ fail:
+
+       for (j = 0; j < i; j++)
+               remove_proc_entry(drm_proc_list[i].name,
+                                 minor->dev_root);
+       remove_proc_entry(name, root);
+       minor->dev_root = NULL;
+       return ret;
 }
 
 /**
@@ -133,12 +160,16 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
  */
 int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
 {
+       struct drm_device *dev = minor->dev;
        int i;
        char name[64];
 
        if (!root || !minor->dev_root)
                return 0;
 
+       if (dev->driver->proc_cleanup)
+               dev->driver->proc_cleanup(minor);
+
        for (i = 0; i < DRM_PROC_ENTRIES; i++)
                remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
        sprintf(name, "%d", minor->index);
@@ -480,6 +511,84 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
        return ret;
 }
 
+struct drm_gem_name_info_data {
+       int                     len;
+       char                    *buf;
+       int                     eof;
+};
+
+static int drm_gem_one_name_info(int id, void *ptr, void *data)
+{
+       struct drm_gem_object *obj = ptr;
+       struct drm_gem_name_info_data   *nid = data;
+
+       DRM_INFO("name %d size %d\n", obj->name, obj->size);
+       if (nid->eof)
+               return 0;
+
+       nid->len += sprintf(&nid->buf[nid->len],
+                           "%6d%9d%8d%9d\n",
+                           obj->name, obj->size,
+                           atomic_read(&obj->handlecount.refcount),
+                           atomic_read(&obj->refcount.refcount));
+       if (nid->len > DRM_PROC_LIMIT) {
+               nid->eof = 1;
+               return 0;
+       }
+       return 0;
+}
+
+static int drm_gem_name_info(char *buf, char **start, off_t offset,
+                            int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       struct drm_gem_name_info_data nid;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       nid.len = sprintf(buf, "  name     size handles refcount\n");
+       nid.buf = buf;
+       nid.eof = 0;
+       idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid);
+
+       *start = &buf[offset];
+       *eof = 0;
+       if (nid.len > request + offset)
+               return request;
+       *eof = 1;
+       return nid.len - offset;
+}
+
+static int drm_gem_object_info(char *buf, char **start, off_t offset,
+                              int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       int len = 0;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count));
+       DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory));
+       DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count));
+       DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory));
+       DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory));
+       DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total);
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
 #if DRM_DEBUG_CODE
 
 static int drm__vma_info(char *buf, char **start, off_t offset, int request,
index c2f584f3b46c6b56e5cbba2303b70da5d5fa3067..141e33004a7605c31fcdd7814f5e0fdc767d3e08 100644 (file)
@@ -107,7 +107,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
 #ifdef __alpha__
        dev->hose = pdev->sysdata;
 #endif
-       dev->irq = pdev->irq;
 
        if (drm_ht_create(&dev->map_hash, 12)) {
                return -ENOMEM;
@@ -152,6 +151,15 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
                goto error_out_unreg;
        }
 
+       if (driver->driver_features & DRIVER_GEM) {
+               retcode = drm_gem_init(dev);
+               if (retcode) {
+                       DRM_ERROR("Cannot initialize graphics execution "
+                                 "manager (GEM)\n");
+                       goto error_out_unreg;
+               }
+       }
+
        return 0;
 
       error_out_unreg:
@@ -317,6 +325,7 @@ int drm_put_dev(struct drm_device * dev)
 int drm_put_minor(struct drm_minor **minor_p)
 {
        struct drm_minor *minor = *minor_p;
+
        DRM_DEBUG("release secondary minor %d\n", minor->index);
 
        if (minor->type == DRM_MINOR_LEGACY)
index af211a0ef179defa1b2fb6c8de0d2acb14224389..1611b9bcbe7fd6378bc91a069ff8b8afab0d968b 100644 (file)
@@ -184,7 +184,7 @@ int drm_sysfs_device_add(struct drm_minor *minor)
 err_out_files:
        if (i > 0)
                for (j = 0; j < i; j++)
-                       device_remove_file(&minor->kdev, &device_attrs[i]);
+                       device_remove_file(&minor->kdev, &device_attrs[j]);
        device_unregister(&minor->kdev);
 err_out:
 
index a9e60464df74c0e0f6dac34b9a8b1d269299f7bb..5ba78e4fd2b517c9e6bab2af49c7f6c93fb38b21 100644 (file)
@@ -3,7 +3,12 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm
-i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
+i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_opregion.o \
+          i915_suspend.o \
+         i915_gem.o \
+         i915_gem_debug.o \
+         i915_gem_proc.o \
+         i915_gem_tiling.o
 
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 
index 9ac4720e647b2e2b026791d3d96d24ee2ef226a2..db34780edbb274d9fe44a96463cea638e177bed5 100644 (file)
@@ -40,40 +40,96 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
-       u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+       u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+       u32 last_acthd = I915_READ(acthd_reg);
+       u32 acthd;
+       u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
        int i;
 
-       for (i = 0; i < 10000; i++) {
-               ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+       for (i = 0; i < 100000; i++) {
+               ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+               acthd = I915_READ(acthd_reg);
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->Size;
                if (ring->space >= n)
                        return 0;
 
-               dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+               if (dev_priv->sarea_priv)
+                       dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
                if (ring->head != last_head)
                        i = 0;
+               if (acthd != last_acthd)
+                       i = 0;
 
                last_head = ring->head;
+               last_acthd = acthd;
+               msleep_interruptible(10);
+
        }
 
        return -EBUSY;
 }
 
+/**
+ * Sets up the hardware status page for devices that need a physical address
+ * in the register.
+ */
+static int i915_init_phys_hws(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       /* Program Hardware Status Page */
+       dev_priv->status_page_dmah =
+               drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
+
+       if (!dev_priv->status_page_dmah) {
+               DRM_ERROR("Can not allocate hardware status page\n");
+               return -ENOMEM;
+       }
+       dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
+       dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
+
+       memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+
+       I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
+       DRM_DEBUG("Enabled hardware status page\n");
+       return 0;
+}
+
+/**
+ * Frees the hardware status page, whether it's a physical address or a virtual
+ * address set up by the X Server.
+ */
+static void i915_free_hws(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       if (dev_priv->status_page_dmah) {
+               drm_pci_free(dev, dev_priv->status_page_dmah);
+               dev_priv->status_page_dmah = NULL;
+       }
+
+       if (dev_priv->status_gfx_addr) {
+               dev_priv->status_gfx_addr = 0;
+               drm_core_ioremapfree(&dev_priv->hws_map, dev);
+       }
+
+       /* Need to rewrite hardware status page */
+       I915_WRITE(HWS_PGA, 0x1ffff000);
+}
+
 void i915_kernel_lost_context(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
 
-       ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
-       ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
+       ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+       ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
        ring->space = ring->head - (ring->tail + 8);
        if (ring->space < 0)
                ring->space += ring->Size;
 
-       if (ring->head == ring->tail)
+       if (ring->head == ring->tail && dev_priv->sarea_priv)
                dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
 }
 
@@ -84,28 +140,19 @@ static int i915_dma_cleanup(struct drm_device * dev)
         * may not have been called from userspace and after dev_private
         * is freed, it's too late.
         */
-       if (dev->irq)
+       if (dev->irq_enabled)
                drm_irq_uninstall(dev);
 
        if (dev_priv->ring.virtual_start) {
                drm_core_ioremapfree(&dev_priv->ring.map, dev);
-               dev_priv->ring.virtual_start = 0;
-               dev_priv->ring.map.handle = 0;
+               dev_priv->ring.virtual_start = NULL;
+               dev_priv->ring.map.handle = NULL;
                dev_priv->ring.map.size = 0;
        }
 
-       if (dev_priv->status_page_dmah) {
-               drm_pci_free(dev, dev_priv->status_page_dmah);
-               dev_priv->status_page_dmah = NULL;
-               /* Need to rewrite hardware status page */
-               I915_WRITE(0x02080, 0x1ffff000);
-       }
-
-       if (dev_priv->status_gfx_addr) {
-               dev_priv->status_gfx_addr = 0;
-               drm_core_ioremapfree(&dev_priv->hws_map, dev);
-               I915_WRITE(0x2080, 0x1ffff000);
-       }
+       /* Clear the HWS virtual address at teardown */
+       if (I915_NEED_GFX_HWS(dev))
+               i915_free_hws(dev);
 
        return 0;
 }
@@ -121,34 +168,34 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
                return -EINVAL;
        }
 
-       dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
-       if (!dev_priv->mmio_map) {
-               i915_dma_cleanup(dev);
-               DRM_ERROR("can not find mmio map!\n");
-               return -EINVAL;
-       }
-
        dev_priv->sarea_priv = (drm_i915_sarea_t *)
            ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
 
-       dev_priv->ring.Start = init->ring_start;
-       dev_priv->ring.End = init->ring_end;
-       dev_priv->ring.Size = init->ring_size;
-       dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+       if (init->ring_size != 0) {
+               if (dev_priv->ring.ring_obj != NULL) {
+                       i915_dma_cleanup(dev);
+                       DRM_ERROR("Client tried to initialize ringbuffer in "
+                                 "GEM mode\n");
+                       return -EINVAL;
+               }
 
-       dev_priv->ring.map.offset = init->ring_start;
-       dev_priv->ring.map.size = init->ring_size;
-       dev_priv->ring.map.type = 0;
-       dev_priv->ring.map.flags = 0;
-       dev_priv->ring.map.mtrr = 0;
+               dev_priv->ring.Size = init->ring_size;
+               dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
-       drm_core_ioremap(&dev_priv->ring.map, dev);
+               dev_priv->ring.map.offset = init->ring_start;
+               dev_priv->ring.map.size = init->ring_size;
+               dev_priv->ring.map.type = 0;
+               dev_priv->ring.map.flags = 0;
+               dev_priv->ring.map.mtrr = 0;
 
-       if (dev_priv->ring.map.handle == NULL) {
-               i915_dma_cleanup(dev);
-               DRM_ERROR("can not ioremap virtual address for"
-                         " ring buffer\n");
-               return -ENOMEM;
+               drm_core_ioremap(&dev_priv->ring.map, dev);
+
+               if (dev_priv->ring.map.handle == NULL) {
+                       i915_dma_cleanup(dev);
+                       DRM_ERROR("can not ioremap virtual address for"
+                                 " ring buffer\n");
+                       return -ENOMEM;
+               }
        }
 
        dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -159,34 +206,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
        dev_priv->current_page = 0;
        dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
 
-       /* We are using separate values as placeholders for mechanisms for
-        * private backbuffer/depthbuffer usage.
-        */
-       dev_priv->use_mi_batchbuffer_start = 0;
-       if (IS_I965G(dev)) /* 965 doesn't support older method */
-               dev_priv->use_mi_batchbuffer_start = 1;
-
        /* Allow hardware batchbuffers unless told otherwise.
         */
        dev_priv->allow_batchbuffer = 1;
 
-       /* Program Hardware Status Page */
-       if (!I915_NEED_GFX_HWS(dev)) {
-               dev_priv->status_page_dmah =
-                       drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
-
-               if (!dev_priv->status_page_dmah) {
-                       i915_dma_cleanup(dev);
-                       DRM_ERROR("Can not allocate hardware status page\n");
-                       return -ENOMEM;
-               }
-               dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
-               dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
-
-               memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
-               I915_WRITE(0x02080, dev_priv->dma_status_page);
-       }
-       DRM_DEBUG("Enabled hardware status page\n");
        return 0;
 }
 
@@ -201,11 +224,6 @@ static int i915_dma_resume(struct drm_device * dev)
                return -EINVAL;
        }
 
-       if (!dev_priv->mmio_map) {
-               DRM_ERROR("can not find mmio map!\n");
-               return -EINVAL;
-       }
-
        if (dev_priv->ring.map.handle == NULL) {
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
@@ -220,9 +238,9 @@ static int i915_dma_resume(struct drm_device * dev)
        DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
 
        if (dev_priv->status_gfx_addr != 0)
-               I915_WRITE(0x02080, dev_priv->status_gfx_addr);
+               I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
        else
-               I915_WRITE(0x02080, dev_priv->dma_status_page);
+               I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
        DRM_DEBUG("Enabled hardware status page\n");
 
        return 0;
@@ -367,9 +385,10 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
        return 0;
 }
 
-static int i915_emit_box(struct drm_device * dev,
-                        struct drm_clip_rect __user * boxes,
-                        int i, int DR1, int DR4)
+int
+i915_emit_box(struct drm_device *dev,
+             struct drm_clip_rect __user *boxes,
+             int i, int DR1, int DR4)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_clip_rect box;
@@ -415,14 +434,15 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        RING_LOCALS;
 
-       dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
-
+       dev_priv->counter++;
        if (dev_priv->counter > 0x7FFFFFFFUL)
-               dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+               dev_priv->counter = 0;
+       if (dev_priv->sarea_priv)
+               dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
        BEGIN_LP_RING(4);
-       OUT_RING(CMD_STORE_DWORD_IDX);
-       OUT_RING(20);
+       OUT_RING(MI_STORE_DWORD_INDEX);
+       OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
        OUT_RING(dev_priv->counter);
        OUT_RING(0);
        ADVANCE_LP_RING();
@@ -486,7 +506,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
                                return ret;
                }
 
-               if (dev_priv->use_mi_batchbuffer_start) {
+               if (!IS_I830(dev) && !IS_845G(dev)) {
                        BEGIN_LP_RING(2);
                        if (IS_I965G(dev)) {
                                OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
@@ -516,6 +536,9 @@ static int i915_dispatch_flip(struct drm_device * dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        RING_LOCALS;
 
+       if (!dev_priv->sarea_priv)
+               return -EINVAL;
+
        DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
                  __func__,
                  dev_priv->current_page,
@@ -524,7 +547,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
        i915_kernel_lost_context(dev);
 
        BEGIN_LP_RING(2);
-       OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
+       OUT_RING(MI_FLUSH | MI_READ_FLUSH);
        OUT_RING(0);
        ADVANCE_LP_RING();
 
@@ -549,8 +572,8 @@ static int i915_dispatch_flip(struct drm_device * dev)
        dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
 
        BEGIN_LP_RING(4);
-       OUT_RING(CMD_STORE_DWORD_IDX);
-       OUT_RING(20);
+       OUT_RING(MI_STORE_DWORD_INDEX);
+       OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
        OUT_RING(dev_priv->counter);
        OUT_RING(0);
        ADVANCE_LP_RING();
@@ -570,9 +593,15 @@ static int i915_quiescent(struct drm_device * dev)
 static int i915_flush_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       int ret;
+
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_quiescent(dev);
+       mutex_unlock(&dev->struct_mutex);
 
-       return i915_quiescent(dev);
+       return ret;
 }
 
 static int i915_batchbuffer(struct drm_device *dev, void *data,
@@ -593,16 +622,19 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
        DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
                  batch->start, batch->used, batch->num_cliprects);
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
                                                       batch->num_cliprects *
                                                       sizeof(struct drm_clip_rect)))
                return -EFAULT;
 
+       mutex_lock(&dev->struct_mutex);
        ret = i915_dispatch_batchbuffer(dev, batch);
+       mutex_unlock(&dev->struct_mutex);
 
-       sarea_priv->last_dispatch = (int)hw_status[5];
+       if (sarea_priv)
+               sarea_priv->last_dispatch = (int)hw_status[5];
        return ret;
 }
 
@@ -619,7 +651,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
        DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
                  cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (cmdbuf->num_cliprects &&
            DRM_VERIFYAREA_READ(cmdbuf->cliprects,
@@ -629,24 +661,33 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
                return -EFAULT;
        }
 
+       mutex_lock(&dev->struct_mutex);
        ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
+       mutex_unlock(&dev->struct_mutex);
        if (ret) {
                DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
                return ret;
        }
 
-       sarea_priv->last_dispatch = (int)hw_status[5];
+       if (sarea_priv)
+               sarea_priv->last_dispatch = (int)hw_status[5];
        return 0;
 }
 
 static int i915_flip_bufs(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
+       int ret;
+
        DRM_DEBUG("%s\n", __func__);
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_dispatch_flip(dev);
+       mutex_unlock(&dev->struct_mutex);
 
-       return i915_dispatch_flip(dev);
+       return ret;
 }
 
 static int i915_getparam(struct drm_device *dev, void *data,
@@ -663,7 +704,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
 
        switch (param->param) {
        case I915_PARAM_IRQ_ACTIVE:
-               value = dev->irq ? 1 : 0;
+               value = dev->pdev->irq ? 1 : 0;
                break;
        case I915_PARAM_ALLOW_BATCHBUFFER:
                value = dev_priv->allow_batchbuffer ? 1 : 0;
@@ -671,6 +712,12 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_LAST_DISPATCH:
                value = READ_BREADCRUMB(dev_priv);
                break;
+       case I915_PARAM_CHIPSET_ID:
+               value = dev->pci_device;
+               break;
+       case I915_PARAM_HAS_GEM:
+               value = 1;
+               break;
        default:
                DRM_ERROR("Unknown parameter %d\n", param->param);
                return -EINVAL;
@@ -697,8 +744,6 @@ static int i915_setparam(struct drm_device *dev, void *data,
 
        switch (param->param) {
        case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
-               if (!IS_I965G(dev))
-                       dev_priv->use_mi_batchbuffer_start = param->value;
                break;
        case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
                dev_priv->tex_lru_log_granularity = param->value;
@@ -749,8 +794,8 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
        dev_priv->hw_status_page = dev_priv->hws_map.handle;
 
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
-       I915_WRITE(0x02080, dev_priv->status_gfx_addr);
-       DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
+       I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
+       DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
                        dev_priv->status_gfx_addr);
        DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
        return 0;
@@ -776,14 +821,38 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        memset(dev_priv, 0, sizeof(drm_i915_private_t));
 
        dev->dev_private = (void *)dev_priv;
+       dev_priv->dev = dev;
 
        /* Add register map (needed for suspend/resume) */
        base = drm_get_resource_start(dev, mmio_bar);
        size = drm_get_resource_len(dev, mmio_bar);
 
-       ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
-                        _DRM_KERNEL | _DRM_DRIVER,
-                        &dev_priv->mmio_map);
+       dev_priv->regs = ioremap(base, size);
+
+       i915_gem_load(dev);
+
+       /* Init HWS */
+       if (!I915_NEED_GFX_HWS(dev)) {
+               ret = i915_init_phys_hws(dev);
+               if (ret != 0)
+                       return ret;
+       }
+
+       /* On the 945G/GM, the chipset reports the MSI capability on the
+        * integrated graphics even though the support isn't actually there
+        * according to the published specs.  It doesn't appear to function
+        * correctly in testing on 945G.
+        * This may be a side effect of MSI having been made available for PEG
+        * and the registers being closely associated.
+        */
+       if (!IS_I945G(dev) && !IS_I945GM(dev))
+               if (pci_enable_msi(dev->pdev))
+                       DRM_ERROR("failed to enable MSI\n");
+
+       intel_opregion_init(dev);
+
+       spin_lock_init(&dev_priv->user_irq_lock);
+
        return ret;
 }
 
@@ -791,8 +860,15 @@ int i915_driver_unload(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (dev_priv->mmio_map)
-               drm_rmmap(dev, dev_priv->mmio_map);
+       if (dev->pdev->msi_enabled)
+               pci_disable_msi(dev->pdev);
+
+       i915_free_hws(dev);
+
+       if (dev_priv->regs != NULL)
+               iounmap(dev_priv->regs);
+
+       intel_opregion_free(dev);
 
        drm_free(dev->dev_private, sizeof(drm_i915_private_t),
                 DRM_MEM_DRIVER);
@@ -800,6 +876,25 @@ int i915_driver_unload(struct drm_device *dev)
        return 0;
 }
 
+int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+{
+       struct drm_i915_file_private *i915_file_priv;
+
+       DRM_DEBUG("\n");
+       i915_file_priv = (struct drm_i915_file_private *)
+           drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);
+
+       if (!i915_file_priv)
+               return -ENOMEM;
+
+       file_priv->driver_priv = i915_file_priv;
+
+       i915_file_priv->mm.last_gem_seqno = 0;
+       i915_file_priv->mm.last_gem_throttle_seqno = 0;
+
+       return 0;
+}
+
 void i915_driver_lastclose(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -807,6 +902,8 @@ void i915_driver_lastclose(struct drm_device * dev)
        if (!dev_priv)
                return;
 
+       i915_gem_lastclose(dev);
+
        if (dev_priv->agp_heap)
                i915_mem_takedown(&(dev_priv->agp_heap));
 
@@ -819,6 +916,13 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
        i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
+void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+{
+       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+
+       drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES);
+}
+
 struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
@@ -836,7 +940,23 @@ struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE,  i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
        DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE,  i915_vblank_pipe_get, DRM_AUTH ),
        DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
index 93aed1c38bd22cfb272f4763e3fa59b9e8d00837..a80ead215282b933aacdb5cfab3b3b45f286d74a 100644 (file)
@@ -38,211 +38,9 @@ static struct pci_device_id pciidlist[] = {
        i915_PCI_IDS
 };
 
-enum pipe {
-    PIPE_A = 0,
-    PIPE_B,
-};
-
-static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (pipe == PIPE_A)
-               return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE);
-       else
-               return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE);
-}
-
-static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
-       u32 *array;
-       int i;
-
-       if (!i915_pipe_enabled(dev, pipe))
-               return;
-
-       if (pipe == PIPE_A)
-               array = dev_priv->save_palette_a;
-       else
-               array = dev_priv->save_palette_b;
-
-       for(i = 0; i < 256; i++)
-               array[i] = I915_READ(reg + (i << 2));
-}
-
-static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
-       u32 *array;
-       int i;
-
-       if (!i915_pipe_enabled(dev, pipe))
-               return;
-
-       if (pipe == PIPE_A)
-               array = dev_priv->save_palette_a;
-       else
-               array = dev_priv->save_palette_b;
-
-       for(i = 0; i < 256; i++)
-               I915_WRITE(reg + (i << 2), array[i]);
-}
-
-static u8 i915_read_indexed(u16 index_port, u16 data_port, u8 reg)
-{
-       outb(reg, index_port);
-       return inb(data_port);
-}
-
-static u8 i915_read_ar(u16 st01, u8 reg, u16 palette_enable)
-{
-       inb(st01);
-       outb(palette_enable | reg, VGA_AR_INDEX);
-       return inb(VGA_AR_DATA_READ);
-}
-
-static void i915_write_ar(u8 st01, u8 reg, u8 val, u16 palette_enable)
-{
-       inb(st01);
-       outb(palette_enable | reg, VGA_AR_INDEX);
-       outb(val, VGA_AR_DATA_WRITE);
-}
-
-static void i915_write_indexed(u16 index_port, u16 data_port, u8 reg, u8 val)
-{
-       outb(reg, index_port);
-       outb(val, data_port);
-}
-
-static void i915_save_vga(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-       u16 cr_index, cr_data, st01;
-
-       /* VGA color palette registers */
-       dev_priv->saveDACMASK = inb(VGA_DACMASK);
-       /* DACCRX automatically increments during read */
-       outb(0, VGA_DACRX);
-       /* Read 3 bytes of color data from each index */
-       for (i = 0; i < 256 * 3; i++)
-               dev_priv->saveDACDATA[i] = inb(VGA_DACDATA);
-
-       /* MSR bits */
-       dev_priv->saveMSR = inb(VGA_MSR_READ);
-       if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
-               cr_index = VGA_CR_INDEX_CGA;
-               cr_data = VGA_CR_DATA_CGA;
-               st01 = VGA_ST01_CGA;
-       } else {
-               cr_index = VGA_CR_INDEX_MDA;
-               cr_data = VGA_CR_DATA_MDA;
-               st01 = VGA_ST01_MDA;
-       }
-
-       /* CRT controller regs */
-       i915_write_indexed(cr_index, cr_data, 0x11,
-                          i915_read_indexed(cr_index, cr_data, 0x11) &
-                          (~0x80));
-       for (i = 0; i <= 0x24; i++)
-               dev_priv->saveCR[i] =
-                       i915_read_indexed(cr_index, cr_data, i);
-       /* Make sure we don't turn off CR group 0 writes */
-       dev_priv->saveCR[0x11] &= ~0x80;
-
-       /* Attribute controller registers */
-       inb(st01);
-       dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX);
-       for (i = 0; i <= 0x14; i++)
-               dev_priv->saveAR[i] = i915_read_ar(st01, i, 0);
-       inb(st01);
-       outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX);
-       inb(st01);
-
-       /* Graphics controller registers */
-       for (i = 0; i < 9; i++)
-               dev_priv->saveGR[i] =
-                       i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, i);
-
-       dev_priv->saveGR[0x10] =
-               i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10);
-       dev_priv->saveGR[0x11] =
-               i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11);
-       dev_priv->saveGR[0x18] =
-               i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18);
-
-       /* Sequencer registers */
-       for (i = 0; i < 8; i++)
-               dev_priv->saveSR[i] =
-                       i915_read_indexed(VGA_SR_INDEX, VGA_SR_DATA, i);
-}
-
-static void i915_restore_vga(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-       u16 cr_index, cr_data, st01;
-
-       /* MSR bits */
-       outb(dev_priv->saveMSR, VGA_MSR_WRITE);
-       if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
-               cr_index = VGA_CR_INDEX_CGA;
-               cr_data = VGA_CR_DATA_CGA;
-               st01 = VGA_ST01_CGA;
-       } else {
-               cr_index = VGA_CR_INDEX_MDA;
-               cr_data = VGA_CR_DATA_MDA;
-               st01 = VGA_ST01_MDA;
-       }
-
-       /* Sequencer registers, don't write SR07 */
-       for (i = 0; i < 7; i++)
-               i915_write_indexed(VGA_SR_INDEX, VGA_SR_DATA, i,
-                                  dev_priv->saveSR[i]);
-
-       /* CRT controller regs */
-       /* Enable CR group 0 writes */
-       i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
-       for (i = 0; i <= 0x24; i++)
-               i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]);
-
-       /* Graphics controller regs */
-       for (i = 0; i < 9; i++)
-               i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, i,
-                                  dev_priv->saveGR[i]);
-
-       i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10,
-                          dev_priv->saveGR[0x10]);
-       i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11,
-                          dev_priv->saveGR[0x11]);
-       i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18,
-                          dev_priv->saveGR[0x18]);
-
-       /* Attribute controller registers */
-       inb(st01);
-       for (i = 0; i <= 0x14; i++)
-               i915_write_ar(st01, i, dev_priv->saveAR[i], 0);
-       inb(st01); /* switch back to index mode */
-       outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX);
-       inb(st01);
-
-       /* VGA color palette registers */
-       outb(dev_priv->saveDACMASK, VGA_DACMASK);
-       /* DACCRX automatically increments during read */
-       outb(0, VGA_DACWX);
-       /* Read 3 bytes of color data from each index */
-       for (i = 0; i < 256 * 3; i++)
-               outb(dev_priv->saveDACDATA[i], VGA_DACDATA);
-
-}
-
 static int i915_suspend(struct drm_device *dev, pm_message_t state)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
 
        if (!dev || !dev_priv) {
                printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
@@ -254,122 +52,10 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
                return 0;
 
        pci_save_state(dev->pdev);
-       pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
-
-       /* Display arbitration control */
-       dev_priv->saveDSPARB = I915_READ(DSPARB);
-
-       /* Pipe & plane A info */
-       dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
-       dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
-       dev_priv->saveFPA0 = I915_READ(FPA0);
-       dev_priv->saveFPA1 = I915_READ(FPA1);
-       dev_priv->saveDPLL_A = I915_READ(DPLL_A);
-       if (IS_I965G(dev))
-               dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
-       dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
-       dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
-       dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
-       dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
-       dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
-       dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
-       dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
-
-       dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
-       dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
-       dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
-       dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
-       dev_priv->saveDSPABASE = I915_READ(DSPABASE);
-       if (IS_I965G(dev)) {
-               dev_priv->saveDSPASURF = I915_READ(DSPASURF);
-               dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
-       }
-       i915_save_palette(dev, PIPE_A);
-       dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT);
-
-       /* Pipe & plane B info */
-       dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
-       dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
-       dev_priv->saveFPB0 = I915_READ(FPB0);
-       dev_priv->saveFPB1 = I915_READ(FPB1);
-       dev_priv->saveDPLL_B = I915_READ(DPLL_B);
-       if (IS_I965G(dev))
-               dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
-       dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
-       dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
-       dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
-       dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
-       dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
-       dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
-       dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
-
-       dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
-       dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
-       dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
-       dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
-       dev_priv->saveDSPBBASE = I915_READ(DSPBBASE);
-       if (IS_I965GM(dev) || IS_IGD_GM(dev)) {
-               dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
-               dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
-       }
-       i915_save_palette(dev, PIPE_B);
-       dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT);
 
-       /* CRT state */
-       dev_priv->saveADPA = I915_READ(ADPA);
+       i915_save_state(dev);
 
-       /* LVDS state */
-       dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
-       dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
-       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
-       if (IS_I965G(dev))
-               dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
-       if (IS_MOBILE(dev) && !IS_I830(dev))
-               dev_priv->saveLVDS = I915_READ(LVDS);
-       if (!IS_I830(dev) && !IS_845G(dev))
-               dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
-       dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON);
-       dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF);
-       dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE);
-
-       /* FIXME: save TV & SDVO state */
-
-       /* FBC state */
-       dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
-       dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
-       dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
-       dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
-
-       /* Interrupt state */
-       dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R);
-       dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R);
-       dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R);
-
-       /* VGA state */
-       dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0);
-       dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1);
-       dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV);
-       dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
-
-       /* Clock gating state */
-       dev_priv->saveD_STATE = I915_READ(D_STATE);
-       dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
-
-       /* Cache mode state */
-       dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
-
-       /* Memory Arbitration state */
-       dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
-
-       /* Scratch space */
-       for (i = 0; i < 16; i++) {
-               dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2));
-               dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
-       }
-       for (i = 0; i < 3; i++)
-               dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
-
-       i915_save_vga(dev);
+       intel_opregion_free(dev);
 
        if (state.event == PM_EVENT_SUSPEND) {
                /* Shut down the device */
@@ -382,155 +68,15 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
 
 static int i915_resume(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
        pci_set_power_state(dev->pdev, PCI_D0);
        pci_restore_state(dev->pdev);
        if (pci_enable_device(dev->pdev))
                return -1;
        pci_set_master(dev->pdev);
 
-       pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
-
-       I915_WRITE(DSPARB, dev_priv->saveDSPARB);
-
-       /* Pipe & plane A info */
-       /* Prime the clock */
-       if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
-               I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
-                          ~DPLL_VCO_ENABLE);
-               udelay(150);
-       }
-       I915_WRITE(FPA0, dev_priv->saveFPA0);
-       I915_WRITE(FPA1, dev_priv->saveFPA1);
-       /* Actually enable it */
-       I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
-       udelay(150);
-       if (IS_I965G(dev))
-               I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
-       udelay(150);
-
-       /* Restore mode */
-       I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
-       I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
-       I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
-       I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
-       I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
-       I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
-       I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
-
-       /* Restore plane info */
-       I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
-       I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
-       I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
-       I915_WRITE(DSPABASE, dev_priv->saveDSPABASE);
-       I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
-       if (IS_I965G(dev)) {
-               I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
-               I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
-       }
-
-       I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
-
-       i915_restore_palette(dev, PIPE_A);
-       /* Enable the plane */
-       I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
-       I915_WRITE(DSPABASE, I915_READ(DSPABASE));
-
-       /* Pipe & plane B info */
-       if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
-               I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
-                          ~DPLL_VCO_ENABLE);
-               udelay(150);
-       }
-       I915_WRITE(FPB0, dev_priv->saveFPB0);
-       I915_WRITE(FPB1, dev_priv->saveFPB1);
-       /* Actually enable it */
-       I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
-       udelay(150);
-       if (IS_I965G(dev))
-               I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
-       udelay(150);
-
-       /* Restore mode */
-       I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
-       I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
-       I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
-       I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
-       I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
-       I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
-       I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
-
-       /* Restore plane info */
-       I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
-       I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
-       I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
-       I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE);
-       I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
-       if (IS_I965G(dev)) {
-               I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
-               I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
-       }
-
-       I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
-
-       i915_restore_palette(dev, PIPE_B);
-       /* Enable the plane */
-       I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
-       I915_WRITE(DSPBBASE, I915_READ(DSPBBASE));
-
-       /* CRT state */
-       I915_WRITE(ADPA, dev_priv->saveADPA);
-
-       /* LVDS state */
-       if (IS_I965G(dev))
-               I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
-       if (IS_MOBILE(dev) && !IS_I830(dev))
-               I915_WRITE(LVDS, dev_priv->saveLVDS);
-       if (!IS_I830(dev) && !IS_845G(dev))
-               I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
-
-       I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
-       I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
-       I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON);
-       I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF);
-       I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE);
-       I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
-
-       /* FIXME: restore TV & SDVO state */
-
-       /* FBC info */
-       I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
-       I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
-       I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
-       I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
-
-       /* VGA state */
-       I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
-       I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0);
-       I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1);
-       I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV);
-       udelay(150);
-
-       /* Clock gating state */
-       I915_WRITE (D_STATE, dev_priv->saveD_STATE);
-       I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
-
-       /* Cache mode state */
-       I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
-
-       /* Memory arbitration state */
-       I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
-
-       for (i = 0; i < 16; i++) {
-               I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]);
-               I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
-       }
-       for (i = 0; i < 3; i++)
-               I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
+       i915_restore_state(dev);
 
-       i915_restore_vga(dev);
+       intel_opregion_init(dev);
 
        return 0;
 }
@@ -541,17 +87,19 @@ static struct drm_driver driver = {
         */
        .driver_features =
            DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
-           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
-           DRIVER_IRQ_VBL2,
+           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
        .load = i915_driver_load,
        .unload = i915_driver_unload,
+       .open = i915_driver_open,
        .lastclose = i915_driver_lastclose,
        .preclose = i915_driver_preclose,
+       .postclose = i915_driver_postclose,
        .suspend = i915_suspend,
        .resume = i915_resume,
        .device_is_agp = i915_driver_device_is_agp,
-       .vblank_wait = i915_driver_vblank_wait,
-       .vblank_wait2 = i915_driver_vblank_wait2,
+       .get_vblank_counter = i915_get_vblank_counter,
+       .enable_vblank = i915_enable_vblank,
+       .disable_vblank = i915_disable_vblank,
        .irq_preinstall = i915_driver_irq_preinstall,
        .irq_postinstall = i915_driver_irq_postinstall,
        .irq_uninstall = i915_driver_irq_uninstall,
@@ -559,6 +107,10 @@ static struct drm_driver driver = {
        .reclaim_buffers = drm_core_reclaim_buffers,
        .get_map_ofs = drm_core_get_map_ofs,
        .get_reg_ofs = drm_core_get_reg_ofs,
+       .proc_init = i915_gem_proc_init,
+       .proc_cleanup = i915_gem_proc_cleanup,
+       .gem_init_object = i915_gem_init_object,
+       .gem_free_object = i915_gem_free_object,
        .ioctls = i915_ioctls,
        .fops = {
                 .owner = THIS_MODULE,
index d7326d92a237c2917e48d0bf5ed2c8d017081578..eae4ed3956e0b456f3a58e0aa29c9dbb4ee3d6f1 100644 (file)
@@ -30,6 +30,8 @@
 #ifndef _I915_DRV_H_
 #define _I915_DRV_H_
 
+#include "i915_reg.h"
+
 /* General customization:
  */
 
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20060119"
+#define DRIVER_DATE            "20080730"
+
+enum pipe {
+       PIPE_A = 0,
+       PIPE_B,
+};
 
 /* Interface history:
  *
 #define DRIVER_MINOR           6
 #define DRIVER_PATCHLEVEL      0
 
+#define WATCH_COHERENCY        0
+#define WATCH_BUF      0
+#define WATCH_EXEC     0
+#define WATCH_LRU      0
+#define WATCH_RELOC    0
+#define WATCH_INACTIVE 0
+#define WATCH_PWRITE   0
+
 typedef struct _drm_i915_ring_buffer {
        int tail_mask;
-       unsigned long Start;
-       unsigned long End;
        unsigned long Size;
        u8 *virtual_start;
        int head;
        int tail;
        int space;
        drm_local_map_t map;
+       struct drm_gem_object *ring_obj;
 } drm_i915_ring_buffer_t;
 
 struct mem_block {
@@ -76,13 +90,28 @@ struct mem_block {
 typedef struct _drm_i915_vbl_swap {
        struct list_head head;
        drm_drawable_t drw_id;
-       unsigned int pipe;
+       unsigned int plane;
        unsigned int sequence;
 } drm_i915_vbl_swap_t;
 
+struct opregion_header;
+struct opregion_acpi;
+struct opregion_swsci;
+struct opregion_asle;
+
+struct intel_opregion {
+       struct opregion_header *header;
+       struct opregion_acpi *acpi;
+       struct opregion_swsci *swsci;
+       struct opregion_asle *asle;
+       int enabled;
+};
+
 typedef struct drm_i915_private {
+       struct drm_device *dev;
+
+       void __iomem *regs;
        drm_local_map_t *sarea;
-       drm_local_map_t *mmio_map;
 
        drm_i915_sarea_t *sarea_priv;
        drm_i915_ring_buffer_t ring;
@@ -90,20 +119,25 @@ typedef struct drm_i915_private {
        drm_dma_handle_t *status_page_dmah;
        void *hw_status_page;
        dma_addr_t dma_status_page;
-       unsigned long counter;
+       uint32_t counter;
        unsigned int status_gfx_addr;
        drm_local_map_t hws_map;
+       struct drm_gem_object *hws_obj;
 
        unsigned int cpp;
        int back_offset;
        int front_offset;
        int current_page;
        int page_flipping;
-       int use_mi_batchbuffer_start;
 
        wait_queue_head_t irq_queue;
        atomic_t irq_received;
-       atomic_t irq_emitted;
+       /** Protects user_irq_refcount and irq_mask_reg */
+       spinlock_t user_irq_lock;
+       /** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */
+       int user_irq_refcount;
+       /** Cached value of IMR to avoid reads in updating the bitfield */
+       u32 irq_mask_reg;
 
        int tex_lru_log_granularity;
        int allow_batchbuffer;
@@ -115,6 +149,8 @@ typedef struct drm_i915_private {
        drm_i915_vbl_swap_t vbl_swaps;
        unsigned int swaps_pending;
 
+       struct intel_opregion opregion;
+
        /* Register state */
        u8 saveLBB;
        u32 saveDSPACNTR;
@@ -139,7 +175,7 @@ typedef struct drm_i915_private {
        u32 saveDSPASTRIDE;
        u32 saveDSPASIZE;
        u32 saveDSPAPOS;
-       u32 saveDSPABASE;
+       u32 saveDSPAADDR;
        u32 saveDSPASURF;
        u32 saveDSPATILEOFF;
        u32 savePFIT_PGM_RATIOS;
@@ -160,24 +196,24 @@ typedef struct drm_i915_private {
        u32 saveDSPBSTRIDE;
        u32 saveDSPBSIZE;
        u32 saveDSPBPOS;
-       u32 saveDSPBBASE;
+       u32 saveDSPBADDR;
        u32 saveDSPBSURF;
        u32 saveDSPBTILEOFF;
-       u32 saveVCLK_DIVISOR_VGA0;
-       u32 saveVCLK_DIVISOR_VGA1;
-       u32 saveVCLK_POST_DIV;
+       u32 saveVGA0;
+       u32 saveVGA1;
+       u32 saveVGA_PD;
        u32 saveVGACNTRL;
        u32 saveADPA;
        u32 saveLVDS;
-       u32 saveLVDSPP_ON;
-       u32 saveLVDSPP_OFF;
+       u32 savePP_ON_DELAYS;
+       u32 savePP_OFF_DELAYS;
        u32 saveDVOA;
        u32 saveDVOB;
        u32 saveDVOC;
        u32 savePP_ON;
        u32 savePP_OFF;
        u32 savePP_CONTROL;
-       u32 savePP_CYCLE;
+       u32 savePP_DIVISOR;
        u32 savePFIT_CONTROL;
        u32 save_palette_a[256];
        u32 save_palette_b[256];
@@ -190,7 +226,7 @@ typedef struct drm_i915_private {
        u32 saveIMR;
        u32 saveCACHE_MODE_0;
        u32 saveD_STATE;
-       u32 saveDSPCLK_GATE_D;
+       u32 saveCG_2D_DIS;
        u32 saveMI_ARB_STATE;
        u32 saveSWF0[16];
        u32 saveSWF1[16];
@@ -203,8 +239,180 @@ typedef struct drm_i915_private {
        u8 saveDACMASK;
        u8 saveDACDATA[256*3]; /* 256 3-byte colors */
        u8 saveCR[37];
+
+       struct {
+               struct drm_mm gtt_space;
+
+               /**
+                * List of objects currently involved in rendering from the
+                * ringbuffer.
+                *
+                * A reference is held on the buffer while on this list.
+                */
+               struct list_head active_list;
+
+               /**
+                * List of objects which are not in the ringbuffer but which
+                * still have a write_domain which needs to be flushed before
+                * unbinding.
+                *
+                * A reference is held on the buffer while on this list.
+                */
+               struct list_head flushing_list;
+
+               /**
+                * LRU list of objects which are not in the ringbuffer and
+                * are ready to unbind, but are still in the GTT.
+                *
+                * A reference is not held on the buffer while on this list,
+                * as merely being GTT-bound shouldn't prevent its being
+                * freed, and we'll pull it off the list in the free path.
+                */
+               struct list_head inactive_list;
+
+               /**
+                * List of breadcrumbs associated with GPU requests currently
+                * outstanding.
+                */
+               struct list_head request_list;
+
+               /**
+                * We leave the user IRQ off as much as possible,
+                * but this means that requests will finish and never
+                * be retired once the system goes idle. Set a timer to
+                * fire periodically while the ring is running. When it
+                * fires, go retire requests.
+                */
+               struct delayed_work retire_work;
+
+               /** Work task for vblank-related ring access */
+               struct work_struct vblank_work;
+
+               uint32_t next_gem_seqno;
+
+               /**
+                * Waiting sequence number, if any
+                */
+               uint32_t waiting_gem_seqno;
+
+               /**
+                * Last seq seen at irq time
+                */
+               uint32_t irq_gem_seqno;
+
+               /**
+                * Flag if the X Server, and thus DRM, is not currently in
+                * control of the device.
+                *
+                * This is set between LeaveVT and EnterVT.  It needs to be
+                * replaced with a semaphore.  It also needs to be
+                * transitioned away from for kernel modesetting.
+                */
+               int suspended;
+
+               /**
+                * Flag if the hardware appears to be wedged.
+                *
+                * This is set when attempts to idle the device timeout.
+                * It prevents command submission from occuring and makes
+                * every pending request fail
+                */
+               int wedged;
+
+               /** Bit 6 swizzling required for X tiling */
+               uint32_t bit_6_swizzle_x;
+               /** Bit 6 swizzling required for Y tiling */
+               uint32_t bit_6_swizzle_y;
+       } mm;
 } drm_i915_private_t;
 
+/** driver private structure attached to each drm_gem_object */
+struct drm_i915_gem_object {
+       struct drm_gem_object *obj;
+
+       /** Current space allocated to this object in the GTT, if any. */
+       struct drm_mm_node *gtt_space;
+
+       /** This object's place on the active/flushing/inactive lists */
+       struct list_head list;
+
+       /**
+        * This is set if the object is on the active or flushing lists
+        * (has pending rendering), and is not set if it's on inactive (ready
+        * to be unbound).
+        */
+       int active;
+
+       /**
+        * This is set if the object has been written to since last bound
+        * to the GTT
+        */
+       int dirty;
+
+       /** AGP memory structure for our GTT binding. */
+       DRM_AGP_MEM *agp_mem;
+
+       struct page **page_list;
+
+       /**
+        * Current offset of the object in GTT space.
+        *
+        * This is the same as gtt_space->start
+        */
+       uint32_t gtt_offset;
+
+       /** Boolean whether this object has a valid gtt offset. */
+       int gtt_bound;
+
+       /** How many users have pinned this object in GTT space */
+       int pin_count;
+
+       /** Breadcrumb of last rendering to the buffer. */
+       uint32_t last_rendering_seqno;
+
+       /** Current tiling mode for the object. */
+       uint32_t tiling_mode;
+
+       /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
+       uint32_t agp_type;
+
+       /**
+        * Flagging of which individual pages are valid in GEM_DOMAIN_CPU when
+        * GEM_DOMAIN_CPU is not in the object's read domain.
+        */
+       uint8_t *page_cpu_valid;
+};
+
+/**
+ * Request queue structure.
+ *
+ * The request queue allows us to note sequence numbers that have been emitted
+ * and may be associated with active buffers to be retired.
+ *
+ * By keeping this list, we can avoid having to do questionable
+ * sequence-number comparisons on buffer last_rendering_seqnos, and associate
+ * an emission time with seqnos for tracking how far ahead of the GPU we are.
+ */
+struct drm_i915_gem_request {
+       /** GEM sequence number associated with this request. */
+       uint32_t seqno;
+
+       /** Time at which this request was emitted, in jiffies. */
+       unsigned long emitted_jiffies;
+
+       /** Cache domains that were flushed at the start of the request. */
+       uint32_t flush_domains;
+
+       struct list_head list;
+};
+
+struct drm_i915_file_private {
+       struct {
+               uint32_t last_gem_seqno;
+               uint32_t last_gem_throttle_seqno;
+       } mm;
+};
+
 extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 
@@ -212,31 +420,42 @@ extern int i915_max_ioctl;
 extern void i915_kernel_lost_context(struct drm_device * dev);
 extern int i915_driver_load(struct drm_device *, unsigned long flags);
 extern int i915_driver_unload(struct drm_device *);
+extern int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv);
 extern void i915_driver_lastclose(struct drm_device * dev);
 extern void i915_driver_preclose(struct drm_device *dev,
                                 struct drm_file *file_priv);
+extern void i915_driver_postclose(struct drm_device *dev,
+                                 struct drm_file *file_priv);
 extern int i915_driver_device_is_agp(struct drm_device * dev);
 extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
                              unsigned long arg);
+extern int i915_emit_box(struct drm_device *dev,
+                        struct drm_clip_rect __user *boxes,
+                        int i, int DR1, int DR4);
 
 /* i915_irq.c */
 extern int i915_irq_emit(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 extern int i915_irq_wait(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
+void i915_user_irq_get(struct drm_device *dev);
+void i915_user_irq_put(struct drm_device *dev);
 
-extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
-extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
+extern void i915_gem_vblank_work_handler(struct work_struct *work);
 extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(struct drm_device * dev);
-extern void i915_driver_irq_postinstall(struct drm_device * dev);
+extern int i915_driver_irq_postinstall(struct drm_device *dev);
 extern void i915_driver_irq_uninstall(struct drm_device * dev);
 extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
+extern int i915_enable_vblank(struct drm_device *dev, int crtc);
+extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int i915_vblank_swap(struct drm_device *dev, void *data,
                            struct drm_file *file_priv);
+extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask);
 
 /* i915_mem.c */
 extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -250,11 +469,99 @@ extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
 extern void i915_mem_takedown(struct mem_block **heap);
 extern void i915_mem_release(struct drm_device * dev,
                             struct drm_file *file_priv, struct mem_block *heap);
+/* i915_gem.c */
+int i915_gem_init_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int i915_gem_create_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv);
+int i915_gem_pread_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv);
+int i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv);
+int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv);
+int i915_gem_execbuffer(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int i915_gem_pin_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+int i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+int i915_gem_busy_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv);
+int i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+int i915_gem_set_tiling(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int i915_gem_get_tiling(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+void i915_gem_load(struct drm_device *dev);
+int i915_gem_proc_init(struct drm_minor *minor);
+void i915_gem_proc_cleanup(struct drm_minor *minor);
+int i915_gem_init_object(struct drm_gem_object *obj);
+void i915_gem_free_object(struct drm_gem_object *obj);
+int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
+void i915_gem_object_unpin(struct drm_gem_object *obj);
+void i915_gem_lastclose(struct drm_device *dev);
+uint32_t i915_get_gem_seqno(struct drm_device *dev);
+void i915_gem_retire_requests(struct drm_device *dev);
+void i915_gem_retire_work_handler(struct work_struct *work);
+void i915_gem_clflush_object(struct drm_gem_object *obj);
+
+/* i915_gem_tiling.c */
+void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
+
+/* i915_gem_debug.c */
+void i915_gem_dump_object(struct drm_gem_object *obj, int len,
+                         const char *where, uint32_t mark);
+#if WATCH_INACTIVE
+void i915_verify_inactive(struct drm_device *dev, char *file, int line);
+#else
+#define i915_verify_inactive(dev, file, line)
+#endif
+void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
+void i915_gem_dump_object(struct drm_gem_object *obj, int len,
+                         const char *where, uint32_t mark);
+void i915_dump_lru(struct drm_device *dev, const char *where);
+
+/* i915_suspend.c */
+extern int i915_save_state(struct drm_device *dev);
+extern int i915_restore_state(struct drm_device *dev);
+
+/* i915_suspend.c */
+extern int i915_save_state(struct drm_device *dev);
+extern int i915_restore_state(struct drm_device *dev);
+
+/* i915_opregion.c */
+extern int intel_opregion_init(struct drm_device *dev);
+extern void intel_opregion_free(struct drm_device *dev);
+extern void opregion_asle_intr(struct drm_device *dev);
+extern void opregion_enable_asle(struct drm_device *dev);
+
+/**
+ * Lock test for when it's just for synchronization of ring access.
+ *
+ * In that case, we don't need to do it when GEM is initialized as nobody else
+ * has access to the ring.
+ */
+#define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do {                        \
+       if (((drm_i915_private_t *)dev->dev_private)->ring.ring_obj == NULL) \
+               LOCK_TEST_WITH_RETURN(dev, file_priv);                  \
+} while (0)
 
-#define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, (reg))
-#define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
-#define I915_READ16(reg)       DRM_READ16(dev_priv->mmio_map, (reg))
-#define I915_WRITE16(reg,val)  DRM_WRITE16(dev_priv->mmio_map, (reg), (val))
+#define I915_READ(reg)          readl(dev_priv->regs + (reg))
+#define I915_WRITE(reg, val)     writel(val, dev_priv->regs + (reg))
+#define I915_READ16(reg)       readw(dev_priv->regs + (reg))
+#define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
+#define I915_READ8(reg)                readb(dev_priv->regs + (reg))
+#define I915_WRITE8(reg, val)  writeb(val, dev_priv->regs + (reg))
 
 #define I915_VERBOSE 0
 
@@ -284,816 +591,29 @@ extern void i915_mem_release(struct drm_device * dev,
        if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring);   \
        dev_priv->ring.tail = outring;                                  \
        dev_priv->ring.space -= outcount * 4;                           \
-       I915_WRITE(LP_RING + RING_TAIL, outring);                       \
+       I915_WRITE(PRB0_TAIL, outring);                 \
 } while(0)
 
-extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
-
-/* Extended config space */
-#define LBB 0xf4
-
-/* VGA stuff */
-
-#define VGA_ST01_MDA 0x3ba
-#define VGA_ST01_CGA 0x3da
-
-#define VGA_MSR_WRITE 0x3c2
-#define VGA_MSR_READ 0x3cc
-#define   VGA_MSR_MEM_EN (1<<1)
-#define   VGA_MSR_CGA_MODE (1<<0)
-
-#define VGA_SR_INDEX 0x3c4
-#define VGA_SR_DATA 0x3c5
-
-#define VGA_AR_INDEX 0x3c0
-#define   VGA_AR_VID_EN (1<<5)
-#define VGA_AR_DATA_WRITE 0x3c0
-#define VGA_AR_DATA_READ 0x3c1
-
-#define VGA_GR_INDEX 0x3ce
-#define VGA_GR_DATA 0x3cf
-/* GR05 */
-#define   VGA_GR_MEM_READ_MODE_SHIFT 3
-#define     VGA_GR_MEM_READ_MODE_PLANE 1
-/* GR06 */
-#define   VGA_GR_MEM_MODE_MASK 0xc
-#define   VGA_GR_MEM_MODE_SHIFT 2
-#define   VGA_GR_MEM_A0000_AFFFF 0
-#define   VGA_GR_MEM_A0000_BFFFF 1
-#define   VGA_GR_MEM_B0000_B7FFF 2
-#define   VGA_GR_MEM_B0000_BFFFF 3
-
-#define VGA_DACMASK 0x3c6
-#define VGA_DACRX 0x3c7
-#define VGA_DACWX 0x3c8
-#define VGA_DACDATA 0x3c9
-
-#define VGA_CR_INDEX_MDA 0x3b4
-#define VGA_CR_DATA_MDA 0x3b5
-#define VGA_CR_INDEX_CGA 0x3d4
-#define VGA_CR_DATA_CGA 0x3d5
-
-#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
-#define GFX_OP_BREAKPOINT_INTERRUPT    ((0<<29)|(1<<23))
-#define CMD_REPORT_HEAD                        (7<<23)
-#define CMD_STORE_DWORD_IDX            ((0x21<<23) | 0x1)
-#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1)
-
-#define INST_PARSER_CLIENT   0x00000000
-#define INST_OP_FLUSH        0x02000000
-#define INST_FLUSH_MAP_CACHE 0x00000001
-
-#define BB1_START_ADDR_MASK   (~0x7)
-#define BB1_PROTECTED         (1<<0)
-#define BB1_UNPROTECTED       (0<<0)
-#define BB2_END_ADDR_MASK     (~0x7)
-
-/* Framebuffer compression */
-#define FBC_CFB_BASE           0x03200 /* 4k page aligned */
-#define FBC_LL_BASE            0x03204 /* 4k page aligned */
-#define FBC_CONTROL            0x03208
-#define   FBC_CTL_EN           (1<<31)
-#define   FBC_CTL_PERIODIC     (1<<30)
-#define   FBC_CTL_INTERVAL_SHIFT (16)
-#define   FBC_CTL_UNCOMPRESSIBLE (1<<14)
-#define   FBC_CTL_STRIDE_SHIFT (5)
-#define   FBC_CTL_FENCENO      (1<<0)
-#define FBC_COMMAND            0x0320c
-#define   FBC_CMD_COMPRESS     (1<<0)
-#define FBC_STATUS             0x03210
-#define   FBC_STAT_COMPRESSING (1<<31)
-#define   FBC_STAT_COMPRESSED  (1<<30)
-#define   FBC_STAT_MODIFIED    (1<<29)
-#define   FBC_STAT_CURRENT_LINE        (1<<0)
-#define FBC_CONTROL2           0x03214
-#define   FBC_CTL_FENCE_DBL    (0<<4)
-#define   FBC_CTL_IDLE_IMM     (0<<2)
-#define   FBC_CTL_IDLE_FULL    (1<<2)
-#define   FBC_CTL_IDLE_LINE    (2<<2)
-#define   FBC_CTL_IDLE_DEBUG   (3<<2)
-#define   FBC_CTL_CPU_FENCE    (1<<1)
-#define   FBC_CTL_PLANEA       (0<<0)
-#define   FBC_CTL_PLANEB       (1<<0)
-#define FBC_FENCE_OFF          0x0321b
-
-#define FBC_LL_SIZE            (1536)
-#define FBC_LL_PAD             (32)
-
-/* Interrupt bits:
- */
-#define USER_INT_FLAG    (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-#define HWB_OOM_FLAG     (1<<13) /* binner out of memory */
-
-#define I915REG_HWSTAM         0x02098
-#define I915REG_INT_IDENTITY_R 0x020a4
-#define I915REG_INT_MASK_R     0x020a8
-#define I915REG_INT_ENABLE_R   0x020a0
-
-#define I915REG_PIPEASTAT      0x70024
-#define I915REG_PIPEBSTAT      0x71024
-
-#define I915_VBLANK_INTERRUPT_ENABLE   (1UL<<17)
-#define I915_VBLANK_CLEAR              (1UL<<1)
-
-#define SRX_INDEX              0x3c4
-#define SRX_DATA               0x3c5
-#define SR01                   1
-#define SR01_SCREEN_OFF                (1<<5)
-
-#define PPCR                   0x61204
-#define PPCR_ON                        (1<<0)
-
-#define DVOB                   0x61140
-#define DVOB_ON                        (1<<31)
-#define DVOC                   0x61160
-#define DVOC_ON                        (1<<31)
-#define LVDS                   0x61180
-#define LVDS_ON                        (1<<31)
-
-#define ADPA                   0x61100
-#define ADPA_DPMS_MASK         (~(3<<10))
-#define ADPA_DPMS_ON           (0<<10)
-#define ADPA_DPMS_SUSPEND      (1<<10)
-#define ADPA_DPMS_STANDBY      (2<<10)
-#define ADPA_DPMS_OFF          (3<<10)
-
-#define NOPID                   0x2094
-#define LP_RING                        0x2030
-#define HP_RING                        0x2040
-/* The binner has its own ring buffer:
- */
-#define HWB_RING               0x2400
-
-#define RING_TAIL              0x00
-#define TAIL_ADDR              0x001FFFF8
-#define RING_HEAD              0x04
-#define HEAD_WRAP_COUNT                0xFFE00000
-#define HEAD_WRAP_ONE          0x00200000
-#define HEAD_ADDR              0x001FFFFC
-#define RING_START             0x08
-#define START_ADDR             0x0xFFFFF000
-#define RING_LEN               0x0C
-#define RING_NR_PAGES          0x001FF000
-#define RING_REPORT_MASK       0x00000006
-#define RING_REPORT_64K                0x00000002
-#define RING_REPORT_128K       0x00000004
-#define RING_NO_REPORT         0x00000000
-#define RING_VALID_MASK                0x00000001
-#define RING_VALID             0x00000001
-#define RING_INVALID           0x00000000
-
-/* Instruction parser error reg:
- */
-#define IPEIR                  0x2088
-
-/* Scratch pad debug 0 reg:
- */
-#define SCPD0                  0x209c
-
-/* Error status reg:
- */
-#define ESR                    0x20b8
-
-/* Secondary DMA fetch address debug reg:
- */
-#define DMA_FADD_S             0x20d4
-
-/* Memory Interface Arbitration State
- */
-#define MI_ARB_STATE           0x20e4
-
-/* Cache mode 0 reg.
- *  - Manipulating render cache behaviour is central
- *    to the concept of zone rendering, tuning this reg can help avoid
- *    unnecessary render cache reads and even writes (for z/stencil)
- *    at beginning and end of scene.
- *
- * - To change a bit, write to this reg with a mask bit set and the
- * bit of interest either set or cleared.  EG: (BIT<<16) | BIT to set.
- */
-#define Cache_Mode_0           0x2120
-#define CACHE_MODE_0           0x2120
-#define CM0_MASK_SHIFT          16
-#define CM0_IZ_OPT_DISABLE      (1<<6)
-#define CM0_ZR_OPT_DISABLE      (1<<5)
-#define CM0_DEPTH_EVICT_DISABLE (1<<4)
-#define CM0_COLOR_EVICT_DISABLE (1<<3)
-#define CM0_DEPTH_WRITE_DISABLE (1<<1)
-#define CM0_RC_OP_FLUSH_DISABLE (1<<0)
-
-
-/* Graphics flush control.  A CPU write flushes the GWB of all writes.
- * The data is discarded.
- */
-#define GFX_FLSH_CNTL          0x2170
-
-/* Binner control.  Defines the location of the bin pointer list:
- */
-#define BINCTL                 0x2420
-#define BC_MASK                        (1 << 9)
-
-/* Binned scene info.
- */
-#define BINSCENE               0x2428
-#define BS_OP_LOAD             (1 << 8)
-#define BS_MASK                        (1 << 22)
-
-/* Bin command parser debug reg:
- */
-#define BCPD                   0x2480
-
-/* Bin memory control debug reg:
- */
-#define BMCD                   0x2484
-
-/* Bin data cache debug reg:
- */
-#define BDCD                   0x2488
-
-/* Binner pointer cache debug reg:
- */
-#define BPCD                   0x248c
-
-/* Binner scratch pad debug reg:
- */
-#define BINSKPD                        0x24f0
-
-/* HWB scratch pad debug reg:
- */
-#define HWBSKPD                        0x24f4
-
-/* Binner memory pool reg:
- */
-#define BMP_BUFFER             0x2430
-#define BMP_PAGE_SIZE_4K       (0 << 10)
-#define BMP_BUFFER_SIZE_SHIFT  1
-#define BMP_ENABLE             (1 << 0)
-
-/* Get/put memory from the binner memory pool:
- */
-#define BMP_GET                        0x2438
-#define BMP_PUT                        0x2440
-#define BMP_OFFSET_SHIFT       5
-
-/* 3D state packets:
- */
-#define GFX_OP_RASTER_RULES    ((0x3<<29)|(0x7<<24))
-
-#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
-#define SC_UPDATE_SCISSOR       (0x1<<1)
-#define SC_ENABLE_MASK          (0x1<<0)
-#define SC_ENABLE               (0x1<<0)
-
-#define GFX_OP_LOAD_INDIRECT   ((0x3<<29)|(0x1d<<24)|(0x7<<16))
-
-#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
-#define SCI_YMIN_MASK      (0xffff<<16)
-#define SCI_XMIN_MASK      (0xffff<<0)
-#define SCI_YMAX_MASK      (0xffff<<16)
-#define SCI_XMAX_MASK      (0xffff<<0)
-
-#define GFX_OP_SCISSOR_ENABLE   ((0x3<<29)|(0x1c<<24)|(0x10<<19))
-#define GFX_OP_SCISSOR_RECT     ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
-#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
-#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
-#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x4)
-#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
-#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
-
-#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
-
-#define SRC_COPY_BLT_CMD                ((2<<29)|(0x43<<22)|4)
-#define XY_SRC_COPY_BLT_CMD            ((2<<29)|(0x53<<22)|6)
-#define XY_SRC_COPY_BLT_WRITE_ALPHA    (1<<21)
-#define XY_SRC_COPY_BLT_WRITE_RGB      (1<<20)
-#define XY_SRC_COPY_BLT_SRC_TILED      (1<<15)
-#define XY_SRC_COPY_BLT_DST_TILED      (1<<11)
-
-#define MI_BATCH_BUFFER                ((0x30<<23)|1)
-#define MI_BATCH_BUFFER_START  (0x31<<23)
-#define MI_BATCH_BUFFER_END    (0xA<<23)
-#define MI_BATCH_NON_SECURE    (1)
-#define MI_BATCH_NON_SECURE_I965 (1<<8)
-
-#define MI_WAIT_FOR_EVENT       ((0x3<<23))
-#define MI_WAIT_FOR_PLANE_B_FLIP      (1<<6)
-#define MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
-#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
-
-#define MI_LOAD_SCAN_LINES_INCL  ((0x12<<23))
-
-#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
-#define ASYNC_FLIP                (1<<22)
-#define DISPLAY_PLANE_A           (0<<20)
-#define DISPLAY_PLANE_B           (1<<20)
-
-/* Display regs */
-#define DSPACNTR                0x70180
-#define DSPBCNTR                0x71180
-#define DISPPLANE_SEL_PIPE_MASK                 (1<<24)
-
-/* Define the region of interest for the binner:
- */
-#define CMD_OP_BIN_CONTROL      ((0x3<<29)|(0x1d<<24)|(0x84<<16)|4)
-
-#define CMD_OP_DESTBUFFER_INFO  ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
-
-#define CMD_MI_FLUSH         (0x04 << 23)
-#define MI_NO_WRITE_FLUSH    (1 << 2)
-#define MI_READ_FLUSH        (1 << 0)
-#define MI_EXE_FLUSH         (1 << 1)
-#define MI_END_SCENE         (1 << 4) /* flush binner and incr scene count */
-#define MI_SCENE_COUNT       (1 << 3) /* just increment scene count */
-
-#define BREADCRUMB_BITS 31
-#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1)
-
-#define READ_BREADCRUMB(dev_priv)  (((volatile u32*)(dev_priv->hw_status_page))[5])
-#define READ_HWSP(dev_priv, reg)  (((volatile u32*)(dev_priv->hw_status_page))[reg])
-
-#define BLC_PWM_CTL            0x61254
-#define BACKLIGHT_MODULATION_FREQ_SHIFT                (17)
-
-#define BLC_PWM_CTL2           0x61250
-/**
- * This is the most significant 15 bits of the number of backlight cycles in a
- * complete cycle of the modulated backlight control.
- *
- * The actual value is this field multiplied by two.
- */
-#define BACKLIGHT_MODULATION_FREQ_MASK         (0x7fff << 17)
-#define BLM_LEGACY_MODE                                (1 << 16)
-/**
- * This is the number of cycles out of the backlight modulation cycle for which
- * the backlight is on.
- *
- * This field must be no greater than the number of cycles in the complete
- * backlight modulation cycle.
- */
-#define BACKLIGHT_DUTY_CYCLE_SHIFT             (0)
-#define BACKLIGHT_DUTY_CYCLE_MASK              (0xffff)
-
-#define I915_GCFGC                     0xf0
-#define I915_LOW_FREQUENCY_ENABLE              (1 << 7)
-#define I915_DISPLAY_CLOCK_190_200_MHZ         (0 << 4)
-#define I915_DISPLAY_CLOCK_333_MHZ             (4 << 4)
-#define I915_DISPLAY_CLOCK_MASK                        (7 << 4)
-
-#define I855_HPLLCC                    0xc0
-#define I855_CLOCK_CONTROL_MASK                        (3 << 0)
-#define I855_CLOCK_133_200                     (0 << 0)
-#define I855_CLOCK_100_200                     (1 << 0)
-#define I855_CLOCK_100_133                     (2 << 0)
-#define I855_CLOCK_166_250                     (3 << 0)
-
-/* p317, 319
- */
-#define VCLK2_VCO_M        0x6008 /* treat as 16 bit? (includes msbs) */
-#define VCLK2_VCO_N        0x600a
-#define VCLK2_VCO_DIV_SEL  0x6012
-
-#define VCLK_DIVISOR_VGA0   0x6000
-#define VCLK_DIVISOR_VGA1   0x6004
-#define VCLK_POST_DIV      0x6010
-/** Selects a post divisor of 4 instead of 2. */
-# define VGA1_PD_P2_DIV_4      (1 << 15)
-/** Overrides the p2 post divisor field */
-# define VGA1_PD_P1_DIV_2      (1 << 13)
-# define VGA1_PD_P1_SHIFT      8
-/** P1 value is 2 greater than this field */
-# define VGA1_PD_P1_MASK       (0x1f << 8)
-/** Selects a post divisor of 4 instead of 2. */
-# define VGA0_PD_P2_DIV_4      (1 << 7)
-/** Overrides the p2 post divisor field */
-# define VGA0_PD_P1_DIV_2      (1 << 5)
-# define VGA0_PD_P1_SHIFT      0
-/** P1 value is 2 greater than this field */
-# define VGA0_PD_P1_MASK       (0x1f << 0)
-
-/* PCI D state control register */
-#define D_STATE                0x6104
-#define DSPCLK_GATE_D  0x6200
-
-/* I830 CRTC registers */
-#define HTOTAL_A       0x60000
-#define HBLANK_A       0x60004
-#define HSYNC_A                0x60008
-#define VTOTAL_A       0x6000c
-#define VBLANK_A       0x60010
-#define VSYNC_A                0x60014
-#define PIPEASRC       0x6001c
-#define BCLRPAT_A      0x60020
-#define VSYNCSHIFT_A   0x60028
-
-#define HTOTAL_B       0x61000
-#define HBLANK_B       0x61004
-#define HSYNC_B                0x61008
-#define VTOTAL_B       0x6100c
-#define VBLANK_B       0x61010
-#define VSYNC_B                0x61014
-#define PIPEBSRC       0x6101c
-#define BCLRPAT_B      0x61020
-#define VSYNCSHIFT_B   0x61028
-
-#define PP_STATUS      0x61200
-# define PP_ON                                 (1 << 31)
-/**
- * Indicates that all dependencies of the panel are on:
- *
- * - PLL enabled
- * - pipe enabled
- * - LVDS/DVOB/DVOC on
- */
-# define PP_READY                              (1 << 30)
-# define PP_SEQUENCE_NONE                      (0 << 28)
-# define PP_SEQUENCE_ON                                (1 << 28)
-# define PP_SEQUENCE_OFF                       (2 << 28)
-# define PP_SEQUENCE_MASK                      0x30000000
-#define PP_CONTROL     0x61204
-# define POWER_TARGET_ON                       (1 << 0)
-
-#define LVDSPP_ON       0x61208
-#define LVDSPP_OFF      0x6120c
-#define PP_CYCLE        0x61210
-
-#define PFIT_CONTROL   0x61230
-# define PFIT_ENABLE                           (1 << 31)
-# define PFIT_PIPE_MASK                                (3 << 29)
-# define PFIT_PIPE_SHIFT                       29
-# define VERT_INTERP_DISABLE                   (0 << 10)
-# define VERT_INTERP_BILINEAR                  (1 << 10)
-# define VERT_INTERP_MASK                      (3 << 10)
-# define VERT_AUTO_SCALE                       (1 << 9)
-# define HORIZ_INTERP_DISABLE                  (0 << 6)
-# define HORIZ_INTERP_BILINEAR                 (1 << 6)
-# define HORIZ_INTERP_MASK                     (3 << 6)
-# define HORIZ_AUTO_SCALE                      (1 << 5)
-# define PANEL_8TO6_DITHER_ENABLE              (1 << 3)
-
-#define PFIT_PGM_RATIOS        0x61234
-# define PFIT_VERT_SCALE_MASK                  0xfff00000
-# define PFIT_HORIZ_SCALE_MASK                 0x0000fff0
-
-#define PFIT_AUTO_RATIOS       0x61238
-
-
-#define DPLL_A         0x06014
-#define DPLL_B         0x06018
-# define DPLL_VCO_ENABLE                       (1 << 31)
-# define DPLL_DVO_HIGH_SPEED                   (1 << 30)
-# define DPLL_SYNCLOCK_ENABLE                  (1 << 29)
-# define DPLL_VGA_MODE_DIS                     (1 << 28)
-# define DPLLB_MODE_DAC_SERIAL                 (1 << 26) /* i915 */
-# define DPLLB_MODE_LVDS                       (2 << 26) /* i915 */
-# define DPLL_MODE_MASK                                (3 << 26)
-# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10       (0 << 24) /* i915 */
-# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5                (1 << 24) /* i915 */
-# define DPLLB_LVDS_P2_CLOCK_DIV_14            (0 << 24) /* i915 */
-# define DPLLB_LVDS_P2_CLOCK_DIV_7             (1 << 24) /* i915 */
-# define DPLL_P2_CLOCK_DIV_MASK                        0x03000000 /* i915 */
-# define DPLL_FPA01_P1_POST_DIV_MASK           0x00ff0000 /* i915 */
-/**
- *  The i830 generation, in DAC/serial mode, defines p1 as two plus this
- * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set.
- */
-# define DPLL_FPA01_P1_POST_DIV_MASK_I830      0x001f0000
-/**
- * The i830 generation, in LVDS mode, defines P1 as the bit number set within
- * this field (only one bit may be set).
- */
-# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000
-# define DPLL_FPA01_P1_POST_DIV_SHIFT          16
-# define PLL_P2_DIVIDE_BY_4                    (1 << 23) /* i830, required in DVO non-gang */
-# define PLL_P1_DIVIDE_BY_TWO                  (1 << 21) /* i830 */
-# define PLL_REF_INPUT_DREFCLK                 (0 << 13)
-# define PLL_REF_INPUT_TVCLKINA                        (1 << 13) /* i830 */
-# define PLL_REF_INPUT_TVCLKINBC               (2 << 13) /* SDVO TVCLKIN */
-# define PLLB_REF_INPUT_SPREADSPECTRUMIN       (3 << 13)
-# define PLL_REF_INPUT_MASK                    (3 << 13)
-# define PLL_LOAD_PULSE_PHASE_SHIFT            9
-/*
- * Parallel to Serial Load Pulse phase selection.
- * Selects the phase for the 10X DPLL clock for the PCIe
- * digital display port. The range is 4 to 13; 10 or more
- * is just a flip delay. The default is 6
- */
-# define PLL_LOAD_PULSE_PHASE_MASK             (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
-# define DISPLAY_RATE_SELECT_FPA1              (1 << 8)
-
-/**
- * SDVO multiplier for 945G/GM. Not used on 965.
- *
- * \sa DPLL_MD_UDI_MULTIPLIER_MASK
- */
-# define SDVO_MULTIPLIER_MASK                  0x000000ff
-# define SDVO_MULTIPLIER_SHIFT_HIRES           4
-# define SDVO_MULTIPLIER_SHIFT_VGA             0
-
-/** @defgroup DPLL_MD
- * @{
- */
-/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */
-#define DPLL_A_MD              0x0601c
-/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */
-#define DPLL_B_MD              0x06020
-/**
- * UDI pixel divider, controlling how many pixels are stuffed into a packet.
- *
- * Value is pixels minus 1.  Must be set to 1 pixel for SDVO.
- */
-# define DPLL_MD_UDI_DIVIDER_MASK              0x3f000000
-# define DPLL_MD_UDI_DIVIDER_SHIFT             24
-/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
-# define DPLL_MD_VGA_UDI_DIVIDER_MASK          0x003f0000
-# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT         16
-/**
- * SDVO/UDI pixel multiplier.
- *
- * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
- * clock rate is 10 times the DPLL clock.  At low resolution/refresh rate
- * modes, the bus rate would be below the limits, so SDVO allows for stuffing
- * dummy bytes in the datastream at an increased clock rate, with both sides of
- * the link knowing how many bytes are fill.
- *
- * So, for a mode with a dotclock of 65Mhz, we would want to double the clock
- * rate to 130Mhz to get a bus rate of 1.30Ghz.  The DPLL clock rate would be
- * set to 130Mhz, and the SDVO multiplier set to 2x in this register and
- * through an SDVO command.
- *
- * This register field has values of multiplication factor minus 1, with
- * a maximum multiplier of 5 for SDVO.
- */
-# define DPLL_MD_UDI_MULTIPLIER_MASK           0x00003f00
-# define DPLL_MD_UDI_MULTIPLIER_SHIFT          8
-/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
- * This best be set to the default value (3) or the CRT won't work. No,
- * I don't entirely understand what this does...
- */
-# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK       0x0000003f
-# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT      0
-/** @} */
-
-#define DPLL_TEST              0x606c
-# define DPLLB_TEST_SDVO_DIV_1                 (0 << 22)
-# define DPLLB_TEST_SDVO_DIV_2                 (1 << 22)
-# define DPLLB_TEST_SDVO_DIV_4                 (2 << 22)
-# define DPLLB_TEST_SDVO_DIV_MASK              (3 << 22)
-# define DPLLB_TEST_N_BYPASS                   (1 << 19)
-# define DPLLB_TEST_M_BYPASS                   (1 << 18)
-# define DPLLB_INPUT_BUFFER_ENABLE             (1 << 16)
-# define DPLLA_TEST_N_BYPASS                   (1 << 3)
-# define DPLLA_TEST_M_BYPASS                   (1 << 2)
-# define DPLLA_INPUT_BUFFER_ENABLE             (1 << 0)
-
-#define ADPA                   0x61100
-#define ADPA_DAC_ENABLE                (1<<31)
-#define ADPA_DAC_DISABLE       0
-#define ADPA_PIPE_SELECT_MASK  (1<<30)
-#define ADPA_PIPE_A_SELECT     0
-#define ADPA_PIPE_B_SELECT     (1<<30)
-#define ADPA_USE_VGA_HVPOLARITY (1<<15)
-#define ADPA_SETS_HVPOLARITY   0
-#define ADPA_VSYNC_CNTL_DISABLE (1<<11)
-#define ADPA_VSYNC_CNTL_ENABLE 0
-#define ADPA_HSYNC_CNTL_DISABLE (1<<10)
-#define ADPA_HSYNC_CNTL_ENABLE 0
-#define ADPA_VSYNC_ACTIVE_HIGH (1<<4)
-#define ADPA_VSYNC_ACTIVE_LOW  0
-#define ADPA_HSYNC_ACTIVE_HIGH (1<<3)
-#define ADPA_HSYNC_ACTIVE_LOW  0
-
-#define FPA0           0x06040
-#define FPA1           0x06044
-#define FPB0           0x06048
-#define FPB1           0x0604c
-# define FP_N_DIV_MASK                         0x003f0000
-# define FP_N_DIV_SHIFT                                16
-# define FP_M1_DIV_MASK                                0x00003f00
-# define FP_M1_DIV_SHIFT                       8
-# define FP_M2_DIV_MASK                                0x0000003f
-# define FP_M2_DIV_SHIFT                       0
-
-
-#define PORT_HOTPLUG_EN                0x61110
-# define SDVOB_HOTPLUG_INT_EN                  (1 << 26)
-# define SDVOC_HOTPLUG_INT_EN                  (1 << 25)
-# define TV_HOTPLUG_INT_EN                     (1 << 18)
-# define CRT_HOTPLUG_INT_EN                    (1 << 9)
-# define CRT_HOTPLUG_FORCE_DETECT              (1 << 3)
-
-#define PORT_HOTPLUG_STAT      0x61114
-# define CRT_HOTPLUG_INT_STATUS                        (1 << 11)
-# define TV_HOTPLUG_INT_STATUS                 (1 << 10)
-# define CRT_HOTPLUG_MONITOR_MASK              (3 << 8)
-# define CRT_HOTPLUG_MONITOR_COLOR             (3 << 8)
-# define CRT_HOTPLUG_MONITOR_MONO              (2 << 8)
-# define CRT_HOTPLUG_MONITOR_NONE              (0 << 8)
-# define SDVOC_HOTPLUG_INT_STATUS              (1 << 7)
-# define SDVOB_HOTPLUG_INT_STATUS              (1 << 6)
-
-#define SDVOB                  0x61140
-#define SDVOC                  0x61160
-#define SDVO_ENABLE                            (1 << 31)
-#define SDVO_PIPE_B_SELECT                     (1 << 30)
-#define SDVO_STALL_SELECT                      (1 << 29)
-#define SDVO_INTERRUPT_ENABLE                  (1 << 26)
 /**
- * 915G/GM SDVO pixel multiplier.
+ * Reads a dword out of the status page, which is written to from the command
+ * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
+ * MI_STORE_DATA_IMM.
  *
- * Programmed value is multiplier - 1, up to 5x.
- *
- * \sa DPLL_MD_UDI_MULTIPLIER_MASK
- */
-#define SDVO_PORT_MULTIPLY_MASK                        (7 << 23)
-#define SDVO_PORT_MULTIPLY_SHIFT               23
-#define SDVO_PHASE_SELECT_MASK                 (15 << 19)
-#define SDVO_PHASE_SELECT_DEFAULT              (6 << 19)
-#define SDVO_CLOCK_OUTPUT_INVERT               (1 << 18)
-#define SDVOC_GANG_MODE                                (1 << 16)
-#define SDVO_BORDER_ENABLE                     (1 << 7)
-#define SDVOB_PCIE_CONCURRENCY                 (1 << 3)
-#define SDVO_DETECTED                          (1 << 2)
-/* Bits to be preserved when writing */
-#define SDVOB_PRESERVE_MASK                    ((1 << 17) | (1 << 16) | (1 << 14))
-#define SDVOC_PRESERVE_MASK                    (1 << 17)
-
-/** @defgroup LVDS
- * @{
- */
-/**
- * This register controls the LVDS output enable, pipe selection, and data
- * format selection.
+ * The following dwords have a reserved meaning:
+ * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes.
+ * 0x04: ring 0 head pointer
+ * 0x05: ring 1 head pointer (915-class)
+ * 0x06: ring 2 head pointer (915-class)
+ * 0x10-0x1b: Context status DWords (GM45)
+ * 0x1f: Last written status offset. (GM45)
  *
- * All of the clock/data pairs are force powered down by power sequencing.
- */
-#define LVDS                   0x61180
-/**
- * Enables the LVDS port.  This bit must be set before DPLLs are enabled, as
- * the DPLL semantics change when the LVDS is assigned to that pipe.
- */
-# define LVDS_PORT_EN                  (1 << 31)
-/** Selects pipe B for LVDS data.  Must be set on pre-965. */
-# define LVDS_PIPEB_SELECT             (1 << 30)
-
-/**
- * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
- * pixel.
- */
-# define LVDS_A0A2_CLKA_POWER_MASK     (3 << 8)
-# define LVDS_A0A2_CLKA_POWER_DOWN     (0 << 8)
-# define LVDS_A0A2_CLKA_POWER_UP       (3 << 8)
-/**
- * Controls the A3 data pair, which contains the additional LSBs for 24 bit
- * mode.  Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
- * on.
- */
-# define LVDS_A3_POWER_MASK            (3 << 6)
-# define LVDS_A3_POWER_DOWN            (0 << 6)
-# define LVDS_A3_POWER_UP              (3 << 6)
-/**
- * Controls the CLKB pair.  This should only be set when LVDS_B0B3_POWER_UP
- * is set.
- */
-# define LVDS_CLKB_POWER_MASK          (3 << 4)
-# define LVDS_CLKB_POWER_DOWN          (0 << 4)
-# define LVDS_CLKB_POWER_UP            (3 << 4)
-
-/**
- * Controls the B0-B3 data pairs.  This must be set to match the DPLL p2
- * setting for whether we are in dual-channel mode.  The B3 pair will
- * additionally only be powered up when LVDS_A3_POWER_UP is set.
- */
-# define LVDS_B0B3_POWER_MASK          (3 << 2)
-# define LVDS_B0B3_POWER_DOWN          (0 << 2)
-# define LVDS_B0B3_POWER_UP            (3 << 2)
-
-#define PIPEACONF 0x70008
-#define PIPEACONF_ENABLE       (1<<31)
-#define PIPEACONF_DISABLE      0
-#define PIPEACONF_DOUBLE_WIDE  (1<<30)
-#define I965_PIPECONF_ACTIVE   (1<<30)
-#define PIPEACONF_SINGLE_WIDE  0
-#define PIPEACONF_PIPE_UNLOCKED 0
-#define PIPEACONF_PIPE_LOCKED  (1<<25)
-#define PIPEACONF_PALETTE      0
-#define PIPEACONF_GAMMA                (1<<24)
-#define PIPECONF_FORCE_BORDER  (1<<25)
-#define PIPECONF_PROGRESSIVE   (0 << 21)
-#define PIPECONF_INTERLACE_W_FIELD_INDICATION  (6 << 21)
-#define PIPECONF_INTERLACE_FIELD_0_ONLY                (7 << 21)
-
-#define DSPARB   0x70030
-#define DSPARB_CSTART_MASK     (0x7f << 7)
-#define DSPARB_CSTART_SHIFT    7
-#define DSPARB_BSTART_MASK     (0x7f)           
-#define DSPARB_BSTART_SHIFT    0
-
-#define PIPEBCONF 0x71008
-#define PIPEBCONF_ENABLE       (1<<31)
-#define PIPEBCONF_DISABLE      0
-#define PIPEBCONF_DOUBLE_WIDE  (1<<30)
-#define PIPEBCONF_DISABLE      0
-#define PIPEBCONF_GAMMA                (1<<24)
-#define PIPEBCONF_PALETTE      0
-
-#define PIPEBGCMAXRED          0x71010
-#define PIPEBGCMAXGREEN                0x71014
-#define PIPEBGCMAXBLUE         0x71018
-#define PIPEBSTAT              0x71024
-#define PIPEBFRAMEHIGH         0x71040
-#define PIPEBFRAMEPIXEL                0x71044
-
-#define DSPACNTR               0x70180
-#define DSPBCNTR               0x71180
-#define DISPLAY_PLANE_ENABLE                   (1<<31)
-#define DISPLAY_PLANE_DISABLE                  0
-#define DISPPLANE_GAMMA_ENABLE                 (1<<30)
-#define DISPPLANE_GAMMA_DISABLE                        0
-#define DISPPLANE_PIXFORMAT_MASK               (0xf<<26)
-#define DISPPLANE_8BPP                         (0x2<<26)
-#define DISPPLANE_15_16BPP                     (0x4<<26)
-#define DISPPLANE_16BPP                                (0x5<<26)
-#define DISPPLANE_32BPP_NO_ALPHA               (0x6<<26)
-#define DISPPLANE_32BPP                                (0x7<<26)
-#define DISPPLANE_STEREO_ENABLE                        (1<<25)
-#define DISPPLANE_STEREO_DISABLE               0
-#define DISPPLANE_SEL_PIPE_MASK                        (1<<24)
-#define DISPPLANE_SEL_PIPE_A                   0
-#define DISPPLANE_SEL_PIPE_B                   (1<<24)
-#define DISPPLANE_SRC_KEY_ENABLE               (1<<22)
-#define DISPPLANE_SRC_KEY_DISABLE              0
-#define DISPPLANE_LINE_DOUBLE                  (1<<20)
-#define DISPPLANE_NO_LINE_DOUBLE               0
-#define DISPPLANE_STEREO_POLARITY_FIRST                0
-#define DISPPLANE_STEREO_POLARITY_SECOND       (1<<18)
-/* plane B only */
-#define DISPPLANE_ALPHA_TRANS_ENABLE           (1<<15)
-#define DISPPLANE_ALPHA_TRANS_DISABLE          0
-#define DISPPLANE_SPRITE_ABOVE_DISPLAYA                0
-#define DISPPLANE_SPRITE_ABOVE_OVERLAY         (1)
-
-#define DSPABASE               0x70184
-#define DSPASTRIDE             0x70188
-
-#define DSPBBASE               0x71184
-#define DSPBADDR               DSPBBASE
-#define DSPBSTRIDE             0x71188
-
-#define DSPAKEYVAL             0x70194
-#define DSPAKEYMASK            0x70198
-
-#define DSPAPOS                        0x7018C /* reserved */
-#define DSPASIZE               0x70190
-#define DSPBPOS                        0x7118C
-#define DSPBSIZE               0x71190
-
-#define DSPASURF               0x7019C
-#define DSPATILEOFF            0x701A4
-
-#define DSPBSURF               0x7119C
-#define DSPBTILEOFF            0x711A4
-
-#define VGACNTRL               0x71400
-# define VGA_DISP_DISABLE                      (1 << 31)
-# define VGA_2X_MODE                           (1 << 30)
-# define VGA_PIPE_B_SELECT                     (1 << 29)
-
-/*
- * Some BIOS scratch area registers.  The 845 (and 830?) store the amount
- * of video memory available to the BIOS in SWF1.
- */
-
-#define SWF0                   0x71410
-
-/*
- * 855 scratch registers.
- */
-#define SWF10                  0x70410
-
-#define SWF30                  0x72414
-
-/*
- * Overlay registers.  These are overlay registers accessed via MMIO.
- * Those loaded via the overlay register page are defined in i830_video.c.
+ * The area from dword 0x20 to 0x3ff is available for driver usage.
  */
-#define OVADD                  0x30000
-
-#define DOVSTA                 0x30008
-#define OC_BUF                 (0x3<<20)
+#define READ_HWSP(dev_priv, reg)  (((volatile u32*)(dev_priv->hw_status_page))[reg])
+#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, 5)
+#define I915_GEM_HWS_INDEX             0x20
 
-#define OGAMC5                 0x30010
-#define OGAMC4                 0x30014
-#define OGAMC3                 0x30018
-#define OGAMC2                 0x3001c
-#define OGAMC1                 0x30020
-#define OGAMC0                 0x30024
-/*
- * Palette registers
- */
-#define PALETTE_A              0x0a000
-#define PALETTE_B              0x0a800
+extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define IS_I830(dev) ((dev)->pci_device == 0x3577)
 #define IS_845G(dev) ((dev)->pci_device == 0x2562)
@@ -1119,7 +639,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02)
 
-#define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42)
+#define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
 
 #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \
                     (dev)->pci_device == 0x2E12 || \
@@ -1133,9 +653,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
                      IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
 
 #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
-                       IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev))
+                       IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev))
 
-#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev) || IS_G4X(dev))
+#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
new file mode 100644 (file)
index 0000000..9ac73dd
--- /dev/null
@@ -0,0 +1,2558 @@
+/*
+ * Copyright Â© 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include <linux/swap.h>
+
+static int
+i915_gem_object_set_domain(struct drm_gem_object *obj,
+                           uint32_t read_domains,
+                           uint32_t write_domain);
+static int
+i915_gem_object_set_domain_range(struct drm_gem_object *obj,
+                                uint64_t offset,
+                                uint64_t size,
+                                uint32_t read_domains,
+                                uint32_t write_domain);
+static int
+i915_gem_set_domain(struct drm_gem_object *obj,
+                   struct drm_file *file_priv,
+                   uint32_t read_domains,
+                   uint32_t write_domain);
+static int i915_gem_object_get_page_list(struct drm_gem_object *obj);
+static void i915_gem_object_free_page_list(struct drm_gem_object *obj);
+static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+
+static void
+i915_gem_cleanup_ringbuffer(struct drm_device *dev);
+
+int
+i915_gem_init_ioctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_init *args = data;
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (args->gtt_start >= args->gtt_end ||
+           (args->gtt_start & (PAGE_SIZE - 1)) != 0 ||
+           (args->gtt_end & (PAGE_SIZE - 1)) != 0) {
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
+       }
+
+       drm_mm_init(&dev_priv->mm.gtt_space, args->gtt_start,
+           args->gtt_end - args->gtt_start);
+
+       dev->gtt_total = (uint32_t) (args->gtt_end - args->gtt_start);
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+
+/**
+ * Creates a new mm object and returns a handle to it.
+ */
+int
+i915_gem_create_ioctl(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
+{
+       struct drm_i915_gem_create *args = data;
+       struct drm_gem_object *obj;
+       int handle, ret;
+
+       args->size = roundup(args->size, PAGE_SIZE);
+
+       /* Allocate the new object */
+       obj = drm_gem_object_alloc(dev, args->size);
+       if (obj == NULL)
+               return -ENOMEM;
+
+       ret = drm_gem_handle_create(file_priv, obj, &handle);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_handle_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       if (ret)
+               return ret;
+
+       args->handle = handle;
+
+       return 0;
+}
+
+/**
+ * Reads data from the object referenced by handle.
+ *
+ * On error, the contents of *data are undefined.
+ */
+int
+i915_gem_pread_ioctl(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       struct drm_i915_gem_pread *args = data;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       ssize_t read;
+       loff_t offset;
+       int ret;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EBADF;
+       obj_priv = obj->driver_private;
+
+       /* Bounds check source.
+        *
+        * XXX: This could use review for overflow issues...
+        */
+       if (args->offset > obj->size || args->size > obj->size ||
+           args->offset + args->size > obj->size) {
+               drm_gem_object_unreference(obj);
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->struct_mutex);
+
+       ret = i915_gem_object_set_domain_range(obj, args->offset, args->size,
+                                              I915_GEM_DOMAIN_CPU, 0);
+       if (ret != 0) {
+               drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       offset = args->offset;
+
+       read = vfs_read(obj->filp, (char __user *)(uintptr_t)args->data_ptr,
+                       args->size, &offset);
+       if (read != args->size) {
+               drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
+               if (read < 0)
+                       return read;
+               else
+                       return -EINVAL;
+       }
+
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int
+i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+                   struct drm_i915_gem_pwrite *args,
+                   struct drm_file *file_priv)
+{
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       ssize_t remain;
+       loff_t offset;
+       char __user *user_data;
+       char __iomem *vaddr;
+       char *vaddr_atomic;
+       int i, o, l;
+       int ret = 0;
+       unsigned long pfn;
+       unsigned long unwritten;
+
+       user_data = (char __user *) (uintptr_t) args->data_ptr;
+       remain = args->size;
+       if (!access_ok(VERIFY_READ, user_data, remain))
+               return -EFAULT;
+
+
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_gem_object_pin(obj, 0);
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+       ret = i915_gem_set_domain(obj, file_priv,
+                                 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+       if (ret)
+               goto fail;
+
+       obj_priv = obj->driver_private;
+       offset = obj_priv->gtt_offset + args->offset;
+       obj_priv->dirty = 1;
+
+       while (remain > 0) {
+               /* Operation in this page
+                *
+                * i = page number
+                * o = offset within page
+                * l = bytes to copy
+                */
+               i = offset >> PAGE_SHIFT;
+               o = offset & (PAGE_SIZE-1);
+               l = remain;
+               if ((o + l) > PAGE_SIZE)
+                       l = PAGE_SIZE - o;
+
+               pfn = (dev->agp->base >> PAGE_SHIFT) + i;
+
+#ifdef CONFIG_HIGHMEM
+               /* This is a workaround for the low performance of iounmap
+                * (approximate 10% cpu cost on normal 3D workloads).
+                * kmap_atomic on HIGHMEM kernels happens to let us map card
+                * memory without taking IPIs.  When the vmap rework lands
+                * we should be able to dump this hack.
+                */
+               vaddr_atomic = kmap_atomic_pfn(pfn, KM_USER0);
+#if WATCH_PWRITE
+               DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n",
+                        i, o, l, pfn, vaddr_atomic);
+#endif
+               unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + o,
+                                                             user_data, l);
+               kunmap_atomic(vaddr_atomic, KM_USER0);
+
+               if (unwritten)
+#endif /* CONFIG_HIGHMEM */
+               {
+                       vaddr = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE);
+#if WATCH_PWRITE
+                       DRM_INFO("pwrite slow i %d o %d l %d "
+                                "pfn %ld vaddr %p\n",
+                                i, o, l, pfn, vaddr);
+#endif
+                       if (vaddr == NULL) {
+                               ret = -EFAULT;
+                               goto fail;
+                       }
+                       unwritten = __copy_from_user(vaddr + o, user_data, l);
+#if WATCH_PWRITE
+                       DRM_INFO("unwritten %ld\n", unwritten);
+#endif
+                       iounmap(vaddr);
+                       if (unwritten) {
+                               ret = -EFAULT;
+                               goto fail;
+                       }
+               }
+
+               remain -= l;
+               user_data += l;
+               offset += l;
+       }
+#if WATCH_PWRITE && 1
+       i915_gem_clflush_object(obj);
+       i915_gem_dump_object(obj, args->offset + args->size, __func__, ~0);
+       i915_gem_clflush_object(obj);
+#endif
+
+fail:
+       i915_gem_object_unpin(obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+
+static int
+i915_gem_shmem_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+                     struct drm_i915_gem_pwrite *args,
+                     struct drm_file *file_priv)
+{
+       int ret;
+       loff_t offset;
+       ssize_t written;
+
+       mutex_lock(&dev->struct_mutex);
+
+       ret = i915_gem_set_domain(obj, file_priv,
+                                 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       offset = args->offset;
+
+       written = vfs_write(obj->filp,
+                           (char __user *)(uintptr_t) args->data_ptr,
+                           args->size, &offset);
+       if (written != args->size) {
+               mutex_unlock(&dev->struct_mutex);
+               if (written < 0)
+                       return written;
+               else
+                       return -EINVAL;
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+/**
+ * Writes data to the object referenced by handle.
+ *
+ * On error, the contents of the buffer that were to be modified are undefined.
+ */
+int
+i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
+{
+       struct drm_i915_gem_pwrite *args = data;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret = 0;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EBADF;
+       obj_priv = obj->driver_private;
+
+       /* Bounds check destination.
+        *
+        * XXX: This could use review for overflow issues...
+        */
+       if (args->offset > obj->size || args->size > obj->size ||
+           args->offset + args->size > obj->size) {
+               drm_gem_object_unreference(obj);
+               return -EINVAL;
+       }
+
+       /* We can only do the GTT pwrite on untiled buffers, as otherwise
+        * it would end up going through the fenced access, and we'll get
+        * different detiling behavior between reading and writing.
+        * pread/pwrite currently are reading and writing from the CPU
+        * perspective, requiring manual detiling by the client.
+        */
+       if (obj_priv->tiling_mode == I915_TILING_NONE &&
+           dev->gtt_total != 0)
+               ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
+       else
+               ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv);
+
+#if WATCH_PWRITE
+       if (ret)
+               DRM_INFO("pwrite failed %d\n", ret);
+#endif
+
+       drm_gem_object_unreference(obj);
+
+       return ret;
+}
+
+/**
+ * Called when user space prepares to use an object
+ */
+int
+i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       struct drm_i915_gem_set_domain *args = data;
+       struct drm_gem_object *obj;
+       int ret;
+
+       if (!(dev->driver->driver_features & DRIVER_GEM))
+               return -ENODEV;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EBADF;
+
+       mutex_lock(&dev->struct_mutex);
+#if WATCH_BUF
+       DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n",
+                obj, obj->size, args->read_domains, args->write_domain);
+#endif
+       ret = i915_gem_set_domain(obj, file_priv,
+                                 args->read_domains, args->write_domain);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+/**
+ * Called when user space has done writes to this buffer
+ */
+int
+i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv)
+{
+       struct drm_i915_gem_sw_finish *args = data;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret = 0;
+
+       if (!(dev->driver->driver_features & DRIVER_GEM))
+               return -ENODEV;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL) {
+               mutex_unlock(&dev->struct_mutex);
+               return -EBADF;
+       }
+
+#if WATCH_BUF
+       DRM_INFO("%s: sw_finish %d (%p %d)\n",
+                __func__, args->handle, obj, obj->size);
+#endif
+       obj_priv = obj->driver_private;
+
+       /* Pinned buffers may be scanout, so flush the cache */
+       if ((obj->write_domain & I915_GEM_DOMAIN_CPU) && obj_priv->pin_count) {
+               i915_gem_clflush_object(obj);
+               drm_agp_chipset_flush(dev);
+       }
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+/**
+ * Maps the contents of an object, returning the address it is mapped
+ * into.
+ *
+ * While the mapping holds a reference on the contents of the object, it doesn't
+ * imply a ref on the object itself.
+ */
+int
+i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv)
+{
+       struct drm_i915_gem_mmap *args = data;
+       struct drm_gem_object *obj;
+       loff_t offset;
+       unsigned long addr;
+
+       if (!(dev->driver->driver_features & DRIVER_GEM))
+               return -ENODEV;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EBADF;
+
+       offset = args->offset;
+
+       down_write(&current->mm->mmap_sem);
+       addr = do_mmap(obj->filp, 0, args->size,
+                      PROT_READ | PROT_WRITE, MAP_SHARED,
+                      args->offset);
+       up_write(&current->mm->mmap_sem);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+       if (IS_ERR((void *)addr))
+               return addr;
+
+       args->addr_ptr = (uint64_t) addr;
+
+       return 0;
+}
+
+static void
+i915_gem_object_free_page_list(struct drm_gem_object *obj)
+{
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int page_count = obj->size / PAGE_SIZE;
+       int i;
+
+       if (obj_priv->page_list == NULL)
+               return;
+
+
+       for (i = 0; i < page_count; i++)
+               if (obj_priv->page_list[i] != NULL) {
+                       if (obj_priv->dirty)
+                               set_page_dirty(obj_priv->page_list[i]);
+                       mark_page_accessed(obj_priv->page_list[i]);
+                       page_cache_release(obj_priv->page_list[i]);
+               }
+       obj_priv->dirty = 0;
+
+       drm_free(obj_priv->page_list,
+                page_count * sizeof(struct page *),
+                DRM_MEM_DRIVER);
+       obj_priv->page_list = NULL;
+}
+
+static void
+i915_gem_object_move_to_active(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+       /* Add a reference if we're newly entering the active list. */
+       if (!obj_priv->active) {
+               drm_gem_object_reference(obj);
+               obj_priv->active = 1;
+       }
+       /* Move from whatever list we were on to the tail of execution. */
+       list_move_tail(&obj_priv->list,
+                      &dev_priv->mm.active_list);
+}
+
+
+static void
+i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+       if (obj_priv->pin_count != 0)
+               list_del_init(&obj_priv->list);
+       else
+               list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+
+       if (obj_priv->active) {
+               obj_priv->active = 0;
+               drm_gem_object_unreference(obj);
+       }
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+}
+
+/**
+ * Creates a new sequence number, emitting a write of it to the status page
+ * plus an interrupt, which will trigger i915_user_interrupt_handler.
+ *
+ * Must be called with struct_lock held.
+ *
+ * Returned sequence numbers are nonzero on success.
+ */
+static uint32_t
+i915_add_request(struct drm_device *dev, uint32_t flush_domains)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_request *request;
+       uint32_t seqno;
+       int was_empty;
+       RING_LOCALS;
+
+       request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER);
+       if (request == NULL)
+               return 0;
+
+       /* Grab the seqno we're going to make this request be, and bump the
+        * next (skipping 0 so it can be the reserved no-seqno value).
+        */
+       seqno = dev_priv->mm.next_gem_seqno;
+       dev_priv->mm.next_gem_seqno++;
+       if (dev_priv->mm.next_gem_seqno == 0)
+               dev_priv->mm.next_gem_seqno++;
+
+       BEGIN_LP_RING(4);
+       OUT_RING(MI_STORE_DWORD_INDEX);
+       OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+       OUT_RING(seqno);
+
+       OUT_RING(MI_USER_INTERRUPT);
+       ADVANCE_LP_RING();
+
+       DRM_DEBUG("%d\n", seqno);
+
+       request->seqno = seqno;
+       request->emitted_jiffies = jiffies;
+       request->flush_domains = flush_domains;
+       was_empty = list_empty(&dev_priv->mm.request_list);
+       list_add_tail(&request->list, &dev_priv->mm.request_list);
+
+       if (was_empty && !dev_priv->mm.suspended)
+               schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
+       return seqno;
+}
+
+/**
+ * Command execution barrier
+ *
+ * Ensures that all commands in the ring are finished
+ * before signalling the CPU
+ */
+static uint32_t
+i915_retire_commands(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
+       uint32_t flush_domains = 0;
+       RING_LOCALS;
+
+       /* The sampler always gets flushed on i965 (sigh) */
+       if (IS_I965G(dev))
+               flush_domains |= I915_GEM_DOMAIN_SAMPLER;
+       BEGIN_LP_RING(2);
+       OUT_RING(cmd);
+       OUT_RING(0); /* noop */
+       ADVANCE_LP_RING();
+       return flush_domains;
+}
+
+/**
+ * Moves buffers associated only with the given active seqno from the active
+ * to inactive list, potentially freeing them.
+ */
+static void
+i915_gem_retire_request(struct drm_device *dev,
+                       struct drm_i915_gem_request *request)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       /* Move any buffers on the active list that are no longer referenced
+        * by the ringbuffer to the flushing/inactive lists as appropriate.
+        */
+       while (!list_empty(&dev_priv->mm.active_list)) {
+               struct drm_gem_object *obj;
+               struct drm_i915_gem_object *obj_priv;
+
+               obj_priv = list_first_entry(&dev_priv->mm.active_list,
+                                           struct drm_i915_gem_object,
+                                           list);
+               obj = obj_priv->obj;
+
+               /* If the seqno being retired doesn't match the oldest in the
+                * list, then the oldest in the list must still be newer than
+                * this seqno.
+                */
+               if (obj_priv->last_rendering_seqno != request->seqno)
+                       return;
+#if WATCH_LRU
+               DRM_INFO("%s: retire %d moves to inactive list %p\n",
+                        __func__, request->seqno, obj);
+#endif
+
+               if (obj->write_domain != 0) {
+                       list_move_tail(&obj_priv->list,
+                                      &dev_priv->mm.flushing_list);
+               } else {
+                       i915_gem_object_move_to_inactive(obj);
+               }
+       }
+
+       if (request->flush_domains != 0) {
+               struct drm_i915_gem_object *obj_priv, *next;
+
+               /* Clear the write domain and activity from any buffers
+                * that are just waiting for a flush matching the one retired.
+                */
+               list_for_each_entry_safe(obj_priv, next,
+                                        &dev_priv->mm.flushing_list, list) {
+                       struct drm_gem_object *obj = obj_priv->obj;
+
+                       if (obj->write_domain & request->flush_domains) {
+                               obj->write_domain = 0;
+                               i915_gem_object_move_to_inactive(obj);
+                       }
+               }
+
+       }
+}
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static int
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+       return (int32_t)(seq1 - seq2) >= 0;
+}
+
+uint32_t
+i915_get_gem_seqno(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
+}
+
+/**
+ * This function clears the request list as sequence numbers are passed.
+ */
+void
+i915_gem_retire_requests(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       uint32_t seqno;
+
+       seqno = i915_get_gem_seqno(dev);
+
+       while (!list_empty(&dev_priv->mm.request_list)) {
+               struct drm_i915_gem_request *request;
+               uint32_t retiring_seqno;
+
+               request = list_first_entry(&dev_priv->mm.request_list,
+                                          struct drm_i915_gem_request,
+                                          list);
+               retiring_seqno = request->seqno;
+
+               if (i915_seqno_passed(seqno, retiring_seqno) ||
+                   dev_priv->mm.wedged) {
+                       i915_gem_retire_request(dev, request);
+
+                       list_del(&request->list);
+                       drm_free(request, sizeof(*request), DRM_MEM_DRIVER);
+               } else
+                       break;
+       }
+}
+
+void
+i915_gem_retire_work_handler(struct work_struct *work)
+{
+       drm_i915_private_t *dev_priv;
+       struct drm_device *dev;
+
+       dev_priv = container_of(work, drm_i915_private_t,
+                               mm.retire_work.work);
+       dev = dev_priv->dev;
+
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_retire_requests(dev);
+       if (!dev_priv->mm.suspended &&
+           !list_empty(&dev_priv->mm.request_list))
+               schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
+       mutex_unlock(&dev->struct_mutex);
+}
+
+/**
+ * Waits for a sequence number to be signaled, and cleans up the
+ * request and object lists appropriately for that event.
+ */
+static int
+i915_wait_request(struct drm_device *dev, uint32_t seqno)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret = 0;
+
+       BUG_ON(seqno == 0);
+
+       if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
+               dev_priv->mm.waiting_gem_seqno = seqno;
+               i915_user_irq_get(dev);
+               ret = wait_event_interruptible(dev_priv->irq_queue,
+                                              i915_seqno_passed(i915_get_gem_seqno(dev),
+                                                                seqno) ||
+                                              dev_priv->mm.wedged);
+               i915_user_irq_put(dev);
+               dev_priv->mm.waiting_gem_seqno = 0;
+       }
+       if (dev_priv->mm.wedged)
+               ret = -EIO;
+
+       if (ret && ret != -ERESTARTSYS)
+               DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
+                         __func__, ret, seqno, i915_get_gem_seqno(dev));
+
+       /* Directly dispatch request retiring.  While we have the work queue
+        * to handle this, the waiter on a request often wants an associated
+        * buffer to have made it to the inactive list, and we would need
+        * a separate wait queue to handle that.
+        */
+       if (ret == 0)
+               i915_gem_retire_requests(dev);
+
+       return ret;
+}
+
+static void
+i915_gem_flush(struct drm_device *dev,
+              uint32_t invalidate_domains,
+              uint32_t flush_domains)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       uint32_t cmd;
+       RING_LOCALS;
+
+#if WATCH_EXEC
+       DRM_INFO("%s: invalidate %08x flush %08x\n", __func__,
+                 invalidate_domains, flush_domains);
+#endif
+
+       if (flush_domains & I915_GEM_DOMAIN_CPU)
+               drm_agp_chipset_flush(dev);
+
+       if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU |
+                                                    I915_GEM_DOMAIN_GTT)) {
+               /*
+                * read/write caches:
+                *
+                * I915_GEM_DOMAIN_RENDER is always invalidated, but is
+                * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
+                * also flushed at 2d versus 3d pipeline switches.
+                *
+                * read-only caches:
+                *
+                * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
+                * MI_READ_FLUSH is set, and is always flushed on 965.
+                *
+                * I915_GEM_DOMAIN_COMMAND may not exist?
+                *
+                * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
+                * invalidated when MI_EXE_FLUSH is set.
+                *
+                * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
+                * invalidated with every MI_FLUSH.
+                *
+                * TLBs:
+                *
+                * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
+                * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
+                * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
+                * are flushed at any MI_FLUSH.
+                */
+
+               cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
+               if ((invalidate_domains|flush_domains) &
+                   I915_GEM_DOMAIN_RENDER)
+                       cmd &= ~MI_NO_WRITE_FLUSH;
+               if (!IS_I965G(dev)) {
+                       /*
+                        * On the 965, the sampler cache always gets flushed
+                        * and this bit is reserved.
+                        */
+                       if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
+                               cmd |= MI_READ_FLUSH;
+               }
+               if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
+                       cmd |= MI_EXE_FLUSH;
+
+#if WATCH_EXEC
+               DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd);
+#endif
+               BEGIN_LP_RING(2);
+               OUT_RING(cmd);
+               OUT_RING(0); /* noop */
+               ADVANCE_LP_RING();
+       }
+}
+
+/**
+ * Ensures that all rendering to the object has completed and the object is
+ * safe to unbind from the GTT or access from the CPU.
+ */
+static int
+i915_gem_object_wait_rendering(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int ret;
+
+       /* If there are writes queued to the buffer, flush and
+        * create a new seqno to wait for.
+        */
+       if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) {
+               uint32_t write_domain = obj->write_domain;
+#if WATCH_BUF
+               DRM_INFO("%s: flushing object %p from write domain %08x\n",
+                         __func__, obj, write_domain);
+#endif
+               i915_gem_flush(dev, 0, write_domain);
+
+               i915_gem_object_move_to_active(obj);
+               obj_priv->last_rendering_seqno = i915_add_request(dev,
+                                                                 write_domain);
+               BUG_ON(obj_priv->last_rendering_seqno == 0);
+#if WATCH_LRU
+               DRM_INFO("%s: flush moves to exec list %p\n", __func__, obj);
+#endif
+       }
+
+       /* If there is rendering queued on the buffer being evicted, wait for
+        * it.
+        */
+       if (obj_priv->active) {
+#if WATCH_BUF
+               DRM_INFO("%s: object %p wait for seqno %08x\n",
+                         __func__, obj, obj_priv->last_rendering_seqno);
+#endif
+               ret = i915_wait_request(dev, obj_priv->last_rendering_seqno);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * Unbinds an object from the GTT aperture.
+ */
+static int
+i915_gem_object_unbind(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int ret = 0;
+
+#if WATCH_BUF
+       DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj);
+       DRM_INFO("gtt_space %p\n", obj_priv->gtt_space);
+#endif
+       if (obj_priv->gtt_space == NULL)
+               return 0;
+
+       if (obj_priv->pin_count != 0) {
+               DRM_ERROR("Attempting to unbind pinned buffer\n");
+               return -EINVAL;
+       }
+
+       /* Wait for any rendering to complete
+        */
+       ret = i915_gem_object_wait_rendering(obj);
+       if (ret) {
+               DRM_ERROR("wait_rendering failed: %d\n", ret);
+               return ret;
+       }
+
+       /* Move the object to the CPU domain to ensure that
+        * any possible CPU writes while it's not in the GTT
+        * are flushed when we go to remap it. This will
+        * also ensure that all pending GPU writes are finished
+        * before we unbind.
+        */
+       ret = i915_gem_object_set_domain(obj, I915_GEM_DOMAIN_CPU,
+                                        I915_GEM_DOMAIN_CPU);
+       if (ret) {
+               DRM_ERROR("set_domain failed: %d\n", ret);
+               return ret;
+       }
+
+       if (obj_priv->agp_mem != NULL) {
+               drm_unbind_agp(obj_priv->agp_mem);
+               drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
+               obj_priv->agp_mem = NULL;
+       }
+
+       BUG_ON(obj_priv->active);
+
+       i915_gem_object_free_page_list(obj);
+
+       if (obj_priv->gtt_space) {
+               atomic_dec(&dev->gtt_count);
+               atomic_sub(obj->size, &dev->gtt_memory);
+
+               drm_mm_put_block(obj_priv->gtt_space);
+               obj_priv->gtt_space = NULL;
+       }
+
+       /* Remove ourselves from the LRU list if present. */
+       if (!list_empty(&obj_priv->list))
+               list_del_init(&obj_priv->list);
+
+       return 0;
+}
+
+static int
+i915_gem_evict_something(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret = 0;
+
+       for (;;) {
+               /* If there's an inactive buffer available now, grab it
+                * and be done.
+                */
+               if (!list_empty(&dev_priv->mm.inactive_list)) {
+                       obj_priv = list_first_entry(&dev_priv->mm.inactive_list,
+                                                   struct drm_i915_gem_object,
+                                                   list);
+                       obj = obj_priv->obj;
+                       BUG_ON(obj_priv->pin_count != 0);
+#if WATCH_LRU
+                       DRM_INFO("%s: evicting %p\n", __func__, obj);
+#endif
+                       BUG_ON(obj_priv->active);
+
+                       /* Wait on the rendering and unbind the buffer. */
+                       ret = i915_gem_object_unbind(obj);
+                       break;
+               }
+
+               /* If we didn't get anything, but the ring is still processing
+                * things, wait for one of those things to finish and hopefully
+                * leave us a buffer to evict.
+                */
+               if (!list_empty(&dev_priv->mm.request_list)) {
+                       struct drm_i915_gem_request *request;
+
+                       request = list_first_entry(&dev_priv->mm.request_list,
+                                                  struct drm_i915_gem_request,
+                                                  list);
+
+                       ret = i915_wait_request(dev, request->seqno);
+                       if (ret)
+                               break;
+
+                       /* if waiting caused an object to become inactive,
+                        * then loop around and wait for it. Otherwise, we
+                        * assume that waiting freed and unbound something,
+                        * so there should now be some space in the GTT
+                        */
+                       if (!list_empty(&dev_priv->mm.inactive_list))
+                               continue;
+                       break;
+               }
+
+               /* If we didn't have anything on the request list but there
+                * are buffers awaiting a flush, emit one and try again.
+                * When we wait on it, those buffers waiting for that flush
+                * will get moved to inactive.
+                */
+               if (!list_empty(&dev_priv->mm.flushing_list)) {
+                       obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
+                                                   struct drm_i915_gem_object,
+                                                   list);
+                       obj = obj_priv->obj;
+
+                       i915_gem_flush(dev,
+                                      obj->write_domain,
+                                      obj->write_domain);
+                       i915_add_request(dev, obj->write_domain);
+
+                       obj = NULL;
+                       continue;
+               }
+
+               DRM_ERROR("inactive empty %d request empty %d "
+                         "flushing empty %d\n",
+                         list_empty(&dev_priv->mm.inactive_list),
+                         list_empty(&dev_priv->mm.request_list),
+                         list_empty(&dev_priv->mm.flushing_list));
+               /* If we didn't do any of the above, there's nothing to be done
+                * and we just can't fit it in.
+                */
+               return -ENOMEM;
+       }
+       return ret;
+}
+
+static int
+i915_gem_object_get_page_list(struct drm_gem_object *obj)
+{
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int page_count, i;
+       struct address_space *mapping;
+       struct inode *inode;
+       struct page *page;
+       int ret;
+
+       if (obj_priv->page_list)
+               return 0;
+
+       /* Get the list of pages out of our struct file.  They'll be pinned
+        * at this point until we release them.
+        */
+       page_count = obj->size / PAGE_SIZE;
+       BUG_ON(obj_priv->page_list != NULL);
+       obj_priv->page_list = drm_calloc(page_count, sizeof(struct page *),
+                                        DRM_MEM_DRIVER);
+       if (obj_priv->page_list == NULL) {
+               DRM_ERROR("Faled to allocate page list\n");
+               return -ENOMEM;
+       }
+
+       inode = obj->filp->f_path.dentry->d_inode;
+       mapping = inode->i_mapping;
+       for (i = 0; i < page_count; i++) {
+               page = read_mapping_page(mapping, i, NULL);
+               if (IS_ERR(page)) {
+                       ret = PTR_ERR(page);
+                       DRM_ERROR("read_mapping_page failed: %d\n", ret);
+                       i915_gem_object_free_page_list(obj);
+                       return ret;
+               }
+               obj_priv->page_list[i] = page;
+       }
+       return 0;
+}
+
+/**
+ * Finds free space in the GTT aperture and binds the object there.
+ */
+static int
+i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
+{
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       struct drm_mm_node *free_space;
+       int page_count, ret;
+
+       if (alignment == 0)
+               alignment = PAGE_SIZE;
+       if (alignment & (PAGE_SIZE - 1)) {
+               DRM_ERROR("Invalid object alignment requested %u\n", alignment);
+               return -EINVAL;
+       }
+
+ search_free:
+       free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
+                                       obj->size, alignment, 0);
+       if (free_space != NULL) {
+               obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
+                                                      alignment);
+               if (obj_priv->gtt_space != NULL) {
+                       obj_priv->gtt_space->private = obj;
+                       obj_priv->gtt_offset = obj_priv->gtt_space->start;
+               }
+       }
+       if (obj_priv->gtt_space == NULL) {
+               /* If the gtt is empty and we're still having trouble
+                * fitting our object in, we're out of memory.
+                */
+#if WATCH_LRU
+               DRM_INFO("%s: GTT full, evicting something\n", __func__);
+#endif
+               if (list_empty(&dev_priv->mm.inactive_list) &&
+                   list_empty(&dev_priv->mm.flushing_list) &&
+                   list_empty(&dev_priv->mm.active_list)) {
+                       DRM_ERROR("GTT full, but LRU list empty\n");
+                       return -ENOMEM;
+               }
+
+               ret = i915_gem_evict_something(dev);
+               if (ret != 0) {
+                       DRM_ERROR("Failed to evict a buffer %d\n", ret);
+                       return ret;
+               }
+               goto search_free;
+       }
+
+#if WATCH_BUF
+       DRM_INFO("Binding object of size %d at 0x%08x\n",
+                obj->size, obj_priv->gtt_offset);
+#endif
+       ret = i915_gem_object_get_page_list(obj);
+       if (ret) {
+               drm_mm_put_block(obj_priv->gtt_space);
+               obj_priv->gtt_space = NULL;
+               return ret;
+       }
+
+       page_count = obj->size / PAGE_SIZE;
+       /* Create an AGP memory structure pointing at our pages, and bind it
+        * into the GTT.
+        */
+       obj_priv->agp_mem = drm_agp_bind_pages(dev,
+                                              obj_priv->page_list,
+                                              page_count,
+                                              obj_priv->gtt_offset,
+                                              obj_priv->agp_type);
+       if (obj_priv->agp_mem == NULL) {
+               i915_gem_object_free_page_list(obj);
+               drm_mm_put_block(obj_priv->gtt_space);
+               obj_priv->gtt_space = NULL;
+               return -ENOMEM;
+       }
+       atomic_inc(&dev->gtt_count);
+       atomic_add(obj->size, &dev->gtt_memory);
+
+       /* Assert that the object is not currently in any GPU domain. As it
+        * wasn't in the GTT, there shouldn't be any way it could have been in
+        * a GPU cache
+        */
+       BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+       BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+
+       return 0;
+}
+
+void
+i915_gem_clflush_object(struct drm_gem_object *obj)
+{
+       struct drm_i915_gem_object      *obj_priv = obj->driver_private;
+
+       /* If we don't have a page list set up, then we're not pinned
+        * to GPU, and we can ignore the cache flush because it'll happen
+        * again at bind time.
+        */
+       if (obj_priv->page_list == NULL)
+               return;
+
+       drm_clflush_pages(obj_priv->page_list, obj->size / PAGE_SIZE);
+}
+
+/*
+ * Set the next domain for the specified object. This
+ * may not actually perform the necessary flushing/invaliding though,
+ * as that may want to be batched with other set_domain operations
+ *
+ * This is (we hope) the only really tricky part of gem. The goal
+ * is fairly simple -- track which caches hold bits of the object
+ * and make sure they remain coherent. A few concrete examples may
+ * help to explain how it works. For shorthand, we use the notation
+ * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the
+ * a pair of read and write domain masks.
+ *
+ * Case 1: the batch buffer
+ *
+ *     1. Allocated
+ *     2. Written by CPU
+ *     3. Mapped to GTT
+ *     4. Read by GPU
+ *     5. Unmapped from GTT
+ *     6. Freed
+ *
+ *     Let's take these a step at a time
+ *
+ *     1. Allocated
+ *             Pages allocated from the kernel may still have
+ *             cache contents, so we set them to (CPU, CPU) always.
+ *     2. Written by CPU (using pwrite)
+ *             The pwrite function calls set_domain (CPU, CPU) and
+ *             this function does nothing (as nothing changes)
+ *     3. Mapped by GTT
+ *             This function asserts that the object is not
+ *             currently in any GPU-based read or write domains
+ *     4. Read by GPU
+ *             i915_gem_execbuffer calls set_domain (COMMAND, 0).
+ *             As write_domain is zero, this function adds in the
+ *             current read domains (CPU+COMMAND, 0).
+ *             flush_domains is set to CPU.
+ *             invalidate_domains is set to COMMAND
+ *             clflush is run to get data out of the CPU caches
+ *             then i915_dev_set_domain calls i915_gem_flush to
+ *             emit an MI_FLUSH and drm_agp_chipset_flush
+ *     5. Unmapped from GTT
+ *             i915_gem_object_unbind calls set_domain (CPU, CPU)
+ *             flush_domains and invalidate_domains end up both zero
+ *             so no flushing/invalidating happens
+ *     6. Freed
+ *             yay, done
+ *
+ * Case 2: The shared render buffer
+ *
+ *     1. Allocated
+ *     2. Mapped to GTT
+ *     3. Read/written by GPU
+ *     4. set_domain to (CPU,CPU)
+ *     5. Read/written by CPU
+ *     6. Read/written by GPU
+ *
+ *     1. Allocated
+ *             Same as last example, (CPU, CPU)
+ *     2. Mapped to GTT
+ *             Nothing changes (assertions find that it is not in the GPU)
+ *     3. Read/written by GPU
+ *             execbuffer calls set_domain (RENDER, RENDER)
+ *             flush_domains gets CPU
+ *             invalidate_domains gets GPU
+ *             clflush (obj)
+ *             MI_FLUSH and drm_agp_chipset_flush
+ *     4. set_domain (CPU, CPU)
+ *             flush_domains gets GPU
+ *             invalidate_domains gets CPU
+ *             wait_rendering (obj) to make sure all drawing is complete.
+ *             This will include an MI_FLUSH to get the data from GPU
+ *             to memory
+ *             clflush (obj) to invalidate the CPU cache
+ *             Another MI_FLUSH in i915_gem_flush (eliminate this somehow?)
+ *     5. Read/written by CPU
+ *             cache lines are loaded and dirtied
+ *     6. Read written by GPU
+ *             Same as last GPU access
+ *
+ * Case 3: The constant buffer
+ *
+ *     1. Allocated
+ *     2. Written by CPU
+ *     3. Read by GPU
+ *     4. Updated (written) by CPU again
+ *     5. Read by GPU
+ *
+ *     1. Allocated
+ *             (CPU, CPU)
+ *     2. Written by CPU
+ *             (CPU, CPU)
+ *     3. Read by GPU
+ *             (CPU+RENDER, 0)
+ *             flush_domains = CPU
+ *             invalidate_domains = RENDER
+ *             clflush (obj)
+ *             MI_FLUSH
+ *             drm_agp_chipset_flush
+ *     4. Updated (written) by CPU again
+ *             (CPU, CPU)
+ *             flush_domains = 0 (no previous write domain)
+ *             invalidate_domains = 0 (no new read domains)
+ *     5. Read by GPU
+ *             (CPU+RENDER, 0)
+ *             flush_domains = CPU
+ *             invalidate_domains = RENDER
+ *             clflush (obj)
+ *             MI_FLUSH
+ *             drm_agp_chipset_flush
+ */
+static int
+i915_gem_object_set_domain(struct drm_gem_object *obj,
+                           uint32_t read_domains,
+                           uint32_t write_domain)
+{
+       struct drm_device               *dev = obj->dev;
+       struct drm_i915_gem_object      *obj_priv = obj->driver_private;
+       uint32_t                        invalidate_domains = 0;
+       uint32_t                        flush_domains = 0;
+       int                             ret;
+
+#if WATCH_BUF
+       DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
+                __func__, obj,
+                obj->read_domains, read_domains,
+                obj->write_domain, write_domain);
+#endif
+       /*
+        * If the object isn't moving to a new write domain,
+        * let the object stay in multiple read domains
+        */
+       if (write_domain == 0)
+               read_domains |= obj->read_domains;
+       else
+               obj_priv->dirty = 1;
+
+       /*
+        * Flush the current write domain if
+        * the new read domains don't match. Invalidate
+        * any read domains which differ from the old
+        * write domain
+        */
+       if (obj->write_domain && obj->write_domain != read_domains) {
+               flush_domains |= obj->write_domain;
+               invalidate_domains |= read_domains & ~obj->write_domain;
+       }
+       /*
+        * Invalidate any read caches which may have
+        * stale data. That is, any new read domains.
+        */
+       invalidate_domains |= read_domains & ~obj->read_domains;
+       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
+#if WATCH_BUF
+               DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
+                        __func__, flush_domains, invalidate_domains);
+#endif
+               /*
+                * If we're invaliding the CPU cache and flushing a GPU cache,
+                * then pause for rendering so that the GPU caches will be
+                * flushed before the cpu cache is invalidated
+                */
+               if ((invalidate_domains & I915_GEM_DOMAIN_CPU) &&
+                   (flush_domains & ~(I915_GEM_DOMAIN_CPU |
+                                      I915_GEM_DOMAIN_GTT))) {
+                       ret = i915_gem_object_wait_rendering(obj);
+                       if (ret)
+                               return ret;
+               }
+               i915_gem_clflush_object(obj);
+       }
+
+       if ((write_domain | flush_domains) != 0)
+               obj->write_domain = write_domain;
+
+       /* If we're invalidating the CPU domain, clear the per-page CPU
+        * domain list as well.
+        */
+       if (obj_priv->page_cpu_valid != NULL &&
+           (write_domain != 0 ||
+            read_domains & I915_GEM_DOMAIN_CPU)) {
+               drm_free(obj_priv->page_cpu_valid, obj->size / PAGE_SIZE,
+                        DRM_MEM_DRIVER);
+               obj_priv->page_cpu_valid = NULL;
+       }
+       obj->read_domains = read_domains;
+
+       dev->invalidate_domains |= invalidate_domains;
+       dev->flush_domains |= flush_domains;
+#if WATCH_BUF
+       DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n",
+                __func__,
+                obj->read_domains, obj->write_domain,
+                dev->invalidate_domains, dev->flush_domains);
+#endif
+       return 0;
+}
+
+/**
+ * Set the read/write domain on a range of the object.
+ *
+ * Currently only implemented for CPU reads, otherwise drops to normal
+ * i915_gem_object_set_domain().
+ */
+static int
+i915_gem_object_set_domain_range(struct drm_gem_object *obj,
+                                uint64_t offset,
+                                uint64_t size,
+                                uint32_t read_domains,
+                                uint32_t write_domain)
+{
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int ret, i;
+
+       if (obj->read_domains & I915_GEM_DOMAIN_CPU)
+               return 0;
+
+       if (read_domains != I915_GEM_DOMAIN_CPU ||
+           write_domain != 0)
+               return i915_gem_object_set_domain(obj,
+                                                 read_domains, write_domain);
+
+       /* Wait on any GPU rendering to the object to be flushed. */
+       if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) {
+               ret = i915_gem_object_wait_rendering(obj);
+               if (ret)
+                       return ret;
+       }
+
+       if (obj_priv->page_cpu_valid == NULL) {
+               obj_priv->page_cpu_valid = drm_calloc(1, obj->size / PAGE_SIZE,
+                                                     DRM_MEM_DRIVER);
+       }
+
+       /* Flush the cache on any pages that are still invalid from the CPU's
+        * perspective.
+        */
+       for (i = offset / PAGE_SIZE; i <= (offset + size - 1) / PAGE_SIZE; i++) {
+               if (obj_priv->page_cpu_valid[i])
+                       continue;
+
+               drm_clflush_pages(obj_priv->page_list + i, 1);
+
+               obj_priv->page_cpu_valid[i] = 1;
+       }
+
+       return 0;
+}
+
+/**
+ * Once all of the objects have been set in the proper domain,
+ * perform the necessary flush and invalidate operations.
+ *
+ * Returns the write domains flushed, for use in flush tracking.
+ */
+static uint32_t
+i915_gem_dev_set_domain(struct drm_device *dev)
+{
+       uint32_t flush_domains = dev->flush_domains;
+
+       /*
+        * Now that all the buffers are synced to the proper domains,
+        * flush and invalidate the collected domains
+        */
+       if (dev->invalidate_domains | dev->flush_domains) {
+#if WATCH_EXEC
+               DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
+                         __func__,
+                        dev->invalidate_domains,
+                        dev->flush_domains);
+#endif
+               i915_gem_flush(dev,
+                              dev->invalidate_domains,
+                              dev->flush_domains);
+               dev->invalidate_domains = 0;
+               dev->flush_domains = 0;
+       }
+
+       return flush_domains;
+}
+
+/**
+ * Pin an object to the GTT and evaluate the relocations landing in it.
+ */
+static int
+i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
+                                struct drm_file *file_priv,
+                                struct drm_i915_gem_exec_object *entry)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_relocation_entry reloc;
+       struct drm_i915_gem_relocation_entry __user *relocs;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int i, ret;
+       uint32_t last_reloc_offset = -1;
+       void __iomem *reloc_page = NULL;
+
+       /* Choose the GTT offset for our buffer and put it there. */
+       ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
+       if (ret)
+               return ret;
+
+       entry->offset = obj_priv->gtt_offset;
+
+       relocs = (struct drm_i915_gem_relocation_entry __user *)
+                (uintptr_t) entry->relocs_ptr;
+       /* Apply the relocations, using the GTT aperture to avoid cache
+        * flushing requirements.
+        */
+       for (i = 0; i < entry->relocation_count; i++) {
+               struct drm_gem_object *target_obj;
+               struct drm_i915_gem_object *target_obj_priv;
+               uint32_t reloc_val, reloc_offset;
+               uint32_t __iomem *reloc_entry;
+
+               ret = copy_from_user(&reloc, relocs + i, sizeof(reloc));
+               if (ret != 0) {
+                       i915_gem_object_unpin(obj);
+                       return ret;
+               }
+
+               target_obj = drm_gem_object_lookup(obj->dev, file_priv,
+                                                  reloc.target_handle);
+               if (target_obj == NULL) {
+                       i915_gem_object_unpin(obj);
+                       return -EBADF;
+               }
+               target_obj_priv = target_obj->driver_private;
+
+               /* The target buffer should have appeared before us in the
+                * exec_object list, so it should have a GTT space bound by now.
+                */
+               if (target_obj_priv->gtt_space == NULL) {
+                       DRM_ERROR("No GTT space found for object %d\n",
+                                 reloc.target_handle);
+                       drm_gem_object_unreference(target_obj);
+                       i915_gem_object_unpin(obj);
+                       return -EINVAL;
+               }
+
+               if (reloc.offset > obj->size - 4) {
+                       DRM_ERROR("Relocation beyond object bounds: "
+                                 "obj %p target %d offset %d size %d.\n",
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset, (int) obj->size);
+                       drm_gem_object_unreference(target_obj);
+                       i915_gem_object_unpin(obj);
+                       return -EINVAL;
+               }
+               if (reloc.offset & 3) {
+                       DRM_ERROR("Relocation not 4-byte aligned: "
+                                 "obj %p target %d offset %d.\n",
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset);
+                       drm_gem_object_unreference(target_obj);
+                       i915_gem_object_unpin(obj);
+                       return -EINVAL;
+               }
+
+               if (reloc.write_domain && target_obj->pending_write_domain &&
+                   reloc.write_domain != target_obj->pending_write_domain) {
+                       DRM_ERROR("Write domain conflict: "
+                                 "obj %p target %d offset %d "
+                                 "new %08x old %08x\n",
+                                 obj, reloc.target_handle,
+                                 (int) reloc.offset,
+                                 reloc.write_domain,
+                                 target_obj->pending_write_domain);
+                       drm_gem_object_unreference(target_obj);
+                       i915_gem_object_unpin(obj);
+                       return -EINVAL;
+               }
+
+#if WATCH_RELOC
+               DRM_INFO("%s: obj %p offset %08x target %d "
+                        "read %08x write %08x gtt %08x "
+                        "presumed %08x delta %08x\n",
+                        __func__,
+                        obj,
+                        (int) reloc.offset,
+                        (int) reloc.target_handle,
+                        (int) reloc.read_domains,
+                        (int) reloc.write_domain,
+                        (int) target_obj_priv->gtt_offset,
+                        (int) reloc.presumed_offset,
+                        reloc.delta);
+#endif
+
+               target_obj->pending_read_domains |= reloc.read_domains;
+               target_obj->pending_write_domain |= reloc.write_domain;
+
+               /* If the relocation already has the right value in it, no
+                * more work needs to be done.
+                */
+               if (target_obj_priv->gtt_offset == reloc.presumed_offset) {
+                       drm_gem_object_unreference(target_obj);
+                       continue;
+               }
+
+               /* Now that we're going to actually write some data in,
+                * make sure that any rendering using this buffer's contents
+                * is completed.
+                */
+               i915_gem_object_wait_rendering(obj);
+
+               /* As we're writing through the gtt, flush
+                * any CPU writes before we write the relocations
+                */
+               if (obj->write_domain & I915_GEM_DOMAIN_CPU) {
+                       i915_gem_clflush_object(obj);
+                       drm_agp_chipset_flush(dev);
+                       obj->write_domain = 0;
+               }
+
+               /* Map the page containing the relocation we're going to
+                * perform.
+                */
+               reloc_offset = obj_priv->gtt_offset + reloc.offset;
+               if (reloc_page == NULL ||
+                   (last_reloc_offset & ~(PAGE_SIZE - 1)) !=
+                   (reloc_offset & ~(PAGE_SIZE - 1))) {
+                       if (reloc_page != NULL)
+                               iounmap(reloc_page);
+
+                       reloc_page = ioremap_wc(dev->agp->base +
+                                               (reloc_offset &
+                                                ~(PAGE_SIZE - 1)),
+                                               PAGE_SIZE);
+                       last_reloc_offset = reloc_offset;
+                       if (reloc_page == NULL) {
+                               drm_gem_object_unreference(target_obj);
+                               i915_gem_object_unpin(obj);
+                               return -ENOMEM;
+                       }
+               }
+
+               reloc_entry = (uint32_t __iomem *)(reloc_page +
+                                          (reloc_offset & (PAGE_SIZE - 1)));
+               reloc_val = target_obj_priv->gtt_offset + reloc.delta;
+
+#if WATCH_BUF
+               DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n",
+                         obj, (unsigned int) reloc.offset,
+                         readl(reloc_entry), reloc_val);
+#endif
+               writel(reloc_val, reloc_entry);
+
+               /* Write the updated presumed offset for this entry back out
+                * to the user.
+                */
+               reloc.presumed_offset = target_obj_priv->gtt_offset;
+               ret = copy_to_user(relocs + i, &reloc, sizeof(reloc));
+               if (ret != 0) {
+                       drm_gem_object_unreference(target_obj);
+                       i915_gem_object_unpin(obj);
+                       return ret;
+               }
+
+               drm_gem_object_unreference(target_obj);
+       }
+
+       if (reloc_page != NULL)
+               iounmap(reloc_page);
+
+#if WATCH_BUF
+       if (0)
+               i915_gem_dump_object(obj, 128, __func__, ~0);
+#endif
+       return 0;
+}
+
+/** Dispatch a batchbuffer to the ring
+ */
+static int
+i915_dispatch_gem_execbuffer(struct drm_device *dev,
+                             struct drm_i915_gem_execbuffer *exec,
+                             uint64_t exec_offset)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_clip_rect __user *boxes = (struct drm_clip_rect __user *)
+                                            (uintptr_t) exec->cliprects_ptr;
+       int nbox = exec->num_cliprects;
+       int i = 0, count;
+       uint32_t        exec_start, exec_len;
+       RING_LOCALS;
+
+       exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+       exec_len = (uint32_t) exec->batch_len;
+
+       if ((exec_start | exec_len) & 0x7) {
+               DRM_ERROR("alignment\n");
+               return -EINVAL;
+       }
+
+       if (!exec_start)
+               return -EINVAL;
+
+       count = nbox ? nbox : 1;
+
+       for (i = 0; i < count; i++) {
+               if (i < nbox) {
+                       int ret = i915_emit_box(dev, boxes, i,
+                                               exec->DR1, exec->DR4);
+                       if (ret)
+                               return ret;
+               }
+
+               if (IS_I830(dev) || IS_845G(dev)) {
+                       BEGIN_LP_RING(4);
+                       OUT_RING(MI_BATCH_BUFFER);
+                       OUT_RING(exec_start | MI_BATCH_NON_SECURE);
+                       OUT_RING(exec_start + exec_len - 4);
+                       OUT_RING(0);
+                       ADVANCE_LP_RING();
+               } else {
+                       BEGIN_LP_RING(2);
+                       if (IS_I965G(dev)) {
+                               OUT_RING(MI_BATCH_BUFFER_START |
+                                        (2 << 6) |
+                                        MI_BATCH_NON_SECURE_I965);
+                               OUT_RING(exec_start);
+                       } else {
+                               OUT_RING(MI_BATCH_BUFFER_START |
+                                        (2 << 6));
+                               OUT_RING(exec_start | MI_BATCH_NON_SECURE);
+                       }
+                       ADVANCE_LP_RING();
+               }
+       }
+
+       /* XXX breadcrumb */
+       return 0;
+}
+
+/* Throttle our rendering by waiting until the ring has completed our requests
+ * emitted over 20 msec ago.
+ *
+ * This should get us reasonable parallelism between CPU and GPU but also
+ * relatively low latency when blocking on a particular request to finish.
+ */
+static int
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
+{
+       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+       int ret = 0;
+       uint32_t seqno;
+
+       mutex_lock(&dev->struct_mutex);
+       seqno = i915_file_priv->mm.last_gem_throttle_seqno;
+       i915_file_priv->mm.last_gem_throttle_seqno =
+               i915_file_priv->mm.last_gem_seqno;
+       if (seqno)
+               ret = i915_wait_request(dev, seqno);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+int
+i915_gem_execbuffer(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+       struct drm_i915_gem_execbuffer *args = data;
+       struct drm_i915_gem_exec_object *exec_list = NULL;
+       struct drm_gem_object **object_list = NULL;
+       struct drm_gem_object *batch_obj;
+       int ret, i, pinned = 0;
+       uint64_t exec_offset;
+       uint32_t seqno, flush_domains;
+
+#if WATCH_EXEC
+       DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
+                 (int) args->buffers_ptr, args->buffer_count, args->batch_len);
+#endif
+
+       if (args->buffer_count < 1) {
+               DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+               return -EINVAL;
+       }
+       /* Copy in the exec list from userland */
+       exec_list = drm_calloc(sizeof(*exec_list), args->buffer_count,
+                              DRM_MEM_DRIVER);
+       object_list = drm_calloc(sizeof(*object_list), args->buffer_count,
+                                DRM_MEM_DRIVER);
+       if (exec_list == NULL || object_list == NULL) {
+               DRM_ERROR("Failed to allocate exec or object list "
+                         "for %d buffers\n",
+                         args->buffer_count);
+               ret = -ENOMEM;
+               goto pre_mutex_err;
+       }
+       ret = copy_from_user(exec_list,
+                            (struct drm_i915_relocation_entry __user *)
+                            (uintptr_t) args->buffers_ptr,
+                            sizeof(*exec_list) * args->buffer_count);
+       if (ret != 0) {
+               DRM_ERROR("copy %d exec entries failed %d\n",
+                         args->buffer_count, ret);
+               goto pre_mutex_err;
+       }
+
+       mutex_lock(&dev->struct_mutex);
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+
+       if (dev_priv->mm.wedged) {
+               DRM_ERROR("Execbuf while wedged\n");
+               mutex_unlock(&dev->struct_mutex);
+               return -EIO;
+       }
+
+       if (dev_priv->mm.suspended) {
+               DRM_ERROR("Execbuf while VT-switched.\n");
+               mutex_unlock(&dev->struct_mutex);
+               return -EBUSY;
+       }
+
+       /* Zero the gloabl flush/invalidate flags. These
+        * will be modified as each object is bound to the
+        * gtt
+        */
+       dev->invalidate_domains = 0;
+       dev->flush_domains = 0;
+
+       /* Look up object handles and perform the relocations */
+       for (i = 0; i < args->buffer_count; i++) {
+               object_list[i] = drm_gem_object_lookup(dev, file_priv,
+                                                      exec_list[i].handle);
+               if (object_list[i] == NULL) {
+                       DRM_ERROR("Invalid object handle %d at index %d\n",
+                                  exec_list[i].handle, i);
+                       ret = -EBADF;
+                       goto err;
+               }
+
+               object_list[i]->pending_read_domains = 0;
+               object_list[i]->pending_write_domain = 0;
+               ret = i915_gem_object_pin_and_relocate(object_list[i],
+                                                      file_priv,
+                                                      &exec_list[i]);
+               if (ret) {
+                       DRM_ERROR("object bind and relocate failed %d\n", ret);
+                       goto err;
+               }
+               pinned = i + 1;
+       }
+
+       /* Set the pending read domains for the batch buffer to COMMAND */
+       batch_obj = object_list[args->buffer_count-1];
+       batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND;
+       batch_obj->pending_write_domain = 0;
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+
+       for (i = 0; i < args->buffer_count; i++) {
+               struct drm_gem_object *obj = object_list[i];
+               struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+               if (obj_priv->gtt_space == NULL) {
+                       /* We evicted the buffer in the process of validating
+                        * our set of buffers in.  We could try to recover by
+                        * kicking them everything out and trying again from
+                        * the start.
+                        */
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               /* make sure all previous memory operations have passed */
+               ret = i915_gem_object_set_domain(obj,
+                                                obj->pending_read_domains,
+                                                obj->pending_write_domain);
+               if (ret)
+                       goto err;
+       }
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+
+       /* Flush/invalidate caches and chipset buffer */
+       flush_domains = i915_gem_dev_set_domain(dev);
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+
+#if WATCH_COHERENCY
+       for (i = 0; i < args->buffer_count; i++) {
+               i915_gem_object_check_coherency(object_list[i],
+                                               exec_list[i].handle);
+       }
+#endif
+
+       exec_offset = exec_list[args->buffer_count - 1].offset;
+
+#if WATCH_EXEC
+       i915_gem_dump_object(object_list[args->buffer_count - 1],
+                             args->batch_len,
+                             __func__,
+                             ~0);
+#endif
+
+       (void)i915_add_request(dev, flush_domains);
+
+       /* Exec the batchbuffer */
+       ret = i915_dispatch_gem_execbuffer(dev, args, exec_offset);
+       if (ret) {
+               DRM_ERROR("dispatch failed %d\n", ret);
+               goto err;
+       }
+
+       /*
+        * Ensure that the commands in the batch buffer are
+        * finished before the interrupt fires
+        */
+       flush_domains = i915_retire_commands(dev);
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+
+       /*
+        * Get a seqno representing the execution of the current buffer,
+        * which we can wait on.  We would like to mitigate these interrupts,
+        * likely by only creating seqnos occasionally (so that we have
+        * *some* interrupts representing completion of buffers that we can
+        * wait on when trying to clear up gtt space).
+        */
+       seqno = i915_add_request(dev, flush_domains);
+       BUG_ON(seqno == 0);
+       i915_file_priv->mm.last_gem_seqno = seqno;
+       for (i = 0; i < args->buffer_count; i++) {
+               struct drm_gem_object *obj = object_list[i];
+               struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+               i915_gem_object_move_to_active(obj);
+               obj_priv->last_rendering_seqno = seqno;
+#if WATCH_LRU
+               DRM_INFO("%s: move to exec list %p\n", __func__, obj);
+#endif
+       }
+#if WATCH_LRU
+       i915_dump_lru(dev, __func__);
+#endif
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+
+       /* Copy the new buffer offsets back to the user's exec list. */
+       ret = copy_to_user((struct drm_i915_relocation_entry __user *)
+                          (uintptr_t) args->buffers_ptr,
+                          exec_list,
+                          sizeof(*exec_list) * args->buffer_count);
+       if (ret)
+               DRM_ERROR("failed to copy %d exec entries "
+                         "back to user (%d)\n",
+                          args->buffer_count, ret);
+err:
+       if (object_list != NULL) {
+               for (i = 0; i < pinned; i++)
+                       i915_gem_object_unpin(object_list[i]);
+
+               for (i = 0; i < args->buffer_count; i++)
+                       drm_gem_object_unreference(object_list[i]);
+       }
+       mutex_unlock(&dev->struct_mutex);
+
+pre_mutex_err:
+       drm_free(object_list, sizeof(*object_list) * args->buffer_count,
+                DRM_MEM_DRIVER);
+       drm_free(exec_list, sizeof(*exec_list) * args->buffer_count,
+                DRM_MEM_DRIVER);
+
+       return ret;
+}
+
+int
+i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int ret;
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+       if (obj_priv->gtt_space == NULL) {
+               ret = i915_gem_object_bind_to_gtt(obj, alignment);
+               if (ret != 0) {
+                       DRM_ERROR("Failure to bind: %d", ret);
+                       return ret;
+               }
+       }
+       obj_priv->pin_count++;
+
+       /* If the object is not active and not pending a flush,
+        * remove it from the inactive list
+        */
+       if (obj_priv->pin_count == 1) {
+               atomic_inc(&dev->pin_count);
+               atomic_add(obj->size, &dev->pin_memory);
+               if (!obj_priv->active &&
+                   (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
+                                          I915_GEM_DOMAIN_GTT)) == 0 &&
+                   !list_empty(&obj_priv->list))
+                       list_del_init(&obj_priv->list);
+       }
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+
+       return 0;
+}
+
+void
+i915_gem_object_unpin(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+       obj_priv->pin_count--;
+       BUG_ON(obj_priv->pin_count < 0);
+       BUG_ON(obj_priv->gtt_space == NULL);
+
+       /* If the object is no longer pinned, and is
+        * neither active nor being flushed, then stick it on
+        * the inactive list
+        */
+       if (obj_priv->pin_count == 0) {
+               if (!obj_priv->active &&
+                   (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
+                                          I915_GEM_DOMAIN_GTT)) == 0)
+                       list_move_tail(&obj_priv->list,
+                                      &dev_priv->mm.inactive_list);
+               atomic_dec(&dev->pin_count);
+               atomic_sub(obj->size, &dev->pin_memory);
+       }
+       i915_verify_inactive(dev, __FILE__, __LINE__);
+}
+
+int
+i915_gem_pin_ioctl(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv)
+{
+       struct drm_i915_gem_pin *args = data;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret;
+
+       mutex_lock(&dev->struct_mutex);
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL) {
+               DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
+                         args->handle);
+               mutex_unlock(&dev->struct_mutex);
+               return -EBADF;
+       }
+       obj_priv = obj->driver_private;
+
+       ret = i915_gem_object_pin(obj, args->alignment);
+       if (ret != 0) {
+               drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       /* XXX - flush the CPU caches for pinned objects
+        * as the X server doesn't manage domains yet
+        */
+       if (obj->write_domain & I915_GEM_DOMAIN_CPU) {
+               i915_gem_clflush_object(obj);
+               drm_agp_chipset_flush(dev);
+               obj->write_domain = 0;
+       }
+       args->offset = obj_priv->gtt_offset;
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+int
+i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       struct drm_i915_gem_pin *args = data;
+       struct drm_gem_object *obj;
+
+       mutex_lock(&dev->struct_mutex);
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL) {
+               DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
+                         args->handle);
+               mutex_unlock(&dev->struct_mutex);
+               return -EBADF;
+       }
+
+       i915_gem_object_unpin(obj);
+
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+       return 0;
+}
+
+int
+i915_gem_busy_ioctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       struct drm_i915_gem_busy *args = data;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL) {
+               DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
+                         args->handle);
+               mutex_unlock(&dev->struct_mutex);
+               return -EBADF;
+       }
+
+       obj_priv = obj->driver_private;
+       args->busy = obj_priv->active;
+
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+       return 0;
+}
+
+int
+i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+    return i915_gem_ring_throttle(dev, file_priv);
+}
+
+int i915_gem_init_object(struct drm_gem_object *obj)
+{
+       struct drm_i915_gem_object *obj_priv;
+
+       obj_priv = drm_calloc(1, sizeof(*obj_priv), DRM_MEM_DRIVER);
+       if (obj_priv == NULL)
+               return -ENOMEM;
+
+       /*
+        * We've just allocated pages from the kernel,
+        * so they've just been written by the CPU with
+        * zeros. They'll need to be clflushed before we
+        * use them with the GPU.
+        */
+       obj->write_domain = I915_GEM_DOMAIN_CPU;
+       obj->read_domains = I915_GEM_DOMAIN_CPU;
+
+       obj_priv->agp_type = AGP_USER_MEMORY;
+
+       obj->driver_private = obj_priv;
+       obj_priv->obj = obj;
+       INIT_LIST_HEAD(&obj_priv->list);
+       return 0;
+}
+
+void i915_gem_free_object(struct drm_gem_object *obj)
+{
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+       while (obj_priv->pin_count > 0)
+               i915_gem_object_unpin(obj);
+
+       i915_gem_object_unbind(obj);
+
+       drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
+       drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
+}
+
+static int
+i915_gem_set_domain(struct drm_gem_object *obj,
+                   struct drm_file *file_priv,
+                   uint32_t read_domains,
+                   uint32_t write_domain)
+{
+       struct drm_device *dev = obj->dev;
+       int ret;
+       uint32_t flush_domains;
+
+       BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+
+       ret = i915_gem_object_set_domain(obj, read_domains, write_domain);
+       if (ret)
+               return ret;
+       flush_domains = i915_gem_dev_set_domain(obj->dev);
+
+       if (flush_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT))
+               (void) i915_add_request(dev, flush_domains);
+
+       return 0;
+}
+
+/** Unbinds all objects that are on the given buffer list. */
+static int
+i915_gem_evict_from_list(struct drm_device *dev, struct list_head *head)
+{
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret;
+
+       while (!list_empty(head)) {
+               obj_priv = list_first_entry(head,
+                                           struct drm_i915_gem_object,
+                                           list);
+               obj = obj_priv->obj;
+
+               if (obj_priv->pin_count != 0) {
+                       DRM_ERROR("Pinned object in unbind list\n");
+                       mutex_unlock(&dev->struct_mutex);
+                       return -EINVAL;
+               }
+
+               ret = i915_gem_object_unbind(obj);
+               if (ret != 0) {
+                       DRM_ERROR("Error unbinding object in LeaveVT: %d\n",
+                                 ret);
+                       mutex_unlock(&dev->struct_mutex);
+                       return ret;
+               }
+       }
+
+
+       return 0;
+}
+
+static int
+i915_gem_idle(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       uint32_t seqno, cur_seqno, last_seqno;
+       int stuck, ret;
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
+               mutex_unlock(&dev->struct_mutex);
+               return 0;
+       }
+
+       /* Hack!  Don't let anybody do execbuf while we don't control the chip.
+        * We need to replace this with a semaphore, or something.
+        */
+       dev_priv->mm.suspended = 1;
+
+       /* Cancel the retire work handler, wait for it to finish if running
+        */
+       mutex_unlock(&dev->struct_mutex);
+       cancel_delayed_work_sync(&dev_priv->mm.retire_work);
+       mutex_lock(&dev->struct_mutex);
+
+       i915_kernel_lost_context(dev);
+
+       /* Flush the GPU along with all non-CPU write domains
+        */
+       i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT),
+                      ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+       seqno = i915_add_request(dev, ~(I915_GEM_DOMAIN_CPU |
+                                       I915_GEM_DOMAIN_GTT));
+
+       if (seqno == 0) {
+               mutex_unlock(&dev->struct_mutex);
+               return -ENOMEM;
+       }
+
+       dev_priv->mm.waiting_gem_seqno = seqno;
+       last_seqno = 0;
+       stuck = 0;
+       for (;;) {
+               cur_seqno = i915_get_gem_seqno(dev);
+               if (i915_seqno_passed(cur_seqno, seqno))
+                       break;
+               if (last_seqno == cur_seqno) {
+                       if (stuck++ > 100) {
+                               DRM_ERROR("hardware wedged\n");
+                               dev_priv->mm.wedged = 1;
+                               DRM_WAKEUP(&dev_priv->irq_queue);
+                               break;
+                       }
+               }
+               msleep(10);
+               last_seqno = cur_seqno;
+       }
+       dev_priv->mm.waiting_gem_seqno = 0;
+
+       i915_gem_retire_requests(dev);
+
+       /* Active and flushing should now be empty as we've
+        * waited for a sequence higher than any pending execbuffer
+        */
+       BUG_ON(!list_empty(&dev_priv->mm.active_list));
+       BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+
+       /* Request should now be empty as we've also waited
+        * for the last request in the list
+        */
+       BUG_ON(!list_empty(&dev_priv->mm.request_list));
+
+       /* Move all buffers out of the GTT. */
+       ret = i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list);
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       BUG_ON(!list_empty(&dev_priv->mm.active_list));
+       BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+       BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
+       BUG_ON(!list_empty(&dev_priv->mm.request_list));
+
+       i915_gem_cleanup_ringbuffer(dev);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int
+i915_gem_init_hws(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret;
+
+       /* If we need a physical address for the status page, it's already
+        * initialized at driver load time.
+        */
+       if (!I915_NEED_GFX_HWS(dev))
+               return 0;
+
+       obj = drm_gem_object_alloc(dev, 4096);
+       if (obj == NULL) {
+               DRM_ERROR("Failed to allocate status page\n");
+               return -ENOMEM;
+       }
+       obj_priv = obj->driver_private;
+       obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
+
+       ret = i915_gem_object_pin(obj, 4096);
+       if (ret != 0) {
+               drm_gem_object_unreference(obj);
+               return ret;
+       }
+
+       dev_priv->status_gfx_addr = obj_priv->gtt_offset;
+
+       dev_priv->hw_status_page = kmap(obj_priv->page_list[0]);
+       if (dev_priv->hw_status_page == NULL) {
+               DRM_ERROR("Failed to map status page.\n");
+               memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+               drm_gem_object_unreference(obj);
+               return -EINVAL;
+       }
+       dev_priv->hws_obj = obj;
+       memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+       I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
+       I915_READ(HWS_PGA); /* posting read */
+       DRM_DEBUG("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
+
+       return 0;
+}
+
+static int
+i915_gem_init_ringbuffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret;
+       u32 head;
+
+       ret = i915_gem_init_hws(dev);
+       if (ret != 0)
+               return ret;
+
+       obj = drm_gem_object_alloc(dev, 128 * 1024);
+       if (obj == NULL) {
+               DRM_ERROR("Failed to allocate ringbuffer\n");
+               return -ENOMEM;
+       }
+       obj_priv = obj->driver_private;
+
+       ret = i915_gem_object_pin(obj, 4096);
+       if (ret != 0) {
+               drm_gem_object_unreference(obj);
+               return ret;
+       }
+
+       /* Set up the kernel mapping for the ring. */
+       dev_priv->ring.Size = obj->size;
+       dev_priv->ring.tail_mask = obj->size - 1;
+
+       dev_priv->ring.map.offset = dev->agp->base + obj_priv->gtt_offset;
+       dev_priv->ring.map.size = obj->size;
+       dev_priv->ring.map.type = 0;
+       dev_priv->ring.map.flags = 0;
+       dev_priv->ring.map.mtrr = 0;
+
+       drm_core_ioremap_wc(&dev_priv->ring.map, dev);
+       if (dev_priv->ring.map.handle == NULL) {
+               DRM_ERROR("Failed to map ringbuffer.\n");
+               memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
+               drm_gem_object_unreference(obj);
+               return -EINVAL;
+       }
+       dev_priv->ring.ring_obj = obj;
+       dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
+       /* Stop the ring if it's running. */
+       I915_WRITE(PRB0_CTL, 0);
+       I915_WRITE(PRB0_TAIL, 0);
+       I915_WRITE(PRB0_HEAD, 0);
+
+       /* Initialize the ring. */
+       I915_WRITE(PRB0_START, obj_priv->gtt_offset);
+       head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+
+       /* G45 ring initialization fails to reset head to zero */
+       if (head != 0) {
+               DRM_ERROR("Ring head not reset to zero "
+                         "ctl %08x head %08x tail %08x start %08x\n",
+                         I915_READ(PRB0_CTL),
+                         I915_READ(PRB0_HEAD),
+                         I915_READ(PRB0_TAIL),
+                         I915_READ(PRB0_START));
+               I915_WRITE(PRB0_HEAD, 0);
+
+               DRM_ERROR("Ring head forced to zero "
+                         "ctl %08x head %08x tail %08x start %08x\n",
+                         I915_READ(PRB0_CTL),
+                         I915_READ(PRB0_HEAD),
+                         I915_READ(PRB0_TAIL),
+                         I915_READ(PRB0_START));
+       }
+
+       I915_WRITE(PRB0_CTL,
+                  ((obj->size - 4096) & RING_NR_PAGES) |
+                  RING_NO_REPORT |
+                  RING_VALID);
+
+       head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+
+       /* If the head is still not zero, the ring is dead */
+       if (head != 0) {
+               DRM_ERROR("Ring initialization failed "
+                         "ctl %08x head %08x tail %08x start %08x\n",
+                         I915_READ(PRB0_CTL),
+                         I915_READ(PRB0_HEAD),
+                         I915_READ(PRB0_TAIL),
+                         I915_READ(PRB0_START));
+               return -EIO;
+       }
+
+       /* Update our cache of the ring state */
+       i915_kernel_lost_context(dev);
+
+       return 0;
+}
+
+static void
+i915_gem_cleanup_ringbuffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       if (dev_priv->ring.ring_obj == NULL)
+               return;
+
+       drm_core_ioremapfree(&dev_priv->ring.map, dev);
+
+       i915_gem_object_unpin(dev_priv->ring.ring_obj);
+       drm_gem_object_unreference(dev_priv->ring.ring_obj);
+       dev_priv->ring.ring_obj = NULL;
+       memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
+
+       if (dev_priv->hws_obj != NULL) {
+               struct drm_gem_object *obj = dev_priv->hws_obj;
+               struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+               kunmap(obj_priv->page_list[0]);
+               i915_gem_object_unpin(obj);
+               drm_gem_object_unreference(obj);
+               dev_priv->hws_obj = NULL;
+               memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+               dev_priv->hw_status_page = NULL;
+
+               /* Write high address into HWS_PGA when disabling. */
+               I915_WRITE(HWS_PGA, 0x1ffff000);
+       }
+}
+
+int
+i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       if (dev_priv->mm.wedged) {
+               DRM_ERROR("Reenabling wedged hardware, good luck\n");
+               dev_priv->mm.wedged = 0;
+       }
+
+       ret = i915_gem_init_ringbuffer(dev);
+       if (ret != 0)
+               return ret;
+
+       mutex_lock(&dev->struct_mutex);
+       BUG_ON(!list_empty(&dev_priv->mm.active_list));
+       BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+       BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
+       BUG_ON(!list_empty(&dev_priv->mm.request_list));
+       dev_priv->mm.suspended = 0;
+       mutex_unlock(&dev->struct_mutex);
+
+       drm_irq_install(dev);
+
+       return 0;
+}
+
+int
+i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
+{
+       int ret;
+
+       ret = i915_gem_idle(dev);
+       drm_irq_uninstall(dev);
+
+       return ret;
+}
+
+void
+i915_gem_lastclose(struct drm_device *dev)
+{
+       int ret;
+
+       ret = i915_gem_idle(dev);
+       if (ret)
+               DRM_ERROR("failed to idle hardware: %d\n", ret);
+}
+
+void
+i915_gem_load(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       INIT_LIST_HEAD(&dev_priv->mm.active_list);
+       INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
+       INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+       INIT_LIST_HEAD(&dev_priv->mm.request_list);
+       INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
+                         i915_gem_retire_work_handler);
+       INIT_WORK(&dev_priv->mm.vblank_work,
+                 i915_gem_vblank_work_handler);
+       dev_priv->mm.next_gem_seqno = 1;
+
+       i915_gem_detect_bit_6_swizzle(dev);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
new file mode 100644 (file)
index 0000000..131c088
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright Â© 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#if WATCH_INACTIVE
+void
+i915_verify_inactive(struct drm_device *dev, char *file, int line)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+
+       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+               obj = obj_priv->obj;
+               if (obj_priv->pin_count || obj_priv->active ||
+                   (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
+                                          I915_GEM_DOMAIN_GTT)))
+                       DRM_ERROR("inactive %p (p %d a %d w %x)  %s:%d\n",
+                                 obj,
+                                 obj_priv->pin_count, obj_priv->active,
+                                 obj->write_domain, file, line);
+       }
+}
+#endif /* WATCH_INACTIVE */
+
+
+#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
+static void
+i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
+                  uint32_t bias, uint32_t mark)
+{
+       uint32_t *mem = kmap_atomic(page, KM_USER0);
+       int i;
+       for (i = start; i < end; i += 4)
+               DRM_INFO("%08x: %08x%s\n",
+                         (int) (bias + i), mem[i / 4],
+                         (bias + i == mark) ? " ********" : "");
+       kunmap_atomic(mem, KM_USER0);
+       /* give syslog time to catch up */
+       msleep(1);
+}
+
+void
+i915_gem_dump_object(struct drm_gem_object *obj, int len,
+                    const char *where, uint32_t mark)
+{
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int page;
+
+       DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset);
+       for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) {
+               int page_len, chunk, chunk_len;
+
+               page_len = len - page * PAGE_SIZE;
+               if (page_len > PAGE_SIZE)
+                       page_len = PAGE_SIZE;
+
+               for (chunk = 0; chunk < page_len; chunk += 128) {
+                       chunk_len = page_len - chunk;
+                       if (chunk_len > 128)
+                               chunk_len = 128;
+                       i915_gem_dump_page(obj_priv->page_list[page],
+                                          chunk, chunk + chunk_len,
+                                          obj_priv->gtt_offset +
+                                          page * PAGE_SIZE,
+                                          mark);
+               }
+       }
+}
+#endif
+
+#if WATCH_LRU
+void
+i915_dump_lru(struct drm_device *dev, const char *where)
+{
+       drm_i915_private_t              *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object      *obj_priv;
+
+       DRM_INFO("active list %s {\n", where);
+       list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
+                           list)
+       {
+               DRM_INFO("    %p: %08x\n", obj_priv,
+                        obj_priv->last_rendering_seqno);
+       }
+       DRM_INFO("}\n");
+       DRM_INFO("flushing list %s {\n", where);
+       list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
+                           list)
+       {
+               DRM_INFO("    %p: %08x\n", obj_priv,
+                        obj_priv->last_rendering_seqno);
+       }
+       DRM_INFO("}\n");
+       DRM_INFO("inactive %s {\n", where);
+       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+               DRM_INFO("    %p: %08x\n", obj_priv,
+                        obj_priv->last_rendering_seqno);
+       }
+       DRM_INFO("}\n");
+}
+#endif
+
+
+#if WATCH_COHERENCY
+void
+i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int page;
+       uint32_t *gtt_mapping;
+       uint32_t *backing_map = NULL;
+       int bad_count = 0;
+
+       DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n",
+                __func__, obj, obj_priv->gtt_offset, handle,
+                obj->size / 1024);
+
+       gtt_mapping = ioremap(dev->agp->base + obj_priv->gtt_offset,
+                             obj->size);
+       if (gtt_mapping == NULL) {
+               DRM_ERROR("failed to map GTT space\n");
+               return;
+       }
+
+       for (page = 0; page < obj->size / PAGE_SIZE; page++) {
+               int i;
+
+               backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0);
+
+               if (backing_map == NULL) {
+                       DRM_ERROR("failed to map backing page\n");
+                       goto out;
+               }
+
+               for (i = 0; i < PAGE_SIZE / 4; i++) {
+                       uint32_t cpuval = backing_map[i];
+                       uint32_t gttval = readl(gtt_mapping +
+                                               page * 1024 + i);
+
+                       if (cpuval != gttval) {
+                               DRM_INFO("incoherent CPU vs GPU at 0x%08x: "
+                                        "0x%08x vs 0x%08x\n",
+                                        (int)(obj_priv->gtt_offset +
+                                              page * PAGE_SIZE + i * 4),
+                                        cpuval, gttval);
+                               if (bad_count++ >= 8) {
+                                       DRM_INFO("...\n");
+                                       goto out;
+                               }
+                       }
+               }
+               kunmap_atomic(backing_map, KM_USER0);
+               backing_map = NULL;
+       }
+
+ out:
+       if (backing_map != NULL)
+               kunmap_atomic(backing_map, KM_USER0);
+       iounmap(gtt_mapping);
+
+       /* give syslog time to catch up */
+       msleep(1);
+
+       /* Directly flush the object, since we just loaded values with the CPU
+        * from the backing pages and we don't want to disturb the cache
+        * management that we're trying to observe.
+        */
+
+       i915_gem_clflush_object(obj);
+}
+#endif
diff --git a/drivers/gpu/drm/i915/i915_gem_proc.c b/drivers/gpu/drm/i915/i915_gem_proc.c
new file mode 100644 (file)
index 0000000..15d4160
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright Â© 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+static int i915_gem_active_info(char *buf, char **start, off_t offset,
+                               int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv;
+       int len = 0;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("Active:\n");
+       list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
+                           list)
+       {
+               struct drm_gem_object *obj = obj_priv->obj;
+               if (obj->name) {
+                       DRM_PROC_PRINT("    %p(%d): %08x %08x %d\n",
+                                      obj, obj->name,
+                                      obj->read_domains, obj->write_domain,
+                                      obj_priv->last_rendering_seqno);
+               } else {
+                       DRM_PROC_PRINT("       %p: %08x %08x %d\n",
+                                      obj,
+                                      obj->read_domains, obj->write_domain,
+                                      obj_priv->last_rendering_seqno);
+               }
+       }
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+static int i915_gem_flushing_info(char *buf, char **start, off_t offset,
+                                 int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv;
+       int len = 0;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("Flushing:\n");
+       list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
+                           list)
+       {
+               struct drm_gem_object *obj = obj_priv->obj;
+               if (obj->name) {
+                       DRM_PROC_PRINT("    %p(%d): %08x %08x %d\n",
+                                      obj, obj->name,
+                                      obj->read_domains, obj->write_domain,
+                                      obj_priv->last_rendering_seqno);
+               } else {
+                       DRM_PROC_PRINT("       %p: %08x %08x %d\n", obj,
+                                      obj->read_domains, obj->write_domain,
+                                      obj_priv->last_rendering_seqno);
+               }
+       }
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+static int i915_gem_inactive_info(char *buf, char **start, off_t offset,
+                                 int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv;
+       int len = 0;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("Inactive:\n");
+       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list,
+                           list)
+       {
+               struct drm_gem_object *obj = obj_priv->obj;
+               if (obj->name) {
+                       DRM_PROC_PRINT("    %p(%d): %08x %08x %d\n",
+                                      obj, obj->name,
+                                      obj->read_domains, obj->write_domain,
+                                      obj_priv->last_rendering_seqno);
+               } else {
+                       DRM_PROC_PRINT("       %p: %08x %08x %d\n", obj,
+                                      obj->read_domains, obj->write_domain,
+                                      obj_priv->last_rendering_seqno);
+               }
+       }
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+static int i915_gem_request_info(char *buf, char **start, off_t offset,
+                                int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_request *gem_request;
+       int len = 0;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("Request:\n");
+       list_for_each_entry(gem_request, &dev_priv->mm.request_list,
+                           list)
+       {
+               DRM_PROC_PRINT("    %d @ %d %08x\n",
+                              gem_request->seqno,
+                              (int) (jiffies - gem_request->emitted_jiffies),
+                              gem_request->flush_domains);
+       }
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+static int i915_gem_seqno_info(char *buf, char **start, off_t offset,
+                              int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int len = 0;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("Current sequence: %d\n", i915_get_gem_seqno(dev));
+       DRM_PROC_PRINT("Waiter sequence:  %d\n",
+                      dev_priv->mm.waiting_gem_seqno);
+       DRM_PROC_PRINT("IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+
+static int i915_interrupt_info(char *buf, char **start, off_t offset,
+                              int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int len = 0;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       DRM_PROC_PRINT("Interrupt enable:    %08x\n",
+                      I915_READ(IER));
+       DRM_PROC_PRINT("Interrupt identity:  %08x\n",
+                      I915_READ(IIR));
+       DRM_PROC_PRINT("Interrupt mask:      %08x\n",
+                      I915_READ(IMR));
+       DRM_PROC_PRINT("Pipe A stat:         %08x\n",
+                      I915_READ(PIPEASTAT));
+       DRM_PROC_PRINT("Pipe B stat:         %08x\n",
+                      I915_READ(PIPEBSTAT));
+       DRM_PROC_PRINT("Interrupts received: %d\n",
+                      atomic_read(&dev_priv->irq_received));
+       DRM_PROC_PRINT("Current sequence:    %d\n",
+                      i915_get_gem_seqno(dev));
+       DRM_PROC_PRINT("Waiter sequence:     %d\n",
+                      dev_priv->mm.waiting_gem_seqno);
+       DRM_PROC_PRINT("IRQ sequence:        %d\n",
+                      dev_priv->mm.irq_gem_seqno);
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+static struct drm_proc_list {
+       /** file name */
+       const char *name;
+       /** proc callback*/
+       int (*f) (char *, char **, off_t, int, int *, void *);
+} i915_gem_proc_list[] = {
+       {"i915_gem_active", i915_gem_active_info},
+       {"i915_gem_flushing", i915_gem_flushing_info},
+       {"i915_gem_inactive", i915_gem_inactive_info},
+       {"i915_gem_request", i915_gem_request_info},
+       {"i915_gem_seqno", i915_gem_seqno_info},
+       {"i915_gem_interrupt", i915_interrupt_info},
+};
+
+#define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
+
+int i915_gem_proc_init(struct drm_minor *minor)
+{
+       struct proc_dir_entry *ent;
+       int i, j;
+
+       for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
+               ent = create_proc_entry(i915_gem_proc_list[i].name,
+                                       S_IFREG | S_IRUGO, minor->dev_root);
+               if (!ent) {
+                       DRM_ERROR("Cannot create /proc/dri/.../%s\n",
+                                 i915_gem_proc_list[i].name);
+                       for (j = 0; j < i; j++)
+                               remove_proc_entry(i915_gem_proc_list[i].name,
+                                                 minor->dev_root);
+                       return -1;
+               }
+               ent->read_proc = i915_gem_proc_list[i].f;
+               ent->data = minor;
+       }
+       return 0;
+}
+
+void i915_gem_proc_cleanup(struct drm_minor *minor)
+{
+       int i;
+
+       if (!minor->dev_root)
+               return;
+
+       for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
+               remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
new file mode 100644 (file)
index 0000000..e8b85ac
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright Â© 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/** @file i915_gem_tiling.c
+ *
+ * Support for managing tiling state of buffer objects.
+ *
+ * The idea behind tiling is to increase cache hit rates by rearranging
+ * pixel data so that a group of pixel accesses are in the same cacheline.
+ * Performance improvement from doing this on the back/depth buffer are on
+ * the order of 30%.
+ *
+ * Intel architectures make this somewhat more complicated, though, by
+ * adjustments made to addressing of data when the memory is in interleaved
+ * mode (matched pairs of DIMMS) to improve memory bandwidth.
+ * For interleaved memory, the CPU sends every sequential 64 bytes
+ * to an alternate memory channel so it can get the bandwidth from both.
+ *
+ * The GPU also rearranges its accesses for increased bandwidth to interleaved
+ * memory, and it matches what the CPU does for non-tiled.  However, when tiled
+ * it does it a little differently, since one walks addresses not just in the
+ * X direction but also Y.  So, along with alternating channels when bit
+ * 6 of the address flips, it also alternates when other bits flip --  Bits 9
+ * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
+ * are common to both the 915 and 965-class hardware.
+ *
+ * The CPU also sometimes XORs in higher bits as well, to improve
+ * bandwidth doing strided access like we do so frequently in graphics.  This
+ * is called "Channel XOR Randomization" in the MCH documentation.  The result
+ * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
+ * decode.
+ *
+ * All of this bit 6 XORing has an effect on our memory management,
+ * as we need to make sure that the 3d driver can correctly address object
+ * contents.
+ *
+ * If we don't have interleaved memory, all tiling is safe and no swizzling is
+ * required.
+ *
+ * When bit 17 is XORed in, we simply refuse to tile at all.  Bit
+ * 17 is not just a page offset, so as we page an objet out and back in,
+ * individual pages in it will have different bit 17 addresses, resulting in
+ * each 64 bytes being swapped with its neighbor!
+ *
+ * Otherwise, if interleaved, we have to tell the 3d driver what the address
+ * swizzling it needs to do is, since it's writing with the CPU to the pages
+ * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
+ * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
+ * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
+ * to match what the GPU expects.
+ */
+
+/**
+ * Detects bit 6 swizzling of address lookup between IGD access and CPU
+ * access through main memory.
+ */
+void
+i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+       uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+
+       if (!IS_I9XX(dev)) {
+               /* As far as we know, the 865 doesn't have these bit 6
+                * swizzling issues.
+                */
+               swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+               swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+       } else if ((!IS_I965G(dev) && !IS_G33(dev)) || IS_I965GM(dev) ||
+                  IS_GM45(dev)) {
+               uint32_t dcc;
+
+               /* On 915-945 and GM965, channel interleave by the CPU is
+                * determined by DCC.  The CPU will alternate based on bit 6
+                * in interleaved mode, and the GPU will then also alternate
+                * on bit 6, 9, and 10 for X, but the CPU may also optionally
+                * alternate based on bit 17 (XOR not disabled and XOR
+                * bit == 17).
+                */
+               dcc = I915_READ(DCC);
+               switch (dcc & DCC_ADDRESSING_MODE_MASK) {
+               case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
+               case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
+                       swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+                       swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+                       break;
+               case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
+                       if (IS_I915G(dev) || IS_I915GM(dev) ||
+                           dcc & DCC_CHANNEL_XOR_DISABLE) {
+                               swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+                               swizzle_y = I915_BIT_6_SWIZZLE_9;
+                       } else if (IS_I965GM(dev) || IS_GM45(dev)) {
+                               /* GM965 only does bit 11-based channel
+                                * randomization
+                                */
+                               swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
+                               swizzle_y = I915_BIT_6_SWIZZLE_9_11;
+                       } else {
+                               /* Bit 17 or perhaps other swizzling */
+                               swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+                               swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+                       }
+                       break;
+               }
+               if (dcc == 0xffffffff) {
+                       DRM_ERROR("Couldn't read from MCHBAR.  "
+                                 "Disabling tiling.\n");
+                       swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+                       swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+               }
+       } else {
+               /* The 965, G33, and newer, have a very flexible memory
+                * configuration.  It will enable dual-channel mode
+                * (interleaving) on as much memory as it can, and the GPU
+                * will additionally sometimes enable different bit 6
+                * swizzling for tiled objects from the CPU.
+                *
+                * Here's what I found on the G965:
+                *    slot fill         memory size  swizzling
+                * 0A   0B   1A   1B    1-ch   2-ch
+                * 512  0    0    0     512    0     O
+                * 512  0    512  0     16     1008  X
+                * 512  0    0    512   16     1008  X
+                * 0    512  0    512   16     1008  X
+                * 1024 1024 1024 0     2048   1024  O
+                *
+                * We could probably detect this based on either the DRB
+                * matching, which was the case for the swizzling required in
+                * the table above, or from the 1-ch value being less than
+                * the minimum size of a rank.
+                */
+               if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
+                       swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+                       swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+               } else {
+                       swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+                       swizzle_y = I915_BIT_6_SWIZZLE_9;
+               }
+       }
+
+       dev_priv->mm.bit_6_swizzle_x = swizzle_x;
+       dev_priv->mm.bit_6_swizzle_y = swizzle_y;
+}
+
+/**
+ * Sets the tiling mode of an object, returning the required swizzling of
+ * bit 6 of addresses in the object.
+ */
+int
+i915_gem_set_tiling(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv)
+{
+       struct drm_i915_gem_set_tiling *args = data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EINVAL;
+       obj_priv = obj->driver_private;
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (args->tiling_mode == I915_TILING_NONE) {
+               obj_priv->tiling_mode = I915_TILING_NONE;
+               args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+       } else {
+               if (args->tiling_mode == I915_TILING_X)
+                       args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
+               else
+                       args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
+               /* If we can't handle the swizzling, make it untiled. */
+               if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
+                       args->tiling_mode = I915_TILING_NONE;
+                       args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+               }
+       }
+       obj_priv->tiling_mode = args->tiling_mode;
+
+       mutex_unlock(&dev->struct_mutex);
+
+       drm_gem_object_unreference(obj);
+
+       return 0;
+}
+
+/**
+ * Returns the current tiling mode and required bit 6 swizzling for the object.
+ */
+int
+i915_gem_get_tiling(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv)
+{
+       struct drm_i915_gem_get_tiling *args = data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EINVAL;
+       obj_priv = obj->driver_private;
+
+       mutex_lock(&dev->struct_mutex);
+
+       args->tiling_mode = obj_priv->tiling_mode;
+       switch (obj_priv->tiling_mode) {
+       case I915_TILING_X:
+               args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
+               break;
+       case I915_TILING_Y:
+               args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
+               break;
+       case I915_TILING_NONE:
+               args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+               break;
+       default:
+               DRM_ERROR("unknown tiling mode\n");
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       drm_gem_object_unreference(obj);
+
+       return 0;
+}
index df036118b8b14ad1c3c1fd33ccf940e6a7fcf830..baae511c785b6297115b47a20a23e6568bb8cca3 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-
 #define MAX_NOPID ((u32)~0)
 
+/** These are the interrupts used by the driver */
+#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT |              \
+                                   I915_ASLE_INTERRUPT |               \
+                                   I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
+                                   I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+
+void
+i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+       if ((dev_priv->irq_mask_reg & mask) != 0) {
+               dev_priv->irq_mask_reg &= ~mask;
+               I915_WRITE(IMR, dev_priv->irq_mask_reg);
+               (void) I915_READ(IMR);
+       }
+}
+
+static inline void
+i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+       if ((dev_priv->irq_mask_reg & mask) != mask) {
+               dev_priv->irq_mask_reg |= mask;
+               I915_WRITE(IMR, dev_priv->irq_mask_reg);
+               (void) I915_READ(IMR);
+       }
+}
+
+/**
+ * i915_get_pipe - return the the pipe associated with a given plane
+ * @dev: DRM device
+ * @plane: plane to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a pipe number, since they may not always be equal.  This routine
+ * maps the given @plane back to a pipe number.
+ */
+static int
+i915_get_pipe(struct drm_device *dev, int plane)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 dspcntr;
+
+       dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
+
+       return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0;
+}
+
+/**
+ * i915_get_plane - return the the plane associated with a given pipe
+ * @dev: DRM device
+ * @pipe: pipe to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a plane number, since they may not always be equal.  This routine
+ * maps the given @pipe back to a plane number.
+ */
+static int
+i915_get_plane(struct drm_device *dev, int pipe)
+{
+       if (i915_get_pipe(dev, 0) == pipe)
+               return 0;
+       return 1;
+}
+
+/**
+ * i915_pipe_enabled - check if a pipe is enabled
+ * @dev: DRM device
+ * @pipe: pipe to check
+ *
+ * Reading certain registers when the pipe is disabled can hang the chip.
+ * Use this routine to make sure the PLL is running and the pipe is active
+ * before reading such registers if unsure.
+ */
+static int
+i915_pipe_enabled(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
+
+       if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
+               return 1;
+
+       return 0;
+}
+
 /**
  * Emit blits for scheduled buffer swaps.
  *
@@ -48,8 +128,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
        unsigned long irqflags;
        struct list_head *list, *tmp, hits, *hit;
        int nhits, nrects, slice[2], upper[2], lower[2], i;
-       unsigned counter[2] = { atomic_read(&dev->vbl_received),
-                               atomic_read(&dev->vbl_received2) };
+       unsigned counter[2];
        struct drm_drawable_info *drw;
        drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
        u32 cpp = dev_priv->cpp;
@@ -71,6 +150,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
                src_pitch >>= 2;
        }
 
+       counter[0] = drm_vblank_count(dev, 0);
+       counter[1] = drm_vblank_count(dev, 1);
+
        DRM_DEBUG("\n");
 
        INIT_LIST_HEAD(&hits);
@@ -83,12 +165,14 @@ static void i915_vblank_tasklet(struct drm_device *dev)
        list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
                drm_i915_vbl_swap_t *vbl_swap =
                        list_entry(list, drm_i915_vbl_swap_t, head);
+               int pipe = i915_get_pipe(dev, vbl_swap->plane);
 
-               if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
+               if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
                        continue;
 
                list_del(list);
                dev_priv->swaps_pending--;
+               drm_vblank_put(dev, pipe);
 
                spin_unlock(&dev_priv->swaps_lock);
                spin_lock(&dev->drw_lock);
@@ -181,7 +265,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
                        drm_i915_vbl_swap_t *swap_hit =
                                list_entry(hit, drm_i915_vbl_swap_t, head);
                        struct drm_clip_rect *rect;
-                       int num_rects, pipe;
+                       int num_rects, plane;
                        unsigned short top, bottom;
 
                        drw = drm_get_drawable_info(dev, swap_hit->drw_id);
@@ -190,9 +274,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
                                continue;
 
                        rect = drw->rects;
-                       pipe = swap_hit->pipe;
-                       top = upper[pipe];
-                       bottom = lower[pipe];
+                       plane = swap_hit->plane;
+                       top = upper[plane];
+                       bottom = lower[plane];
 
                        for (num_rects = drw->num_rects; num_rects--; rect++) {
                                int y1 = max(rect->y1, top);
@@ -229,61 +313,139 @@ static void i915_vblank_tasklet(struct drm_device *dev)
        }
 }
 
+u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long high_frame;
+       unsigned long low_frame;
+       u32 high1, high2, low, count;
+       int pipe;
+
+       pipe = i915_get_pipe(dev, plane);
+       high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+       low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
+       if (!i915_pipe_enabled(dev, pipe)) {
+               DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
+               return 0;
+       }
+
+       /*
+        * High & low register fields aren't synchronized, so make sure
+        * we get a low value that's stable across two reads of the high
+        * register.
+        */
+       do {
+               high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+                        PIPE_FRAME_HIGH_SHIFT);
+               low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+                       PIPE_FRAME_LOW_SHIFT);
+               high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+                        PIPE_FRAME_HIGH_SHIFT);
+       } while (high1 != high2);
+
+       count = (high1 << 8) | low;
+
+       return count;
+}
+
+void
+i915_gem_vblank_work_handler(struct work_struct *work)
+{
+       drm_i915_private_t *dev_priv;
+       struct drm_device *dev;
+
+       dev_priv = container_of(work, drm_i915_private_t,
+                               mm.vblank_work);
+       dev = dev_priv->dev;
+
+       mutex_lock(&dev->struct_mutex);
+       i915_vblank_tasklet(dev);
+       mutex_unlock(&dev->struct_mutex);
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u16 temp;
+       u32 iir;
        u32 pipea_stats, pipeb_stats;
+       int vblank = 0;
 
-       pipea_stats = I915_READ(I915REG_PIPEASTAT);
-       pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
+       atomic_inc(&dev_priv->irq_received);
 
-       temp = I915_READ16(I915REG_INT_IDENTITY_R);
+       if (dev->pdev->msi_enabled)
+               I915_WRITE(IMR, ~0);
+       iir = I915_READ(IIR);
 
-       temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
+       if (iir == 0) {
+               if (dev->pdev->msi_enabled) {
+                       I915_WRITE(IMR, dev_priv->irq_mask_reg);
+                       (void) I915_READ(IMR);
+               }
+               return IRQ_NONE;
+       }
 
-       DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+       /*
+        * Clear the PIPE(A|B)STAT regs before the IIR otherwise
+        * we may get extra interrupts.
+        */
+       if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+               pipea_stats = I915_READ(PIPEASTAT);
+               if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A))
+                       pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+                                        PIPE_VBLANK_INTERRUPT_ENABLE);
+               else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+                                       PIPE_VBLANK_INTERRUPT_STATUS)) {
+                       vblank++;
+                       drm_handle_vblank(dev, i915_get_plane(dev, 0));
+               }
 
-       if (temp == 0)
-               return IRQ_NONE;
+               I915_WRITE(PIPEASTAT, pipea_stats);
+       }
+       if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
+               pipeb_stats = I915_READ(PIPEBSTAT);
+               /* Ack the event */
+               I915_WRITE(PIPEBSTAT, pipeb_stats);
+
+               /* The vblank interrupt gets enabled even if we didn't ask for
+                  it, so make sure it's shut down again */
+               if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B))
+                       pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+                                        PIPE_VBLANK_INTERRUPT_ENABLE);
+               else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
+                                       PIPE_VBLANK_INTERRUPT_STATUS)) {
+                       vblank++;
+                       drm_handle_vblank(dev, i915_get_plane(dev, 1));
+               }
 
-       I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
-       (void) I915_READ16(I915REG_INT_IDENTITY_R);
-       DRM_READMEMORYBARRIER();
+               if (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS)
+                       opregion_asle_intr(dev);
+               I915_WRITE(PIPEBSTAT, pipeb_stats);
+       }
+
+       I915_WRITE(IIR, iir);
+       if (dev->pdev->msi_enabled)
+               I915_WRITE(IMR, dev_priv->irq_mask_reg);
+       (void) I915_READ(IIR); /* Flush posted writes */
 
-       dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+       if (dev_priv->sarea_priv)
+               dev_priv->sarea_priv->last_dispatch =
+                       READ_BREADCRUMB(dev_priv);
 
-       if (temp & USER_INT_FLAG)
+       if (iir & I915_USER_INTERRUPT) {
+               dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
                DRM_WAKEUP(&dev_priv->irq_queue);
+       }
 
-       if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
-               int vblank_pipe = dev_priv->vblank_pipe;
-
-               if ((vblank_pipe &
-                    (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
-                   == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
-                       if (temp & VSYNC_PIPEA_FLAG)
-                               atomic_inc(&dev->vbl_received);
-                       if (temp & VSYNC_PIPEB_FLAG)
-                               atomic_inc(&dev->vbl_received2);
-               } else if (((temp & VSYNC_PIPEA_FLAG) &&
-                           (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
-                          ((temp & VSYNC_PIPEB_FLAG) &&
-                           (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
-                       atomic_inc(&dev->vbl_received);
-
-               DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals(dev);
-
-               if (dev_priv->swaps_pending > 0)
+       if (iir & I915_ASLE_INTERRUPT)
+               opregion_asle_intr(dev);
+
+       if (vblank && dev_priv->swaps_pending > 0) {
+               if (dev_priv->ring.ring_obj == NULL)
                        drm_locked_tasklet(dev, i915_vblank_tasklet);
-               I915_WRITE(I915REG_PIPEASTAT,
-                       pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
-                       I915_VBLANK_CLEAR);
-               I915_WRITE(I915REG_PIPEBSTAT,
-                       pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
-                       I915_VBLANK_CLEAR);
+               else
+                       schedule_work(&dev_priv->mm.vblank_work);
        }
 
        return IRQ_HANDLED;
@@ -298,23 +460,45 @@ static int i915_emit_irq(struct drm_device * dev)
 
        DRM_DEBUG("\n");
 
-       dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
-
+       dev_priv->counter++;
        if (dev_priv->counter > 0x7FFFFFFFUL)
-               dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+               dev_priv->counter = 1;
+       if (dev_priv->sarea_priv)
+               dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
        BEGIN_LP_RING(6);
-       OUT_RING(CMD_STORE_DWORD_IDX);
-       OUT_RING(20);
+       OUT_RING(MI_STORE_DWORD_INDEX);
+       OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
        OUT_RING(dev_priv->counter);
        OUT_RING(0);
        OUT_RING(0);
-       OUT_RING(GFX_OP_USER_INTERRUPT);
+       OUT_RING(MI_USER_INTERRUPT);
        ADVANCE_LP_RING();
 
        return dev_priv->counter;
 }
 
+void i915_user_irq_get(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       spin_lock(&dev_priv->user_irq_lock);
+       if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
+               i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+       spin_unlock(&dev_priv->user_irq_lock);
+}
+
+void i915_user_irq_put(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       spin_lock(&dev_priv->user_irq_lock);
+       BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
+       if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
+               i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+       spin_unlock(&dev_priv->user_irq_lock);
+}
+
 static int i915_wait_irq(struct drm_device * dev, int irq_nr)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -323,55 +507,34 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
        DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
                  READ_BREADCRUMB(dev_priv));
 
-       if (READ_BREADCRUMB(dev_priv) >= irq_nr)
+       if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
+               if (dev_priv->sarea_priv) {
+                       dev_priv->sarea_priv->last_dispatch =
+                               READ_BREADCRUMB(dev_priv);
+               }
                return 0;
+       }
 
-       dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+       if (dev_priv->sarea_priv)
+               dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
+       i915_user_irq_get(dev);
        DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
                    READ_BREADCRUMB(dev_priv) >= irq_nr);
+       i915_user_irq_put(dev);
 
        if (ret == -EBUSY) {
                DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
                          READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
        }
 
-       dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
-       return ret;
-}
-
-static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
-                                     atomic_t *counter)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       unsigned int cur_vblank;
-       int ret = 0;
-
-       if (!dev_priv) {
-               DRM_ERROR("called with no initialization\n");
-               return -EINVAL;
-       }
-
-       DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(counter))
-                       - *sequence) <= (1<<23)));
-
-       *sequence = cur_vblank;
+       if (dev_priv->sarea_priv)
+               dev_priv->sarea_priv->last_dispatch =
+                       READ_BREADCRUMB(dev_priv);
 
        return ret;
 }
 
-
-int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
-{
-       return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
-}
-
-int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
-{
-       return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
-}
-
 /* Needs the lock as it touches the ring.
  */
 int i915_irq_emit(struct drm_device *dev, void *data,
@@ -381,14 +544,15 @@ int i915_irq_emit(struct drm_device *dev, void *data,
        drm_i915_irq_emit_t *emit = data;
        int result;
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
-
+       mutex_lock(&dev->struct_mutex);
        result = i915_emit_irq(dev);
+       mutex_unlock(&dev->struct_mutex);
 
        if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
@@ -414,18 +578,74 @@ int i915_irq_wait(struct drm_device *dev, void *data,
        return i915_wait_irq(dev, irqwait->irq_seq);
 }
 
-static void i915_enable_interrupt (struct drm_device *dev)
+int i915_enable_vblank(struct drm_device *dev, int plane)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u16 flag;
+       int pipe = i915_get_pipe(dev, plane);
+       u32     pipestat_reg = 0;
+       u32     pipestat;
+
+       switch (pipe) {
+       case 0:
+               pipestat_reg = PIPEASTAT;
+               i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT);
+               break;
+       case 1:
+               pipestat_reg = PIPEBSTAT;
+               i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
+               break;
+       default:
+               DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
+                         pipe);
+               break;
+       }
+
+       if (pipestat_reg) {
+               pipestat = I915_READ(pipestat_reg);
+               if (IS_I965G(dev))
+                       pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
+               else
+                       pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
+               /* Clear any stale interrupt status */
+               pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+                            PIPE_VBLANK_INTERRUPT_STATUS);
+               I915_WRITE(pipestat_reg, pipestat);
+       }
+
+       return 0;
+}
 
-       flag = 0;
-       if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
-               flag |= VSYNC_PIPEA_FLAG;
-       if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
-               flag |= VSYNC_PIPEB_FLAG;
+void i915_disable_vblank(struct drm_device *dev, int plane)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int pipe = i915_get_pipe(dev, plane);
+       u32     pipestat_reg = 0;
+       u32     pipestat;
+
+       switch (pipe) {
+       case 0:
+               pipestat_reg = PIPEASTAT;
+               i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT);
+               break;
+       case 1:
+               pipestat_reg = PIPEBSTAT;
+               i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
+               break;
+       default:
+               DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
+                         pipe);
+               break;
+       }
 
-       I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
+       if (pipestat_reg) {
+               pipestat = I915_READ(pipestat_reg);
+               pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
+                             PIPE_VBLANK_INTERRUPT_ENABLE);
+               /* Clear any stale interrupt status */
+               pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
+                            PIPE_VBLANK_INTERRUPT_STATUS);
+               I915_WRITE(pipestat_reg, pipestat);
+       }
 }
 
 /* Set the vblank monitor pipe
@@ -434,22 +654,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_vblank_pipe_t *pipe = data;
 
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
-       if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
-               DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
-               return -EINVAL;
-       }
-
-       dev_priv->vblank_pipe = pipe->pipe;
-
-       i915_enable_interrupt (dev);
-
        return 0;
 }
 
@@ -458,19 +668,13 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        drm_i915_vblank_pipe_t *pipe = data;
-       u16 flag;
 
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
-       flag = I915_READ(I915REG_INT_ENABLE_R);
-       pipe->pipe = 0;
-       if (flag & VSYNC_PIPEA_FLAG)
-               pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
-       if (flag & VSYNC_PIPEB_FLAG)
-               pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
+       pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
        return 0;
 }
@@ -484,11 +688,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
        drm_i915_private_t *dev_priv = dev->dev_private;
        drm_i915_vblank_swap_t *swap = data;
        drm_i915_vbl_swap_t *vbl_swap;
-       unsigned int pipe, seqtype, curseq;
+       unsigned int pipe, seqtype, curseq, plane;
        unsigned long irqflags;
        struct list_head *list;
+       int ret;
 
-       if (!dev_priv) {
+       if (!dev_priv || !dev_priv->sarea_priv) {
                DRM_ERROR("%s called with no initialization\n", __func__);
                return -EINVAL;
        }
@@ -504,7 +709,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+       plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+       pipe = i915_get_pipe(dev, plane);
 
        seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
 
@@ -523,7 +729,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 
        spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
-       curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+       /*
+        * We take the ref here and put it when the swap actually completes
+        * in the tasklet.
+        */
+       ret = drm_vblank_get(dev, pipe);
+       if (ret)
+               return ret;
+       curseq = drm_vblank_count(dev, pipe);
 
        if (seqtype == _DRM_VBLANK_RELATIVE)
                swap->sequence += curseq;
@@ -533,6 +746,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
                        swap->sequence = curseq + 1;
                } else {
                        DRM_DEBUG("Missed target sequence\n");
+                       drm_vblank_put(dev, pipe);
                        return -EINVAL;
                }
        }
@@ -543,7 +757,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
                vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
 
                if (vbl_swap->drw_id == swap->drawable &&
-                   vbl_swap->pipe == pipe &&
+                   vbl_swap->plane == plane &&
                    vbl_swap->sequence == swap->sequence) {
                        spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
                        DRM_DEBUG("Already scheduled\n");
@@ -555,6 +769,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 
        if (dev_priv->swaps_pending >= 100) {
                DRM_DEBUG("Too many swaps queued\n");
+               drm_vblank_put(dev, pipe);
                return -EBUSY;
        }
 
@@ -562,13 +777,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 
        if (!vbl_swap) {
                DRM_ERROR("Failed to allocate memory to queue swap\n");
+               drm_vblank_put(dev, pipe);
                return -ENOMEM;
        }
 
        DRM_DEBUG("\n");
 
        vbl_swap->drw_id = swap->drawable;
-       vbl_swap->pipe = pipe;
+       vbl_swap->plane = plane;
        vbl_swap->sequence = swap->sequence;
 
        spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -587,37 +803,63 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-       I915_WRITE16(I915REG_HWSTAM, 0xfffe);
-       I915_WRITE16(I915REG_INT_MASK_R, 0x0);
-       I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+       I915_WRITE(HWSTAM, 0xeffe);
+       I915_WRITE(IMR, 0xffffffff);
+       I915_WRITE(IER, 0x0);
 }
 
-void i915_driver_irq_postinstall(struct drm_device * dev)
+int i915_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int ret, num_pipes = 2;
 
        spin_lock_init(&dev_priv->swaps_lock);
        INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
        dev_priv->swaps_pending = 0;
 
-       if (!dev_priv->vblank_pipe)
-               dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
-       i915_enable_interrupt(dev);
+       /* Set initial unmasked IRQs to just the selected vblank pipes. */
+       dev_priv->irq_mask_reg = ~0;
+
+       ret = drm_vblank_init(dev, num_pipes);
+       if (ret)
+               return ret;
+
+       dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+       dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+       dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+       dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+
+       dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK;
+
+       I915_WRITE(IMR, dev_priv->irq_mask_reg);
+       I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+       (void) I915_READ(IER);
+
+       opregion_enable_asle(dev);
        DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+
+       return 0;
 }
 
 void i915_driver_irq_uninstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u16 temp;
+       u32 temp;
 
        if (!dev_priv)
                return;
 
-       I915_WRITE16(I915REG_HWSTAM, 0xffff);
-       I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
-       I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+       dev_priv->vblank_pipe = 0;
+
+       I915_WRITE(HWSTAM, 0xffffffff);
+       I915_WRITE(IMR, 0xffffffff);
+       I915_WRITE(IER, 0x0);
 
-       temp = I915_READ16(I915REG_INT_IDENTITY_R);
-       I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+       temp = I915_READ(PIPEASTAT);
+       I915_WRITE(PIPEASTAT, temp);
+       temp = I915_READ(PIPEBSTAT);
+       I915_WRITE(PIPEBSTAT, temp);
+       temp = I915_READ(IIR);
+       I915_WRITE(IIR, temp);
 }
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
new file mode 100644 (file)
index 0000000..1787a0c
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2008 Intel Corporation <hong.liu@intel.com>
+ * Copyright 2008 Red Hat <mjg@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/acpi.h>
+
+#include "drmP.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#define PCI_ASLE 0xe4
+#define PCI_LBPC 0xf4
+#define PCI_ASLS 0xfc
+
+#define OPREGION_SZ            (8*1024)
+#define OPREGION_HEADER_OFFSET 0
+#define OPREGION_ACPI_OFFSET   0x100
+#define OPREGION_SWSCI_OFFSET  0x200
+#define OPREGION_ASLE_OFFSET   0x300
+#define OPREGION_VBT_OFFSET    0x1000
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define MBOX_ACPI      (1<<0)
+#define MBOX_SWSCI     (1<<1)
+#define MBOX_ASLE      (1<<2)
+
+struct opregion_header {
+       u8 signature[16];
+       u32 size;
+       u32 opregion_ver;
+       u8 bios_ver[32];
+       u8 vbios_ver[16];
+       u8 driver_ver[16];
+       u32 mboxes;
+       u8 reserved[164];
+} __attribute__((packed));
+
+/* OpRegion mailbox #1: public ACPI methods */
+struct opregion_acpi {
+       u32 drdy;       /* driver readiness */
+       u32 csts;       /* notification status */
+       u32 cevt;       /* current event */
+       u8 rsvd1[20];
+       u32 didl[8];    /* supported display devices ID list */
+       u32 cpdl[8];    /* currently presented display list */
+       u32 cadl[8];    /* currently active display list */
+       u32 nadl[8];    /* next active devices list */
+       u32 aslp;       /* ASL sleep time-out */
+       u32 tidx;       /* toggle table index */
+       u32 chpd;       /* current hotplug enable indicator */
+       u32 clid;       /* current lid state*/
+       u32 cdck;       /* current docking state */
+       u32 sxsw;       /* Sx state resume */
+       u32 evts;       /* ASL supported events */
+       u32 cnot;       /* current OS notification */
+       u32 nrdy;       /* driver status */
+       u8 rsvd2[60];
+} __attribute__((packed));
+
+/* OpRegion mailbox #2: SWSCI */
+struct opregion_swsci {
+       u32 scic;       /* SWSCI command|status|data */
+       u32 parm;       /* command parameters */
+       u32 dslp;       /* driver sleep time-out */
+       u8 rsvd[244];
+} __attribute__((packed));
+
+/* OpRegion mailbox #3: ASLE */
+struct opregion_asle {
+       u32 ardy;       /* driver readiness */
+       u32 aslc;       /* ASLE interrupt command */
+       u32 tche;       /* technology enabled indicator */
+       u32 alsi;       /* current ALS illuminance reading */
+       u32 bclp;       /* backlight brightness to set */
+       u32 pfit;       /* panel fitting state */
+       u32 cblv;       /* current brightness level */
+       u16 bclm[20];   /* backlight level duty cycle mapping table */
+       u32 cpfm;       /* current panel fitting mode */
+       u32 epfm;       /* enabled panel fitting modes */
+       u8 plut[74];    /* panel LUT and identifier */
+       u32 pfmb;       /* PWM freq and min brightness */
+       u8 rsvd[102];
+} __attribute__((packed));
+
+/* ASLE irq request bits */
+#define ASLE_SET_ALS_ILLUM     (1 << 0)
+#define ASLE_SET_BACKLIGHT     (1 << 1)
+#define ASLE_SET_PFIT          (1 << 2)
+#define ASLE_SET_PWM_FREQ      (1 << 3)
+#define ASLE_REQ_MSK           0xf
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAIL    (2<<10)
+#define ASLE_BACKLIGHT_FAIL    (2<<12)
+#define ASLE_PFIT_FAIL         (2<<14)
+#define ASLE_PWM_FREQ_FAIL     (2<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID                (1<<31)
+#define ASLE_BCLP_MSK          (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID         (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* PWM frequency and minimum brightness */
+#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
+#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
+#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
+#define ASLE_PFMB_PWM_VALID (1<<31)
+
+#define ASLE_CBLV_VALID         (1<<31)
+
+static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct opregion_asle *asle = dev_priv->opregion.asle;
+       u32 blc_pwm_ctl, blc_pwm_ctl2;
+
+       if (!(bclp & ASLE_BCLP_VALID))
+               return ASLE_BACKLIGHT_FAIL;
+
+       bclp &= ASLE_BCLP_MSK;
+       if (bclp < 0 || bclp > 255)
+               return ASLE_BACKLIGHT_FAIL;
+
+       blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
+       blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
+       blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
+
+       if (blc_pwm_ctl2 & BLM_COMBINATION_MODE)
+               pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
+       else
+               I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | ((bclp * 0x101)-1));
+
+       asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+
+       return 0;
+}
+
+static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
+{
+       /* alsi is the current ALS reading in lux. 0 indicates below sensor
+          range, 0xffff indicates above sensor range. 1-0xfffe are valid */
+       return 0;
+}
+
+static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (pfmb & ASLE_PFMB_PWM_VALID) {
+               u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
+               u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
+               blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
+               pwm = pwm >> 9;
+               /* FIXME - what do we do with the PWM? */
+       }
+       return 0;
+}
+
+static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
+{
+       /* Panel fitting is currently controlled by the X code, so this is a
+          noop until modesetting support works fully */
+       if (!(pfit & ASLE_PFIT_VALID))
+               return ASLE_PFIT_FAIL;
+       return 0;
+}
+
+void opregion_asle_intr(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct opregion_asle *asle = dev_priv->opregion.asle;
+       u32 asle_stat = 0;
+       u32 asle_req;
+
+       if (!asle)
+               return;
+
+       asle_req = asle->aslc & ASLE_REQ_MSK;
+
+       if (!asle_req) {
+               DRM_DEBUG("non asle set request??\n");
+               return;
+       }
+
+       if (asle_req & ASLE_SET_ALS_ILLUM)
+               asle_stat |= asle_set_als_illum(dev, asle->alsi);
+
+       if (asle_req & ASLE_SET_BACKLIGHT)
+               asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+       if (asle_req & ASLE_SET_PFIT)
+               asle_stat |= asle_set_pfit(dev, asle->pfit);
+
+       if (asle_req & ASLE_SET_PWM_FREQ)
+               asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
+
+       asle->aslc = asle_stat;
+}
+
+#define ASLE_ALS_EN    (1<<0)
+#define ASLE_BLC_EN    (1<<1)
+#define ASLE_PFIT_EN   (1<<2)
+#define ASLE_PFMB_EN   (1<<3)
+
+void opregion_enable_asle(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct opregion_asle *asle = dev_priv->opregion.asle;
+
+       if (asle) {
+               u32 pipeb_stats = I915_READ(PIPEBSTAT);
+               if (IS_MOBILE(dev)) {
+                       /* Many devices trigger events with a write to the
+                          legacy backlight controller, so we need to ensure
+                          that it's able to generate interrupts */
+                       I915_WRITE(PIPEBSTAT, pipeb_stats |=
+                                  I915_LEGACY_BLC_EVENT_ENABLE);
+                       i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT |
+                                       I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
+               } else
+                       i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT);
+
+               asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
+                       ASLE_PFMB_EN;
+               asle->ardy = 1;
+       }
+}
+
+#define ACPI_EV_DISPLAY_SWITCH (1<<0)
+#define ACPI_EV_LID            (1<<1)
+#define ACPI_EV_DOCK           (1<<2)
+
+static struct intel_opregion *system_opregion;
+
+int intel_opregion_video_event(struct notifier_block *nb, unsigned long val,
+                              void *data)
+{
+       /* The only video events relevant to opregion are 0x80. These indicate
+          either a docking event, lid switch or display switch request. In
+          Linux, these are handled by the dock, button and video drivers.
+          We might want to fix the video driver to be opregion-aware in
+          future, but right now we just indicate to the firmware that the
+          request has been handled */
+
+       struct opregion_acpi *acpi;
+
+       if (!system_opregion)
+               return NOTIFY_DONE;
+
+       acpi = system_opregion->acpi;
+       acpi->csts = 0;
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block intel_opregion_notifier = {
+       .notifier_call = intel_opregion_video_event,
+};
+
+int intel_opregion_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+       void *base;
+       u32 asls, mboxes;
+       int err = 0;
+
+       pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
+       DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
+       if (asls == 0) {
+               DRM_DEBUG("ACPI OpRegion not supported!\n");
+               return -ENOTSUPP;
+       }
+
+       base = ioremap(asls, OPREGION_SZ);
+       if (!base)
+               return -ENOMEM;
+
+       opregion->header = base;
+       if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
+               DRM_DEBUG("opregion signature mismatch\n");
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       mboxes = opregion->header->mboxes;
+       if (mboxes & MBOX_ACPI) {
+               DRM_DEBUG("Public ACPI methods supported\n");
+               opregion->acpi = base + OPREGION_ACPI_OFFSET;
+       } else {
+               DRM_DEBUG("Public ACPI methods not supported\n");
+               err = -ENOTSUPP;
+               goto err_out;
+       }
+       opregion->enabled = 1;
+
+       if (mboxes & MBOX_SWSCI) {
+               DRM_DEBUG("SWSCI supported\n");
+               opregion->swsci = base + OPREGION_SWSCI_OFFSET;
+       }
+       if (mboxes & MBOX_ASLE) {
+               DRM_DEBUG("ASLE supported\n");
+               opregion->asle = base + OPREGION_ASLE_OFFSET;
+       }
+
+       /* Notify BIOS we are ready to handle ACPI video ext notifs.
+        * Right now, all the events are handled by the ACPI video module.
+        * We don't actually need to do anything with them. */
+       opregion->acpi->csts = 0;
+       opregion->acpi->drdy = 1;
+
+       system_opregion = opregion;
+       register_acpi_notifier(&intel_opregion_notifier);
+
+       return 0;
+
+err_out:
+       iounmap(opregion->header);
+       opregion->header = NULL;
+       return err;
+}
+
+void intel_opregion_free(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+
+       if (!opregion->enabled)
+               return;
+
+       opregion->acpi->drdy = 0;
+
+       system_opregion = NULL;
+       unregister_acpi_notifier(&intel_opregion_notifier);
+
+       /* just clear all opregion memory pointers now */
+       iounmap(opregion->header);
+       opregion->header = NULL;
+       opregion->acpi = NULL;
+       opregion->swsci = NULL;
+       opregion->asle = NULL;
+
+       opregion->enabled = 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
new file mode 100644 (file)
index 0000000..5c2d9f2
--- /dev/null
@@ -0,0 +1,1417 @@
+/* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _I915_REG_H_
+#define _I915_REG_H_
+
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ */
+#define INTEL_GMCH_CTRL                0x52
+#define INTEL_GMCH_ENABLED     0x4
+#define INTEL_GMCH_MEM_MASK    0x1
+#define INTEL_GMCH_MEM_64M     0x1
+#define INTEL_GMCH_MEM_128M    0
+
+#define INTEL_855_GMCH_GMS_MASK                (0x7 << 4)
+#define INTEL_855_GMCH_GMS_DISABLED    (0x0 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_1M   (0x1 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_4M   (0x2 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_8M   (0x3 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_16M  (0x4 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_32M  (0x5 << 4)
+
+#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
+#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
+
+/* PCI config space */
+
+#define HPLLCC 0xc0 /* 855 only */
+#define   GC_CLOCK_CONTROL_MASK                (3 << 0)
+#define   GC_CLOCK_133_200             (0 << 0)
+#define   GC_CLOCK_100_200             (1 << 0)
+#define   GC_CLOCK_100_133             (2 << 0)
+#define   GC_CLOCK_166_250             (3 << 0)
+#define GCFGC  0xf0 /* 915+ only */
+#define   GC_LOW_FREQUENCY_ENABLE      (1 << 7)
+#define   GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
+#define   GC_DISPLAY_CLOCK_333_MHZ     (4 << 4)
+#define   GC_DISPLAY_CLOCK_MASK                (7 << 4)
+#define LBB    0xf4
+
+/* VGA stuff */
+
+#define VGA_ST01_MDA 0x3ba
+#define VGA_ST01_CGA 0x3da
+
+#define VGA_MSR_WRITE 0x3c2
+#define VGA_MSR_READ 0x3cc
+#define   VGA_MSR_MEM_EN (1<<1)
+#define   VGA_MSR_CGA_MODE (1<<0)
+
+#define VGA_SR_INDEX 0x3c4
+#define VGA_SR_DATA 0x3c5
+
+#define VGA_AR_INDEX 0x3c0
+#define   VGA_AR_VID_EN (1<<5)
+#define VGA_AR_DATA_WRITE 0x3c0
+#define VGA_AR_DATA_READ 0x3c1
+
+#define VGA_GR_INDEX 0x3ce
+#define VGA_GR_DATA 0x3cf
+/* GR05 */
+#define   VGA_GR_MEM_READ_MODE_SHIFT 3
+#define     VGA_GR_MEM_READ_MODE_PLANE 1
+/* GR06 */
+#define   VGA_GR_MEM_MODE_MASK 0xc
+#define   VGA_GR_MEM_MODE_SHIFT 2
+#define   VGA_GR_MEM_A0000_AFFFF 0
+#define   VGA_GR_MEM_A0000_BFFFF 1
+#define   VGA_GR_MEM_B0000_B7FFF 2
+#define   VGA_GR_MEM_B0000_BFFFF 3
+
+#define VGA_DACMASK 0x3c6
+#define VGA_DACRX 0x3c7
+#define VGA_DACWX 0x3c8
+#define VGA_DACDATA 0x3c9
+
+#define VGA_CR_INDEX_MDA 0x3b4
+#define VGA_CR_DATA_MDA 0x3b5
+#define VGA_CR_INDEX_CGA 0x3d4
+#define VGA_CR_DATA_CGA 0x3d5
+
+/*
+ * Memory interface instructions used by the kernel
+ */
+#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags))
+
+#define MI_NOOP                        MI_INSTR(0, 0)
+#define MI_USER_INTERRUPT      MI_INSTR(0x02, 0)
+#define MI_WAIT_FOR_EVENT       MI_INSTR(0x03, 0)
+#define   MI_WAIT_FOR_PLANE_B_FLIP      (1<<6)
+#define   MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
+#define   MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
+#define MI_FLUSH               MI_INSTR(0x04, 0)
+#define   MI_READ_FLUSH                (1 << 0)
+#define   MI_EXE_FLUSH         (1 << 1)
+#define   MI_NO_WRITE_FLUSH    (1 << 2)
+#define   MI_SCENE_COUNT       (1 << 3) /* just increment scene count */
+#define   MI_END_SCENE         (1 << 4) /* flush binner and incr scene count */
+#define MI_BATCH_BUFFER_END    MI_INSTR(0x0a, 0)
+#define MI_REPORT_HEAD         MI_INSTR(0x07, 0)
+#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0)
+#define MI_STORE_DWORD_IMM     MI_INSTR(0x20, 1)
+#define   MI_MEM_VIRTUAL       (1 << 22) /* 965+ only */
+#define MI_STORE_DWORD_INDEX   MI_INSTR(0x21, 1)
+#define   MI_STORE_DWORD_INDEX_SHIFT 2
+#define MI_LOAD_REGISTER_IMM   MI_INSTR(0x22, 1)
+#define MI_BATCH_BUFFER                MI_INSTR(0x30, 1)
+#define   MI_BATCH_NON_SECURE  (1)
+#define   MI_BATCH_NON_SECURE_I965 (1<<8)
+#define MI_BATCH_BUFFER_START  MI_INSTR(0x31, 0)
+
+/*
+ * 3D instructions used by the kernel
+ */
+#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags))
+
+#define GFX_OP_RASTER_RULES    ((0x3<<29)|(0x7<<24))
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define   SC_UPDATE_SCISSOR       (0x1<<1)
+#define   SC_ENABLE_MASK          (0x1<<0)
+#define   SC_ENABLE               (0x1<<0)
+#define GFX_OP_LOAD_INDIRECT   ((0x3<<29)|(0x1d<<24)|(0x7<<16))
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define   SCI_YMIN_MASK      (0xffff<<16)
+#define   SCI_XMIN_MASK      (0xffff<<0)
+#define   SCI_YMAX_MASK      (0xffff<<16)
+#define   SCI_XMAX_MASK      (0xffff<<0)
+#define GFX_OP_SCISSOR_ENABLE   ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT     ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DESTBUFFER_INFO  ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_DRAWRECT_INFO_I965  ((0x7900<<16)|0x2)
+#define SRC_COPY_BLT_CMD                ((2<<29)|(0x43<<22)|4)
+#define XY_SRC_COPY_BLT_CMD            ((2<<29)|(0x53<<22)|6)
+#define XY_MONO_SRC_COPY_IMM_BLT       ((2<<29)|(0x71<<22)|5)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA    (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB      (1<<20)
+#define   BLT_DEPTH_8                  (0<<24)
+#define   BLT_DEPTH_16_565             (1<<24)
+#define   BLT_DEPTH_16_1555            (2<<24)
+#define   BLT_DEPTH_32                 (3<<24)
+#define   BLT_ROP_GXCOPY               (0xcc<<16)
+#define XY_SRC_COPY_BLT_SRC_TILED      (1<<15) /* 965+ only */
+#define XY_SRC_COPY_BLT_DST_TILED      (1<<11) /* 965+ only */
+#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
+#define   ASYNC_FLIP                (1<<22)
+#define   DISPLAY_PLANE_A           (0<<20)
+#define   DISPLAY_PLANE_B           (1<<20)
+
+/*
+ * Instruction and interrupt control regs
+ */
+
+#define PRB0_TAIL      0x02030
+#define PRB0_HEAD      0x02034
+#define PRB0_START     0x02038
+#define PRB0_CTL       0x0203c
+#define   TAIL_ADDR            0x001FFFF8
+#define   HEAD_WRAP_COUNT      0xFFE00000
+#define   HEAD_WRAP_ONE                0x00200000
+#define   HEAD_ADDR            0x001FFFFC
+#define   RING_NR_PAGES                0x001FF000
+#define   RING_REPORT_MASK     0x00000006
+#define   RING_REPORT_64K      0x00000002
+#define   RING_REPORT_128K     0x00000004
+#define   RING_NO_REPORT       0x00000000
+#define   RING_VALID_MASK      0x00000001
+#define   RING_VALID           0x00000001
+#define   RING_INVALID         0x00000000
+#define PRB1_TAIL      0x02040 /* 915+ only */
+#define PRB1_HEAD      0x02044 /* 915+ only */
+#define PRB1_START     0x02048 /* 915+ only */
+#define PRB1_CTL       0x0204c /* 915+ only */
+#define ACTHD_I965     0x02074
+#define HWS_PGA                0x02080
+#define HWS_ADDRESS_MASK       0xfffff000
+#define HWS_START_ADDRESS_SHIFT        4
+#define IPEIR          0x02088
+#define NOPID          0x02094
+#define HWSTAM         0x02098
+#define SCPD0          0x0209c /* 915+ only */
+#define IER            0x020a0
+#define IIR            0x020a4
+#define IMR            0x020a8
+#define ISR            0x020ac
+#define   I915_PIPE_CONTROL_NOTIFY_INTERRUPT           (1<<18)
+#define   I915_DISPLAY_PORT_INTERRUPT                  (1<<17)
+#define   I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT   (1<<15)
+#define   I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT     (1<<14)
+#define   I915_HWB_OOM_INTERRUPT                       (1<<13)
+#define   I915_SYNC_STATUS_INTERRUPT                   (1<<12)
+#define   I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT  (1<<11)
+#define   I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT  (1<<10)
+#define   I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT    (1<<9)
+#define   I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT  (1<<8)
+#define   I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT         (1<<7)
+#define   I915_DISPLAY_PIPE_A_EVENT_INTERRUPT          (1<<6)
+#define   I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT         (1<<5)
+#define   I915_DISPLAY_PIPE_B_EVENT_INTERRUPT          (1<<4)
+#define   I915_DEBUG_INTERRUPT                         (1<<2)
+#define   I915_USER_INTERRUPT                          (1<<1)
+#define   I915_ASLE_INTERRUPT                          (1<<0)
+#define EIR            0x020b0
+#define EMR            0x020b4
+#define ESR            0x020b8
+#define INSTPM         0x020c0
+#define ACTHD          0x020c8
+#define FW_BLC         0x020d8
+#define FW_BLC_SELF    0x020e0 /* 915+ only */
+#define MI_ARB_STATE   0x020e4 /* 915+ only */
+#define CACHE_MODE_0   0x02120 /* 915+ only */
+#define   CM0_MASK_SHIFT          16
+#define   CM0_IZ_OPT_DISABLE      (1<<6)
+#define   CM0_ZR_OPT_DISABLE      (1<<5)
+#define   CM0_DEPTH_EVICT_DISABLE (1<<4)
+#define   CM0_COLOR_EVICT_DISABLE (1<<3)
+#define   CM0_DEPTH_WRITE_DISABLE (1<<1)
+#define   CM0_RC_OP_FLUSH_DISABLE (1<<0)
+#define GFX_FLSH_CNTL  0x02170 /* 915+ only */
+
+/*
+ * Framebuffer compression (915+ only)
+ */
+
+#define FBC_CFB_BASE           0x03200 /* 4k page aligned */
+#define FBC_LL_BASE            0x03204 /* 4k page aligned */
+#define FBC_CONTROL            0x03208
+#define   FBC_CTL_EN           (1<<31)
+#define   FBC_CTL_PERIODIC     (1<<30)
+#define   FBC_CTL_INTERVAL_SHIFT (16)
+#define   FBC_CTL_UNCOMPRESSIBLE (1<<14)
+#define   FBC_CTL_STRIDE_SHIFT (5)
+#define   FBC_CTL_FENCENO      (1<<0)
+#define FBC_COMMAND            0x0320c
+#define   FBC_CMD_COMPRESS     (1<<0)
+#define FBC_STATUS             0x03210
+#define   FBC_STAT_COMPRESSING (1<<31)
+#define   FBC_STAT_COMPRESSED  (1<<30)
+#define   FBC_STAT_MODIFIED    (1<<29)
+#define   FBC_STAT_CURRENT_LINE        (1<<0)
+#define FBC_CONTROL2           0x03214
+#define   FBC_CTL_FENCE_DBL    (0<<4)
+#define   FBC_CTL_IDLE_IMM     (0<<2)
+#define   FBC_CTL_IDLE_FULL    (1<<2)
+#define   FBC_CTL_IDLE_LINE    (2<<2)
+#define   FBC_CTL_IDLE_DEBUG   (3<<2)
+#define   FBC_CTL_CPU_FENCE    (1<<1)
+#define   FBC_CTL_PLANEA       (0<<0)
+#define   FBC_CTL_PLANEB       (1<<0)
+#define FBC_FENCE_OFF          0x0321b
+
+#define FBC_LL_SIZE            (1536)
+
+/*
+ * GPIO regs
+ */
+#define GPIOA                  0x5010
+#define GPIOB                  0x5014
+#define GPIOC                  0x5018
+#define GPIOD                  0x501c
+#define GPIOE                  0x5020
+#define GPIOF                  0x5024
+#define GPIOG                  0x5028
+#define GPIOH                  0x502c
+# define GPIO_CLOCK_DIR_MASK           (1 << 0)
+# define GPIO_CLOCK_DIR_IN             (0 << 1)
+# define GPIO_CLOCK_DIR_OUT            (1 << 1)
+# define GPIO_CLOCK_VAL_MASK           (1 << 2)
+# define GPIO_CLOCK_VAL_OUT            (1 << 3)
+# define GPIO_CLOCK_VAL_IN             (1 << 4)
+# define GPIO_CLOCK_PULLUP_DISABLE     (1 << 5)
+# define GPIO_DATA_DIR_MASK            (1 << 8)
+# define GPIO_DATA_DIR_IN              (0 << 9)
+# define GPIO_DATA_DIR_OUT             (1 << 9)
+# define GPIO_DATA_VAL_MASK            (1 << 10)
+# define GPIO_DATA_VAL_OUT             (1 << 11)
+# define GPIO_DATA_VAL_IN              (1 << 12)
+# define GPIO_DATA_PULLUP_DISABLE      (1 << 13)
+
+/*
+ * Clock control & power management
+ */
+
+#define VGA0   0x6000
+#define VGA1   0x6004
+#define VGA_PD 0x6010
+#define   VGA0_PD_P2_DIV_4     (1 << 7)
+#define   VGA0_PD_P1_DIV_2     (1 << 5)
+#define   VGA0_PD_P1_SHIFT     0
+#define   VGA0_PD_P1_MASK      (0x1f << 0)
+#define   VGA1_PD_P2_DIV_4     (1 << 15)
+#define   VGA1_PD_P1_DIV_2     (1 << 13)
+#define   VGA1_PD_P1_SHIFT     8
+#define   VGA1_PD_P1_MASK      (0x1f << 8)
+#define DPLL_A 0x06014
+#define DPLL_B 0x06018
+#define   DPLL_VCO_ENABLE              (1 << 31)
+#define   DPLL_DVO_HIGH_SPEED          (1 << 30)
+#define   DPLL_SYNCLOCK_ENABLE         (1 << 29)
+#define   DPLL_VGA_MODE_DIS            (1 << 28)
+#define   DPLLB_MODE_DAC_SERIAL                (1 << 26) /* i915 */
+#define   DPLLB_MODE_LVDS              (2 << 26) /* i915 */
+#define   DPLL_MODE_MASK               (3 << 26)
+#define   DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
+#define   DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
+#define   DPLLB_LVDS_P2_CLOCK_DIV_14   (0 << 24) /* i915 */
+#define   DPLLB_LVDS_P2_CLOCK_DIV_7    (1 << 24) /* i915 */
+#define   DPLL_P2_CLOCK_DIV_MASK       0x03000000 /* i915 */
+#define   DPLL_FPA01_P1_POST_DIV_MASK  0x00ff0000 /* i915 */
+
+#define I915_FIFO_UNDERRUN_STATUS              (1UL<<31)
+#define I915_CRC_ERROR_ENABLE                  (1UL<<29)
+#define I915_CRC_DONE_ENABLE                   (1UL<<28)
+#define I915_GMBUS_EVENT_ENABLE                        (1UL<<27)
+#define I915_VSYNC_INTERRUPT_ENABLE            (1UL<<25)
+#define I915_DISPLAY_LINE_COMPARE_ENABLE       (1UL<<24)
+#define I915_DPST_EVENT_ENABLE                 (1UL<<23)
+#define I915_LEGACY_BLC_EVENT_ENABLE           (1UL<<22)
+#define I915_ODD_FIELD_INTERRUPT_ENABLE                (1UL<<21)
+#define I915_EVEN_FIELD_INTERRUPT_ENABLE       (1UL<<20)
+#define I915_START_VBLANK_INTERRUPT_ENABLE     (1UL<<18)       /* 965 or later */
+#define I915_VBLANK_INTERRUPT_ENABLE           (1UL<<17)
+#define I915_OVERLAY_UPDATED_ENABLE            (1UL<<16)
+#define I915_CRC_ERROR_INTERRUPT_STATUS                (1UL<<13)
+#define I915_CRC_DONE_INTERRUPT_STATUS         (1UL<<12)
+#define I915_GMBUS_INTERRUPT_STATUS            (1UL<<11)
+#define I915_VSYNC_INTERRUPT_STATUS            (1UL<<9)
+#define I915_DISPLAY_LINE_COMPARE_STATUS       (1UL<<8)
+#define I915_DPST_EVENT_STATUS                 (1UL<<7)
+#define I915_LEGACY_BLC_EVENT_STATUS           (1UL<<6)
+#define I915_ODD_FIELD_INTERRUPT_STATUS                (1UL<<5)
+#define I915_EVEN_FIELD_INTERRUPT_STATUS       (1UL<<4)
+#define I915_START_VBLANK_INTERRUPT_STATUS     (1UL<<2)        /* 965 or later */
+#define I915_VBLANK_INTERRUPT_STATUS           (1UL<<1)
+#define I915_OVERLAY_UPDATED_STATUS            (1UL<<0)
+
+#define SRX_INDEX              0x3c4
+#define SRX_DATA               0x3c5
+#define SR01                   1
+#define SR01_SCREEN_OFF                (1<<5)
+
+#define PPCR                   0x61204
+#define PPCR_ON                        (1<<0)
+
+#define DVOB                   0x61140
+#define DVOB_ON                        (1<<31)
+#define DVOC                   0x61160
+#define DVOC_ON                        (1<<31)
+#define LVDS                   0x61180
+#define LVDS_ON                        (1<<31)
+
+#define ADPA                   0x61100
+#define ADPA_DPMS_MASK         (~(3<<10))
+#define ADPA_DPMS_ON           (0<<10)
+#define ADPA_DPMS_SUSPEND      (1<<10)
+#define ADPA_DPMS_STANDBY      (2<<10)
+#define ADPA_DPMS_OFF          (3<<10)
+
+#define RING_TAIL              0x00
+#define TAIL_ADDR              0x001FFFF8
+#define RING_HEAD              0x04
+#define HEAD_WRAP_COUNT                0xFFE00000
+#define HEAD_WRAP_ONE          0x00200000
+#define HEAD_ADDR              0x001FFFFC
+#define RING_START             0x08
+#define START_ADDR             0xFFFFF000
+#define RING_LEN               0x0C
+#define RING_NR_PAGES          0x001FF000
+#define RING_REPORT_MASK       0x00000006
+#define RING_REPORT_64K                0x00000002
+#define RING_REPORT_128K       0x00000004
+#define RING_NO_REPORT         0x00000000
+#define RING_VALID_MASK                0x00000001
+#define RING_VALID             0x00000001
+#define RING_INVALID           0x00000000
+
+/* Scratch pad debug 0 reg:
+ */
+#define   DPLL_FPA01_P1_POST_DIV_MASK_I830     0x001f0000
+/*
+ * The i830 generation, in LVDS mode, defines P1 as the bit number set within
+ * this field (only one bit may be set).
+ */
+#define   DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS        0x003f0000
+#define   DPLL_FPA01_P1_POST_DIV_SHIFT 16
+/* i830, required in DVO non-gang */
+#define   PLL_P2_DIVIDE_BY_4           (1 << 23)
+#define   PLL_P1_DIVIDE_BY_TWO         (1 << 21) /* i830 */
+#define   PLL_REF_INPUT_DREFCLK                (0 << 13)
+#define   PLL_REF_INPUT_TVCLKINA       (1 << 13) /* i830 */
+#define   PLL_REF_INPUT_TVCLKINBC      (2 << 13) /* SDVO TVCLKIN */
+#define   PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
+#define   PLL_REF_INPUT_MASK           (3 << 13)
+#define   PLL_LOAD_PULSE_PHASE_SHIFT           9
+/*
+ * Parallel to Serial Load Pulse phase selection.
+ * Selects the phase for the 10X DPLL clock for the PCIe
+ * digital display port. The range is 4 to 13; 10 or more
+ * is just a flip delay. The default is 6
+ */
+#define   PLL_LOAD_PULSE_PHASE_MASK            (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
+#define   DISPLAY_RATE_SELECT_FPA1             (1 << 8)
+/*
+ * SDVO multiplier for 945G/GM. Not used on 965.
+ */
+#define   SDVO_MULTIPLIER_MASK                 0x000000ff
+#define   SDVO_MULTIPLIER_SHIFT_HIRES          4
+#define   SDVO_MULTIPLIER_SHIFT_VGA            0
+#define DPLL_A_MD 0x0601c /* 965+ only */
+/*
+ * UDI pixel divider, controlling how many pixels are stuffed into a packet.
+ *
+ * Value is pixels minus 1.  Must be set to 1 pixel for SDVO.
+ */
+#define   DPLL_MD_UDI_DIVIDER_MASK             0x3f000000
+#define   DPLL_MD_UDI_DIVIDER_SHIFT            24
+/* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
+#define   DPLL_MD_VGA_UDI_DIVIDER_MASK         0x003f0000
+#define   DPLL_MD_VGA_UDI_DIVIDER_SHIFT                16
+/*
+ * SDVO/UDI pixel multiplier.
+ *
+ * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
+ * clock rate is 10 times the DPLL clock.  At low resolution/refresh rate
+ * modes, the bus rate would be below the limits, so SDVO allows for stuffing
+ * dummy bytes in the datastream at an increased clock rate, with both sides of
+ * the link knowing how many bytes are fill.
+ *
+ * So, for a mode with a dotclock of 65Mhz, we would want to double the clock
+ * rate to 130Mhz to get a bus rate of 1.30Ghz.  The DPLL clock rate would be
+ * set to 130Mhz, and the SDVO multiplier set to 2x in this register and
+ * through an SDVO command.
+ *
+ * This register field has values of multiplication factor minus 1, with
+ * a maximum multiplier of 5 for SDVO.
+ */
+#define   DPLL_MD_UDI_MULTIPLIER_MASK          0x00003f00
+#define   DPLL_MD_UDI_MULTIPLIER_SHIFT         8
+/*
+ * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
+ * This best be set to the default value (3) or the CRT won't work. No,
+ * I don't entirely understand what this does...
+ */
+#define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK      0x0000003f
+#define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT     0
+#define DPLL_B_MD 0x06020 /* 965+ only */
+#define FPA0   0x06040
+#define FPA1   0x06044
+#define FPB0   0x06048
+#define FPB1   0x0604c
+#define   FP_N_DIV_MASK                0x003f0000
+#define   FP_N_DIV_SHIFT               16
+#define   FP_M1_DIV_MASK       0x00003f00
+#define   FP_M1_DIV_SHIFT               8
+#define   FP_M2_DIV_MASK       0x0000003f
+#define   FP_M2_DIV_SHIFT               0
+#define DPLL_TEST      0x606c
+#define   DPLLB_TEST_SDVO_DIV_1                (0 << 22)
+#define   DPLLB_TEST_SDVO_DIV_2                (1 << 22)
+#define   DPLLB_TEST_SDVO_DIV_4                (2 << 22)
+#define   DPLLB_TEST_SDVO_DIV_MASK     (3 << 22)
+#define   DPLLB_TEST_N_BYPASS          (1 << 19)
+#define   DPLLB_TEST_M_BYPASS          (1 << 18)
+#define   DPLLB_INPUT_BUFFER_ENABLE    (1 << 16)
+#define   DPLLA_TEST_N_BYPASS          (1 << 3)
+#define   DPLLA_TEST_M_BYPASS          (1 << 2)
+#define   DPLLA_INPUT_BUFFER_ENABLE    (1 << 0)
+#define D_STATE                0x6104
+#define CG_2D_DIS      0x6200
+#define CG_3D_DIS      0x6204
+
+/*
+ * Palette regs
+ */
+
+#define PALETTE_A              0x0a000
+#define PALETTE_B              0x0a800
+
+/* MCH MMIO space */
+
+/*
+ * MCHBAR mirror.
+ *
+ * This mirrors the MCHBAR MMIO space whose location is determined by
+ * device 0 function 0's pci config register 0x44 or 0x48 and matches it in
+ * every way.  It is not accessible from the CP register read instructions.
+ *
+ */
+#define MCHBAR_MIRROR_BASE     0x10000
+
+/** 915-945 and GM965 MCH register controlling DRAM channel access */
+#define DCC                    0x10200
+#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL             (0 << 0)
+#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC    (1 << 0)
+#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED   (2 << 0)
+#define DCC_ADDRESSING_MODE_MASK                       (3 << 0)
+#define DCC_CHANNEL_XOR_DISABLE                                (1 << 10)
+
+/** 965 MCH register controlling DRAM channel configuration */
+#define C0DRB3                 0x10206
+#define C1DRB3                 0x10606
+
+/*
+ * Overlay regs
+ */
+
+#define OVADD                  0x30000
+#define DOVSTA                 0x30008
+#define OC_BUF                 (0x3<<20)
+#define OGAMC5                 0x30010
+#define OGAMC4                 0x30014
+#define OGAMC3                 0x30018
+#define OGAMC2                 0x3001c
+#define OGAMC1                 0x30020
+#define OGAMC0                 0x30024
+
+/*
+ * Display engine regs
+ */
+
+/* Pipe A timing regs */
+#define HTOTAL_A       0x60000
+#define HBLANK_A       0x60004
+#define HSYNC_A                0x60008
+#define VTOTAL_A       0x6000c
+#define VBLANK_A       0x60010
+#define VSYNC_A                0x60014
+#define PIPEASRC       0x6001c
+#define BCLRPAT_A      0x60020
+
+/* Pipe B timing regs */
+#define HTOTAL_B       0x61000
+#define HBLANK_B       0x61004
+#define HSYNC_B                0x61008
+#define VTOTAL_B       0x6100c
+#define VBLANK_B       0x61010
+#define VSYNC_B                0x61014
+#define PIPEBSRC       0x6101c
+#define BCLRPAT_B      0x61020
+
+/* VGA port control */
+#define ADPA                   0x61100
+#define   ADPA_DAC_ENABLE      (1<<31)
+#define   ADPA_DAC_DISABLE     0
+#define   ADPA_PIPE_SELECT_MASK        (1<<30)
+#define   ADPA_PIPE_A_SELECT   0
+#define   ADPA_PIPE_B_SELECT   (1<<30)
+#define   ADPA_USE_VGA_HVPOLARITY (1<<15)
+#define   ADPA_SETS_HVPOLARITY 0
+#define   ADPA_VSYNC_CNTL_DISABLE (1<<11)
+#define   ADPA_VSYNC_CNTL_ENABLE 0
+#define   ADPA_HSYNC_CNTL_DISABLE (1<<10)
+#define   ADPA_HSYNC_CNTL_ENABLE 0
+#define   ADPA_VSYNC_ACTIVE_HIGH (1<<4)
+#define   ADPA_VSYNC_ACTIVE_LOW        0
+#define   ADPA_HSYNC_ACTIVE_HIGH (1<<3)
+#define   ADPA_HSYNC_ACTIVE_LOW        0
+#define   ADPA_DPMS_MASK       (~(3<<10))
+#define   ADPA_DPMS_ON         (0<<10)
+#define   ADPA_DPMS_SUSPEND    (1<<10)
+#define   ADPA_DPMS_STANDBY    (2<<10)
+#define   ADPA_DPMS_OFF                (3<<10)
+
+/* Hotplug control (945+ only) */
+#define PORT_HOTPLUG_EN                0x61110
+#define   SDVOB_HOTPLUG_INT_EN                 (1 << 26)
+#define   SDVOC_HOTPLUG_INT_EN                 (1 << 25)
+#define   TV_HOTPLUG_INT_EN                    (1 << 18)
+#define   CRT_HOTPLUG_INT_EN                   (1 << 9)
+#define   CRT_HOTPLUG_FORCE_DETECT             (1 << 3)
+
+#define PORT_HOTPLUG_STAT      0x61114
+#define   CRT_HOTPLUG_INT_STATUS               (1 << 11)
+#define   TV_HOTPLUG_INT_STATUS                        (1 << 10)
+#define   CRT_HOTPLUG_MONITOR_MASK             (3 << 8)
+#define   CRT_HOTPLUG_MONITOR_COLOR            (3 << 8)
+#define   CRT_HOTPLUG_MONITOR_MONO             (2 << 8)
+#define   CRT_HOTPLUG_MONITOR_NONE             (0 << 8)
+#define   SDVOC_HOTPLUG_INT_STATUS             (1 << 7)
+#define   SDVOB_HOTPLUG_INT_STATUS             (1 << 6)
+
+/* SDVO port control */
+#define SDVOB                  0x61140
+#define SDVOC                  0x61160
+#define   SDVO_ENABLE          (1 << 31)
+#define   SDVO_PIPE_B_SELECT   (1 << 30)
+#define   SDVO_STALL_SELECT    (1 << 29)
+#define   SDVO_INTERRUPT_ENABLE        (1 << 26)
+/**
+ * 915G/GM SDVO pixel multiplier.
+ *
+ * Programmed value is multiplier - 1, up to 5x.
+ *
+ * \sa DPLL_MD_UDI_MULTIPLIER_MASK
+ */
+#define   SDVO_PORT_MULTIPLY_MASK      (7 << 23)
+#define   SDVO_PORT_MULTIPLY_SHIFT             23
+#define   SDVO_PHASE_SELECT_MASK       (15 << 19)
+#define   SDVO_PHASE_SELECT_DEFAULT    (6 << 19)
+#define   SDVO_CLOCK_OUTPUT_INVERT     (1 << 18)
+#define   SDVOC_GANG_MODE              (1 << 16)
+#define   SDVO_BORDER_ENABLE           (1 << 7)
+#define   SDVOB_PCIE_CONCURRENCY       (1 << 3)
+#define   SDVO_DETECTED                        (1 << 2)
+/* Bits to be preserved when writing */
+#define   SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26))
+#define   SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26))
+
+/* DVO port control */
+#define DVOA                   0x61120
+#define DVOB                   0x61140
+#define DVOC                   0x61160
+#define   DVO_ENABLE                   (1 << 31)
+#define   DVO_PIPE_B_SELECT            (1 << 30)
+#define   DVO_PIPE_STALL_UNUSED                (0 << 28)
+#define   DVO_PIPE_STALL               (1 << 28)
+#define   DVO_PIPE_STALL_TV            (2 << 28)
+#define   DVO_PIPE_STALL_MASK          (3 << 28)
+#define   DVO_USE_VGA_SYNC             (1 << 15)
+#define   DVO_DATA_ORDER_I740          (0 << 14)
+#define   DVO_DATA_ORDER_FP            (1 << 14)
+#define   DVO_VSYNC_DISABLE            (1 << 11)
+#define   DVO_HSYNC_DISABLE            (1 << 10)
+#define   DVO_VSYNC_TRISTATE           (1 << 9)
+#define   DVO_HSYNC_TRISTATE           (1 << 8)
+#define   DVO_BORDER_ENABLE            (1 << 7)
+#define   DVO_DATA_ORDER_GBRG          (1 << 6)
+#define   DVO_DATA_ORDER_RGGB          (0 << 6)
+#define   DVO_DATA_ORDER_GBRG_ERRATA   (0 << 6)
+#define   DVO_DATA_ORDER_RGGB_ERRATA   (1 << 6)
+#define   DVO_VSYNC_ACTIVE_HIGH                (1 << 4)
+#define   DVO_HSYNC_ACTIVE_HIGH                (1 << 3)
+#define   DVO_BLANK_ACTIVE_HIGH                (1 << 2)
+#define   DVO_OUTPUT_CSTATE_PIXELS     (1 << 1)        /* SDG only */
+#define   DVO_OUTPUT_SOURCE_SIZE_PIXELS        (1 << 0)        /* SDG only */
+#define   DVO_PRESERVE_MASK            (0x7<<24)
+#define DVOA_SRCDIM            0x61124
+#define DVOB_SRCDIM            0x61144
+#define DVOC_SRCDIM            0x61164
+#define   DVO_SRCDIM_HORIZONTAL_SHIFT  12
+#define   DVO_SRCDIM_VERTICAL_SHIFT    0
+
+/* LVDS port control */
+#define LVDS                   0x61180
+/*
+ * Enables the LVDS port.  This bit must be set before DPLLs are enabled, as
+ * the DPLL semantics change when the LVDS is assigned to that pipe.
+ */
+#define   LVDS_PORT_EN                 (1 << 31)
+/* Selects pipe B for LVDS data.  Must be set on pre-965. */
+#define   LVDS_PIPEB_SELECT            (1 << 30)
+/*
+ * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
+ * pixel.
+ */
+#define   LVDS_A0A2_CLKA_POWER_MASK    (3 << 8)
+#define   LVDS_A0A2_CLKA_POWER_DOWN    (0 << 8)
+#define   LVDS_A0A2_CLKA_POWER_UP      (3 << 8)
+/*
+ * Controls the A3 data pair, which contains the additional LSBs for 24 bit
+ * mode.  Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
+ * on.
+ */
+#define   LVDS_A3_POWER_MASK           (3 << 6)
+#define   LVDS_A3_POWER_DOWN           (0 << 6)
+#define   LVDS_A3_POWER_UP             (3 << 6)
+/*
+ * Controls the CLKB pair.  This should only be set when LVDS_B0B3_POWER_UP
+ * is set.
+ */
+#define   LVDS_CLKB_POWER_MASK         (3 << 4)
+#define   LVDS_CLKB_POWER_DOWN         (0 << 4)
+#define   LVDS_CLKB_POWER_UP           (3 << 4)
+/*
+ * Controls the B0-B3 data pairs.  This must be set to match the DPLL p2
+ * setting for whether we are in dual-channel mode.  The B3 pair will
+ * additionally only be powered up when LVDS_A3_POWER_UP is set.
+ */
+#define   LVDS_B0B3_POWER_MASK         (3 << 2)
+#define   LVDS_B0B3_POWER_DOWN         (0 << 2)
+#define   LVDS_B0B3_POWER_UP           (3 << 2)
+
+/* Panel power sequencing */
+#define PP_STATUS      0x61200
+#define   PP_ON                (1 << 31)
+/*
+ * Indicates that all dependencies of the panel are on:
+ *
+ * - PLL enabled
+ * - pipe enabled
+ * - LVDS/DVOB/DVOC on
+ */
+#define   PP_READY             (1 << 30)
+#define   PP_SEQUENCE_NONE     (0 << 28)
+#define   PP_SEQUENCE_ON       (1 << 28)
+#define   PP_SEQUENCE_OFF      (2 << 28)
+#define   PP_SEQUENCE_MASK     0x30000000
+#define PP_CONTROL     0x61204
+#define   POWER_TARGET_ON      (1 << 0)
+#define PP_ON_DELAYS   0x61208
+#define PP_OFF_DELAYS  0x6120c
+#define PP_DIVISOR     0x61210
+
+/* Panel fitting */
+#define PFIT_CONTROL   0x61230
+#define   PFIT_ENABLE          (1 << 31)
+#define   PFIT_PIPE_MASK       (3 << 29)
+#define   PFIT_PIPE_SHIFT      29
+#define   VERT_INTERP_DISABLE  (0 << 10)
+#define   VERT_INTERP_BILINEAR (1 << 10)
+#define   VERT_INTERP_MASK     (3 << 10)
+#define   VERT_AUTO_SCALE      (1 << 9)
+#define   HORIZ_INTERP_DISABLE (0 << 6)
+#define   HORIZ_INTERP_BILINEAR        (1 << 6)
+#define   HORIZ_INTERP_MASK    (3 << 6)
+#define   HORIZ_AUTO_SCALE     (1 << 5)
+#define   PANEL_8TO6_DITHER_ENABLE (1 << 3)
+#define PFIT_PGM_RATIOS        0x61234
+#define   PFIT_VERT_SCALE_MASK                 0xfff00000
+#define   PFIT_HORIZ_SCALE_MASK                        0x0000fff0
+#define PFIT_AUTO_RATIOS 0x61238
+
+/* Backlight control */
+#define BLC_PWM_CTL            0x61254
+#define   BACKLIGHT_MODULATION_FREQ_SHIFT              (17)
+#define BLC_PWM_CTL2           0x61250 /* 965+ only */
+#define   BLM_COMBINATION_MODE (1 << 30)
+/*
+ * This is the most significant 15 bits of the number of backlight cycles in a
+ * complete cycle of the modulated backlight control.
+ *
+ * The actual value is this field multiplied by two.
+ */
+#define   BACKLIGHT_MODULATION_FREQ_MASK               (0x7fff << 17)
+#define   BLM_LEGACY_MODE                              (1 << 16)
+/*
+ * This is the number of cycles out of the backlight modulation cycle for which
+ * the backlight is on.
+ *
+ * This field must be no greater than the number of cycles in the complete
+ * backlight modulation cycle.
+ */
+#define   BACKLIGHT_DUTY_CYCLE_SHIFT           (0)
+#define   BACKLIGHT_DUTY_CYCLE_MASK            (0xffff)
+
+/* TV port control */
+#define TV_CTL                 0x68000
+/** Enables the TV encoder */
+# define TV_ENC_ENABLE                 (1 << 31)
+/** Sources the TV encoder input from pipe B instead of A. */
+# define TV_ENC_PIPEB_SELECT           (1 << 30)
+/** Outputs composite video (DAC A only) */
+# define TV_ENC_OUTPUT_COMPOSITE       (0 << 28)
+/** Outputs SVideo video (DAC B/C) */
+# define TV_ENC_OUTPUT_SVIDEO          (1 << 28)
+/** Outputs Component video (DAC A/B/C) */
+# define TV_ENC_OUTPUT_COMPONENT       (2 << 28)
+/** Outputs Composite and SVideo (DAC A/B/C) */
+# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE        (3 << 28)
+# define TV_TRILEVEL_SYNC              (1 << 21)
+/** Enables slow sync generation (945GM only) */
+# define TV_SLOW_SYNC                  (1 << 20)
+/** Selects 4x oversampling for 480i and 576p */
+# define TV_OVERSAMPLE_4X              (0 << 18)
+/** Selects 2x oversampling for 720p and 1080i */
+# define TV_OVERSAMPLE_2X              (1 << 18)
+/** Selects no oversampling for 1080p */
+# define TV_OVERSAMPLE_NONE            (2 << 18)
+/** Selects 8x oversampling */
+# define TV_OVERSAMPLE_8X              (3 << 18)
+/** Selects progressive mode rather than interlaced */
+# define TV_PROGRESSIVE                        (1 << 17)
+/** Sets the colorburst to PAL mode.  Required for non-M PAL modes. */
+# define TV_PAL_BURST                  (1 << 16)
+/** Field for setting delay of Y compared to C */
+# define TV_YC_SKEW_MASK               (7 << 12)
+/** Enables a fix for 480p/576p standard definition modes on the 915GM only */
+# define TV_ENC_SDP_FIX                        (1 << 11)
+/**
+ * Enables a fix for the 915GM only.
+ *
+ * Not sure what it does.
+ */
+# define TV_ENC_C0_FIX                 (1 << 10)
+/** Bits that must be preserved by software */
+# define TV_CTL_SAVE                   ((3 << 8) | (3 << 6))
+# define TV_FUSE_STATE_MASK            (3 << 4)
+/** Read-only state that reports all features enabled */
+# define TV_FUSE_STATE_ENABLED         (0 << 4)
+/** Read-only state that reports that Macrovision is disabled in hardware*/
+# define TV_FUSE_STATE_NO_MACROVISION  (1 << 4)
+/** Read-only state that reports that TV-out is disabled in hardware. */
+# define TV_FUSE_STATE_DISABLED                (2 << 4)
+/** Normal operation */
+# define TV_TEST_MODE_NORMAL           (0 << 0)
+/** Encoder test pattern 1 - combo pattern */
+# define TV_TEST_MODE_PATTERN_1                (1 << 0)
+/** Encoder test pattern 2 - full screen vertical 75% color bars */
+# define TV_TEST_MODE_PATTERN_2                (2 << 0)
+/** Encoder test pattern 3 - full screen horizontal 75% color bars */
+# define TV_TEST_MODE_PATTERN_3                (3 << 0)
+/** Encoder test pattern 4 - random noise */
+# define TV_TEST_MODE_PATTERN_4                (4 << 0)
+/** Encoder test pattern 5 - linear color ramps */
+# define TV_TEST_MODE_PATTERN_5                (5 << 0)
+/**
+ * This test mode forces the DACs to 50% of full output.
+ *
+ * This is used for load detection in combination with TVDAC_SENSE_MASK
+ */
+# define TV_TEST_MODE_MONITOR_DETECT   (7 << 0)
+# define TV_TEST_MODE_MASK             (7 << 0)
+
+#define TV_DAC                 0x68004
+/**
+ * Reports that DAC state change logic has reported change (RO).
+ *
+ * This gets cleared when TV_DAC_STATE_EN is cleared
+*/
+# define TVDAC_STATE_CHG               (1 << 31)
+# define TVDAC_SENSE_MASK              (7 << 28)
+/** Reports that DAC A voltage is above the detect threshold */
+# define TVDAC_A_SENSE                 (1 << 30)
+/** Reports that DAC B voltage is above the detect threshold */
+# define TVDAC_B_SENSE                 (1 << 29)
+/** Reports that DAC C voltage is above the detect threshold */
+# define TVDAC_C_SENSE                 (1 << 28)
+/**
+ * Enables DAC state detection logic, for load-based TV detection.
+ *
+ * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set
+ * to off, for load detection to work.
+ */
+# define TVDAC_STATE_CHG_EN            (1 << 27)
+/** Sets the DAC A sense value to high */
+# define TVDAC_A_SENSE_CTL             (1 << 26)
+/** Sets the DAC B sense value to high */
+# define TVDAC_B_SENSE_CTL             (1 << 25)
+/** Sets the DAC C sense value to high */
+# define TVDAC_C_SENSE_CTL             (1 << 24)
+/** Overrides the ENC_ENABLE and DAC voltage levels */
+# define DAC_CTL_OVERRIDE              (1 << 7)
+/** Sets the slew rate.  Must be preserved in software */
+# define ENC_TVDAC_SLEW_FAST           (1 << 6)
+# define DAC_A_1_3_V                   (0 << 4)
+# define DAC_A_1_1_V                   (1 << 4)
+# define DAC_A_0_7_V                   (2 << 4)
+# define DAC_A_OFF                     (3 << 4)
+# define DAC_B_1_3_V                   (0 << 2)
+# define DAC_B_1_1_V                   (1 << 2)
+# define DAC_B_0_7_V                   (2 << 2)
+# define DAC_B_OFF                     (3 << 2)
+# define DAC_C_1_3_V                   (0 << 0)
+# define DAC_C_1_1_V                   (1 << 0)
+# define DAC_C_0_7_V                   (2 << 0)
+# define DAC_C_OFF                     (3 << 0)
+
+/**
+ * CSC coefficients are stored in a floating point format with 9 bits of
+ * mantissa and 2 or 3 bits of exponent.  The exponent is represented as 2**-n,
+ * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
+ * -1 (0x3) being the only legal negative value.
+ */
+#define TV_CSC_Y               0x68010
+# define TV_RY_MASK                    0x07ff0000
+# define TV_RY_SHIFT                   16
+# define TV_GY_MASK                    0x00000fff
+# define TV_GY_SHIFT                   0
+
+#define TV_CSC_Y2              0x68014
+# define TV_BY_MASK                    0x07ff0000
+# define TV_BY_SHIFT                   16
+/**
+ * Y attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AY_MASK                    0x000003ff
+# define TV_AY_SHIFT                   0
+
+#define TV_CSC_U               0x68018
+# define TV_RU_MASK                    0x07ff0000
+# define TV_RU_SHIFT                   16
+# define TV_GU_MASK                    0x000007ff
+# define TV_GU_SHIFT                   0
+
+#define TV_CSC_U2              0x6801c
+# define TV_BU_MASK                    0x07ff0000
+# define TV_BU_SHIFT                   16
+/**
+ * U attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AU_MASK                    0x000003ff
+# define TV_AU_SHIFT                   0
+
+#define TV_CSC_V               0x68020
+# define TV_RV_MASK                    0x0fff0000
+# define TV_RV_SHIFT                   16
+# define TV_GV_MASK                    0x000007ff
+# define TV_GV_SHIFT                   0
+
+#define TV_CSC_V2              0x68024
+# define TV_BV_MASK                    0x07ff0000
+# define TV_BV_SHIFT                   16
+/**
+ * V attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AV_MASK                    0x000007ff
+# define TV_AV_SHIFT                   0
+
+#define TV_CLR_KNOBS           0x68028
+/** 2s-complement brightness adjustment */
+# define TV_BRIGHTNESS_MASK            0xff000000
+# define TV_BRIGHTNESS_SHIFT           24
+/** Contrast adjustment, as a 2.6 unsigned floating point number */
+# define TV_CONTRAST_MASK              0x00ff0000
+# define TV_CONTRAST_SHIFT             16
+/** Saturation adjustment, as a 2.6 unsigned floating point number */
+# define TV_SATURATION_MASK            0x0000ff00
+# define TV_SATURATION_SHIFT           8
+/** Hue adjustment, as an integer phase angle in degrees */
+# define TV_HUE_MASK                   0x000000ff
+# define TV_HUE_SHIFT                  0
+
+#define TV_CLR_LEVEL           0x6802c
+/** Controls the DAC level for black */
+# define TV_BLACK_LEVEL_MASK           0x01ff0000
+# define TV_BLACK_LEVEL_SHIFT          16
+/** Controls the DAC level for blanking */
+# define TV_BLANK_LEVEL_MASK           0x000001ff
+# define TV_BLANK_LEVEL_SHIFT          0
+
+#define TV_H_CTL_1             0x68030
+/** Number of pixels in the hsync. */
+# define TV_HSYNC_END_MASK             0x1fff0000
+# define TV_HSYNC_END_SHIFT            16
+/** Total number of pixels minus one in the line (display and blanking). */
+# define TV_HTOTAL_MASK                        0x00001fff
+# define TV_HTOTAL_SHIFT               0
+
+#define TV_H_CTL_2             0x68034
+/** Enables the colorburst (needed for non-component color) */
+# define TV_BURST_ENA                  (1 << 31)
+/** Offset of the colorburst from the start of hsync, in pixels minus one. */
+# define TV_HBURST_START_SHIFT         16
+# define TV_HBURST_START_MASK          0x1fff0000
+/** Length of the colorburst */
+# define TV_HBURST_LEN_SHIFT           0
+# define TV_HBURST_LEN_MASK            0x0001fff
+
+#define TV_H_CTL_3             0x68038
+/** End of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_END_SHIFT           16
+# define TV_HBLANK_END_MASK            0x1fff0000
+/** Start of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_START_SHIFT         0
+# define TV_HBLANK_START_MASK          0x0001fff
+
+#define TV_V_CTL_1             0x6803c
+/** XXX */
+# define TV_NBR_END_SHIFT              16
+# define TV_NBR_END_MASK               0x07ff0000
+/** XXX */
+# define TV_VI_END_F1_SHIFT            8
+# define TV_VI_END_F1_MASK             0x00003f00
+/** XXX */
+# define TV_VI_END_F2_SHIFT            0
+# define TV_VI_END_F2_MASK             0x0000003f
+
+#define TV_V_CTL_2             0x68040
+/** Length of vsync, in half lines */
+# define TV_VSYNC_LEN_MASK             0x07ff0000
+# define TV_VSYNC_LEN_SHIFT            16
+/** Offset of the start of vsync in field 1, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F1_MASK                0x00007f00
+# define TV_VSYNC_START_F1_SHIFT       8
+/**
+ * Offset of the start of vsync in field 2, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F2_MASK                0x0000007f
+# define TV_VSYNC_START_F2_SHIFT       0
+
+#define TV_V_CTL_3             0x68044
+/** Enables generation of the equalization signal */
+# define TV_EQUAL_ENA                  (1 << 31)
+/** Length of vsync, in half lines */
+# define TV_VEQ_LEN_MASK               0x007f0000
+# define TV_VEQ_LEN_SHIFT              16
+/** Offset of the start of equalization in field 1, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F1_MASK          0x0007f00
+# define TV_VEQ_START_F1_SHIFT         8
+/**
+ * Offset of the start of equalization in field 2, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F2_MASK          0x000007f
+# define TV_VEQ_START_F2_SHIFT         0
+
+#define TV_V_CTL_4             0x68048
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F1_MASK       0x003f0000
+# define TV_VBURST_START_F1_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F1_MASK         0x000000ff
+# define TV_VBURST_END_F1_SHIFT                0
+
+#define TV_V_CTL_5             0x6804c
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F2_MASK       0x003f0000
+# define TV_VBURST_START_F2_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F2_MASK         0x000000ff
+# define TV_VBURST_END_F2_SHIFT                0
+
+#define TV_V_CTL_6             0x68050
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F3_MASK       0x003f0000
+# define TV_VBURST_START_F3_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F3_MASK         0x000000ff
+# define TV_VBURST_END_F3_SHIFT                0
+
+#define TV_V_CTL_7             0x68054
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F4_MASK       0x003f0000
+# define TV_VBURST_START_F4_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F4_MASK         0x000000ff
+# define TV_VBURST_END_F4_SHIFT                0
+
+#define TV_SC_CTL_1            0x68060
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA1_EN                 (1 << 31)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA2_EN                 (1 << 30)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA3_EN                 (1 << 29)
+/** Sets the subcarrier DDA to reset frequency every other field */
+# define TV_SC_RESET_EVERY_2           (0 << 24)
+/** Sets the subcarrier DDA to reset frequency every fourth field */
+# define TV_SC_RESET_EVERY_4           (1 << 24)
+/** Sets the subcarrier DDA to reset frequency every eighth field */
+# define TV_SC_RESET_EVERY_8           (2 << 24)
+/** Sets the subcarrier DDA to never reset the frequency */
+# define TV_SC_RESET_NEVER             (3 << 24)
+/** Sets the peak amplitude of the colorburst.*/
+# define TV_BURST_LEVEL_MASK           0x00ff0000
+# define TV_BURST_LEVEL_SHIFT          16
+/** Sets the increment of the first subcarrier phase generation DDA */
+# define TV_SCDDA1_INC_MASK            0x00000fff
+# define TV_SCDDA1_INC_SHIFT           0
+
+#define TV_SC_CTL_2            0x68064
+/** Sets the rollover for the second subcarrier phase generation DDA */
+# define TV_SCDDA2_SIZE_MASK           0x7fff0000
+# define TV_SCDDA2_SIZE_SHIFT          16
+/** Sets the increent of the second subcarrier phase generation DDA */
+# define TV_SCDDA2_INC_MASK            0x00007fff
+# define TV_SCDDA2_INC_SHIFT           0
+
+#define TV_SC_CTL_3            0x68068
+/** Sets the rollover for the third subcarrier phase generation DDA */
+# define TV_SCDDA3_SIZE_MASK           0x7fff0000
+# define TV_SCDDA3_SIZE_SHIFT          16
+/** Sets the increent of the third subcarrier phase generation DDA */
+# define TV_SCDDA3_INC_MASK            0x00007fff
+# define TV_SCDDA3_INC_SHIFT           0
+
+#define TV_WIN_POS             0x68070
+/** X coordinate of the display from the start of horizontal active */
+# define TV_XPOS_MASK                  0x1fff0000
+# define TV_XPOS_SHIFT                 16
+/** Y coordinate of the display from the start of vertical active (NBR) */
+# define TV_YPOS_MASK                  0x00000fff
+# define TV_YPOS_SHIFT                 0
+
+#define TV_WIN_SIZE            0x68074
+/** Horizontal size of the display window, measured in pixels*/
+# define TV_XSIZE_MASK                 0x1fff0000
+# define TV_XSIZE_SHIFT                        16
+/**
+ * Vertical size of the display window, measured in pixels.
+ *
+ * Must be even for interlaced modes.
+ */
+# define TV_YSIZE_MASK                 0x00000fff
+# define TV_YSIZE_SHIFT                        0
+
+#define TV_FILTER_CTL_1                0x68080
+/**
+ * Enables automatic scaling calculation.
+ *
+ * If set, the rest of the registers are ignored, and the calculated values can
+ * be read back from the register.
+ */
+# define TV_AUTO_SCALE                 (1 << 31)
+/**
+ * Disables the vertical filter.
+ *
+ * This is required on modes more than 1024 pixels wide */
+# define TV_V_FILTER_BYPASS            (1 << 29)
+/** Enables adaptive vertical filtering */
+# define TV_VADAPT                     (1 << 28)
+# define TV_VADAPT_MODE_MASK           (3 << 26)
+/** Selects the least adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_LEAST          (0 << 26)
+/** Selects the moderately adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MODERATE       (1 << 26)
+/** Selects the most adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MOST           (3 << 26)
+/**
+ * Sets the horizontal scaling factor.
+ *
+ * This should be the fractional part of the horizontal scaling factor divided
+ * by the oversampling rate.  TV_HSCALE should be less than 1, and set to:
+ *
+ * (src width - 1) / ((oversample * dest width) - 1)
+ */
+# define TV_HSCALE_FRAC_MASK           0x00003fff
+# define TV_HSCALE_FRAC_SHIFT          0
+
+#define TV_FILTER_CTL_2                0x68084
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1)
+ */
+# define TV_VSCALE_INT_MASK            0x00038000
+# define TV_VSCALE_INT_SHIFT           15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * \sa TV_VSCALE_INT_MASK
+ */
+# define TV_VSCALE_FRAC_MASK           0x00007fff
+# define TV_VSCALE_FRAC_SHIFT          0
+
+#define TV_FILTER_CTL_3                0x68088
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1))
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ */
+# define TV_VSCALE_IP_INT_MASK         0x00038000
+# define TV_VSCALE_IP_INT_SHIFT                15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ *
+ * \sa TV_VSCALE_IP_INT_MASK
+ */
+# define TV_VSCALE_IP_FRAC_MASK                0x00007fff
+# define TV_VSCALE_IP_FRAC_SHIFT               0
+
+#define TV_CC_CONTROL          0x68090
+# define TV_CC_ENABLE                  (1 << 31)
+/**
+ * Specifies which field to send the CC data in.
+ *
+ * CC data is usually sent in field 0.
+ */
+# define TV_CC_FID_MASK                        (1 << 27)
+# define TV_CC_FID_SHIFT               27
+/** Sets the horizontal position of the CC data.  Usually 135. */
+# define TV_CC_HOFF_MASK               0x03ff0000
+# define TV_CC_HOFF_SHIFT              16
+/** Sets the vertical position of the CC data.  Usually 21 */
+# define TV_CC_LINE_MASK               0x0000003f
+# define TV_CC_LINE_SHIFT              0
+
+#define TV_CC_DATA             0x68094
+# define TV_CC_RDY                     (1 << 31)
+/** Second word of CC data to be transmitted. */
+# define TV_CC_DATA_2_MASK             0x007f0000
+# define TV_CC_DATA_2_SHIFT            16
+/** First word of CC data to be transmitted. */
+# define TV_CC_DATA_1_MASK             0x0000007f
+# define TV_CC_DATA_1_SHIFT            0
+
+#define TV_H_LUMA_0            0x68100
+#define TV_H_LUMA_59           0x681ec
+#define TV_H_CHROMA_0          0x68200
+#define TV_H_CHROMA_59         0x682ec
+#define TV_V_LUMA_0            0x68300
+#define TV_V_LUMA_42           0x683a8
+#define TV_V_CHROMA_0          0x68400
+#define TV_V_CHROMA_42         0x684a8
+
+/* Display & cursor control */
+
+/* Pipe A */
+#define PIPEADSL               0x70000
+#define PIPEACONF              0x70008
+#define   PIPEACONF_ENABLE     (1<<31)
+#define   PIPEACONF_DISABLE    0
+#define   PIPEACONF_DOUBLE_WIDE        (1<<30)
+#define   I965_PIPECONF_ACTIVE (1<<30)
+#define   PIPEACONF_SINGLE_WIDE        0
+#define   PIPEACONF_PIPE_UNLOCKED 0
+#define   PIPEACONF_PIPE_LOCKED        (1<<25)
+#define   PIPEACONF_PALETTE    0
+#define   PIPEACONF_GAMMA              (1<<24)
+#define   PIPECONF_FORCE_BORDER        (1<<25)
+#define   PIPECONF_PROGRESSIVE (0 << 21)
+#define   PIPECONF_INTERLACE_W_FIELD_INDICATION        (6 << 21)
+#define   PIPECONF_INTERLACE_FIELD_0_ONLY              (7 << 21)
+#define PIPEASTAT              0x70024
+#define   PIPE_FIFO_UNDERRUN_STATUS            (1UL<<31)
+#define   PIPE_CRC_ERROR_ENABLE                        (1UL<<29)
+#define   PIPE_CRC_DONE_ENABLE                 (1UL<<28)
+#define   PIPE_GMBUS_EVENT_ENABLE              (1UL<<27)
+#define   PIPE_HOTPLUG_INTERRUPT_ENABLE                (1UL<<26)
+#define   PIPE_VSYNC_INTERRUPT_ENABLE          (1UL<<25)
+#define   PIPE_DISPLAY_LINE_COMPARE_ENABLE     (1UL<<24)
+#define   PIPE_DPST_EVENT_ENABLE               (1UL<<23)
+#define   PIPE_LEGACY_BLC_EVENT_ENABLE         (1UL<<22)
+#define   PIPE_ODD_FIELD_INTERRUPT_ENABLE      (1UL<<21)
+#define   PIPE_EVEN_FIELD_INTERRUPT_ENABLE     (1UL<<20)
+#define   PIPE_HOTPLUG_TV_INTERRUPT_ENABLE     (1UL<<18) /* pre-965 */
+#define   PIPE_START_VBLANK_INTERRUPT_ENABLE   (1UL<<18) /* 965 or later */
+#define   PIPE_VBLANK_INTERRUPT_ENABLE         (1UL<<17)
+#define   PIPE_OVERLAY_UPDATED_ENABLE          (1UL<<16)
+#define   PIPE_CRC_ERROR_INTERRUPT_STATUS      (1UL<<13)
+#define   PIPE_CRC_DONE_INTERRUPT_STATUS       (1UL<<12)
+#define   PIPE_GMBUS_INTERRUPT_STATUS          (1UL<<11)
+#define   PIPE_HOTPLUG_INTERRUPT_STATUS                (1UL<<10)
+#define   PIPE_VSYNC_INTERRUPT_STATUS          (1UL<<9)
+#define   PIPE_DISPLAY_LINE_COMPARE_STATUS     (1UL<<8)
+#define   PIPE_DPST_EVENT_STATUS               (1UL<<7)
+#define   PIPE_LEGACY_BLC_EVENT_STATUS         (1UL<<6)
+#define   PIPE_ODD_FIELD_INTERRUPT_STATUS      (1UL<<5)
+#define   PIPE_EVEN_FIELD_INTERRUPT_STATUS     (1UL<<4)
+#define   PIPE_HOTPLUG_TV_INTERRUPT_STATUS     (1UL<<2) /* pre-965 */
+#define   PIPE_START_VBLANK_INTERRUPT_STATUS   (1UL<<2) /* 965 or later */
+#define   PIPE_VBLANK_INTERRUPT_STATUS         (1UL<<1)
+#define   PIPE_OVERLAY_UPDATED_STATUS          (1UL<<0)
+
+#define DSPARB                 0x70030
+#define   DSPARB_CSTART_MASK   (0x7f << 7)
+#define   DSPARB_CSTART_SHIFT  7
+#define   DSPARB_BSTART_MASK   (0x7f)
+#define   DSPARB_BSTART_SHIFT  0
+/*
+ * The two pipe frame counter registers are not synchronized, so
+ * reading a stable value is somewhat tricky. The following code
+ * should work:
+ *
+ *  do {
+ *    high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ *             PIPE_FRAME_HIGH_SHIFT;
+ *    low1 =  ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >>
+ *             PIPE_FRAME_LOW_SHIFT);
+ *    high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ *             PIPE_FRAME_HIGH_SHIFT);
+ *  } while (high1 != high2);
+ *  frame = (high1 << 8) | low1;
+ */
+#define PIPEAFRAMEHIGH          0x70040
+#define   PIPE_FRAME_HIGH_MASK    0x0000ffff
+#define   PIPE_FRAME_HIGH_SHIFT   0
+#define PIPEAFRAMEPIXEL         0x70044
+#define   PIPE_FRAME_LOW_MASK     0xff000000
+#define   PIPE_FRAME_LOW_SHIFT    24
+#define   PIPE_PIXEL_MASK         0x00ffffff
+#define   PIPE_PIXEL_SHIFT        0
+
+/* Cursor A & B regs */
+#define CURACNTR               0x70080
+#define   CURSOR_MODE_DISABLE   0x00
+#define   CURSOR_MODE_64_32B_AX 0x07
+#define   CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
+#define   MCURSOR_GAMMA_ENABLE  (1 << 26)
+#define CURABASE               0x70084
+#define CURAPOS                        0x70088
+#define   CURSOR_POS_MASK       0x007FF
+#define   CURSOR_POS_SIGN       0x8000
+#define   CURSOR_X_SHIFT        0
+#define   CURSOR_Y_SHIFT        16
+#define CURBCNTR               0x700c0
+#define CURBBASE               0x700c4
+#define CURBPOS                        0x700c8
+
+/* Display A control */
+#define DSPACNTR                0x70180
+#define   DISPLAY_PLANE_ENABLE                 (1<<31)
+#define   DISPLAY_PLANE_DISABLE                        0
+#define   DISPPLANE_GAMMA_ENABLE               (1<<30)
+#define   DISPPLANE_GAMMA_DISABLE              0
+#define   DISPPLANE_PIXFORMAT_MASK             (0xf<<26)
+#define   DISPPLANE_8BPP                       (0x2<<26)
+#define   DISPPLANE_15_16BPP                   (0x4<<26)
+#define   DISPPLANE_16BPP                      (0x5<<26)
+#define   DISPPLANE_32BPP_NO_ALPHA             (0x6<<26)
+#define   DISPPLANE_32BPP                      (0x7<<26)
+#define   DISPPLANE_STEREO_ENABLE              (1<<25)
+#define   DISPPLANE_STEREO_DISABLE             0
+#define   DISPPLANE_SEL_PIPE_MASK              (1<<24)
+#define   DISPPLANE_SEL_PIPE_A                 0
+#define   DISPPLANE_SEL_PIPE_B                 (1<<24)
+#define   DISPPLANE_SRC_KEY_ENABLE             (1<<22)
+#define   DISPPLANE_SRC_KEY_DISABLE            0
+#define   DISPPLANE_LINE_DOUBLE                        (1<<20)
+#define   DISPPLANE_NO_LINE_DOUBLE             0
+#define   DISPPLANE_STEREO_POLARITY_FIRST      0
+#define   DISPPLANE_STEREO_POLARITY_SECOND     (1<<18)
+#define DSPAADDR               0x70184
+#define DSPASTRIDE             0x70188
+#define DSPAPOS                        0x7018C /* reserved */
+#define DSPASIZE               0x70190
+#define DSPASURF               0x7019C /* 965+ only */
+#define DSPATILEOFF            0x701A4 /* 965+ only */
+
+/* VBIOS flags */
+#define SWF00                  0x71410
+#define SWF01                  0x71414
+#define SWF02                  0x71418
+#define SWF03                  0x7141c
+#define SWF04                  0x71420
+#define SWF05                  0x71424
+#define SWF06                  0x71428
+#define SWF10                  0x70410
+#define SWF11                  0x70414
+#define SWF14                  0x71420
+#define SWF30                  0x72414
+#define SWF31                  0x72418
+#define SWF32                  0x7241c
+
+/* Pipe B */
+#define PIPEBDSL               0x71000
+#define PIPEBCONF              0x71008
+#define PIPEBSTAT              0x71024
+#define PIPEBFRAMEHIGH         0x71040
+#define PIPEBFRAMEPIXEL                0x71044
+
+/* Display B control */
+#define DSPBCNTR               0x71180
+#define   DISPPLANE_ALPHA_TRANS_ENABLE         (1<<15)
+#define   DISPPLANE_ALPHA_TRANS_DISABLE                0
+#define   DISPPLANE_SPRITE_ABOVE_DISPLAY       0
+#define   DISPPLANE_SPRITE_ABOVE_OVERLAY       (1)
+#define DSPBADDR               0x71184
+#define DSPBSTRIDE             0x71188
+#define DSPBPOS                        0x7118C
+#define DSPBSIZE               0x71190
+#define DSPBSURF               0x7119C
+#define DSPBTILEOFF            0x711A4
+
+/* VBIOS regs */
+#define VGACNTRL               0x71400
+# define VGA_DISP_DISABLE                      (1 << 31)
+# define VGA_2X_MODE                           (1 << 30)
+# define VGA_PIPE_B_SELECT                     (1 << 29)
+
+#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
new file mode 100644 (file)
index 0000000..603fe74
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ *
+ * Copyright 2008 (c) Intel Corporation
+ *   Jesse Barnes <jbarnes@virtuousgeek.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (pipe == PIPE_A)
+               return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE);
+       else
+               return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE);
+}
+
+static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+       u32 *array;
+       int i;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return;
+
+       if (pipe == PIPE_A)
+               array = dev_priv->save_palette_a;
+       else
+               array = dev_priv->save_palette_b;
+
+       for(i = 0; i < 256; i++)
+               array[i] = I915_READ(reg + (i << 2));
+}
+
+static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+       u32 *array;
+       int i;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return;
+
+       if (pipe == PIPE_A)
+               array = dev_priv->save_palette_a;
+       else
+               array = dev_priv->save_palette_b;
+
+       for(i = 0; i < 256; i++)
+               I915_WRITE(reg + (i << 2), array[i]);
+}
+
+static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE8(index_port, reg);
+       return I915_READ8(data_port);
+}
+
+static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_READ8(st01);
+       I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
+       return I915_READ8(VGA_AR_DATA_READ);
+}
+
+static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_READ8(st01);
+       I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
+       I915_WRITE8(VGA_AR_DATA_WRITE, val);
+}
+
+static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE8(index_port, reg);
+       I915_WRITE8(data_port, val);
+}
+
+static void i915_save_vga(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+       u16 cr_index, cr_data, st01;
+
+       /* VGA color palette registers */
+       dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK);
+       /* DACCRX automatically increments during read */
+       I915_WRITE8(VGA_DACRX, 0);
+       /* Read 3 bytes of color data from each index */
+       for (i = 0; i < 256 * 3; i++)
+               dev_priv->saveDACDATA[i] = I915_READ8(VGA_DACDATA);
+
+       /* MSR bits */
+       dev_priv->saveMSR = I915_READ8(VGA_MSR_READ);
+       if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+               cr_index = VGA_CR_INDEX_CGA;
+               cr_data = VGA_CR_DATA_CGA;
+               st01 = VGA_ST01_CGA;
+       } else {
+               cr_index = VGA_CR_INDEX_MDA;
+               cr_data = VGA_CR_DATA_MDA;
+               st01 = VGA_ST01_MDA;
+       }
+
+       /* CRT controller regs */
+       i915_write_indexed(dev, cr_index, cr_data, 0x11,
+                          i915_read_indexed(dev, cr_index, cr_data, 0x11) &
+                          (~0x80));
+       for (i = 0; i <= 0x24; i++)
+               dev_priv->saveCR[i] =
+                       i915_read_indexed(dev, cr_index, cr_data, i);
+       /* Make sure we don't turn off CR group 0 writes */
+       dev_priv->saveCR[0x11] &= ~0x80;
+
+       /* Attribute controller registers */
+       I915_READ8(st01);
+       dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX);
+       for (i = 0; i <= 0x14; i++)
+               dev_priv->saveAR[i] = i915_read_ar(dev, st01, i, 0);
+       I915_READ8(st01);
+       I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX);
+       I915_READ8(st01);
+
+       /* Graphics controller registers */
+       for (i = 0; i < 9; i++)
+               dev_priv->saveGR[i] =
+                       i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i);
+
+       dev_priv->saveGR[0x10] =
+               i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10);
+       dev_priv->saveGR[0x11] =
+               i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11);
+       dev_priv->saveGR[0x18] =
+               i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18);
+
+       /* Sequencer registers */
+       for (i = 0; i < 8; i++)
+               dev_priv->saveSR[i] =
+                       i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i);
+}
+
+static void i915_restore_vga(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+       u16 cr_index, cr_data, st01;
+
+       /* MSR bits */
+       I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR);
+       if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+               cr_index = VGA_CR_INDEX_CGA;
+               cr_data = VGA_CR_DATA_CGA;
+               st01 = VGA_ST01_CGA;
+       } else {
+               cr_index = VGA_CR_INDEX_MDA;
+               cr_data = VGA_CR_DATA_MDA;
+               st01 = VGA_ST01_MDA;
+       }
+
+       /* Sequencer registers, don't write SR07 */
+       for (i = 0; i < 7; i++)
+               i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i,
+                                  dev_priv->saveSR[i]);
+
+       /* CRT controller regs */
+       /* Enable CR group 0 writes */
+       i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
+       for (i = 0; i <= 0x24; i++)
+               i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->saveCR[i]);
+
+       /* Graphics controller regs */
+       for (i = 0; i < 9; i++)
+               i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i,
+                                  dev_priv->saveGR[i]);
+
+       i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10,
+                          dev_priv->saveGR[0x10]);
+       i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11,
+                          dev_priv->saveGR[0x11]);
+       i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18,
+                          dev_priv->saveGR[0x18]);
+
+       /* Attribute controller registers */
+       I915_READ8(st01); /* switch back to index mode */
+       for (i = 0; i <= 0x14; i++)
+               i915_write_ar(dev, st01, i, dev_priv->saveAR[i], 0);
+       I915_READ8(st01); /* switch back to index mode */
+       I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20);
+       I915_READ8(st01);
+
+       /* VGA color palette registers */
+       I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
+       /* DACCRX automatically increments during read */
+       I915_WRITE8(VGA_DACWX, 0);
+       /* Read 3 bytes of color data from each index */
+       for (i = 0; i < 256 * 3; i++)
+               I915_WRITE8(VGA_DACDATA, dev_priv->saveDACDATA[i]);
+
+}
+
+int i915_save_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
+
+       /* Display arbitration control */
+       dev_priv->saveDSPARB = I915_READ(DSPARB);
+
+       /* Pipe & plane A info */
+       dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
+       dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
+       dev_priv->saveFPA0 = I915_READ(FPA0);
+       dev_priv->saveFPA1 = I915_READ(FPA1);
+       dev_priv->saveDPLL_A = I915_READ(DPLL_A);
+       if (IS_I965G(dev))
+               dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
+       dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
+       dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
+       dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
+       dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
+       dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
+       dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
+       dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+
+       dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
+       dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
+       dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
+       dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
+       dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
+       if (IS_I965G(dev)) {
+               dev_priv->saveDSPASURF = I915_READ(DSPASURF);
+               dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
+       }
+       i915_save_palette(dev, PIPE_A);
+       dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT);
+
+       /* Pipe & plane B info */
+       dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
+       dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
+       dev_priv->saveFPB0 = I915_READ(FPB0);
+       dev_priv->saveFPB1 = I915_READ(FPB1);
+       dev_priv->saveDPLL_B = I915_READ(DPLL_B);
+       if (IS_I965G(dev))
+               dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
+       dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
+       dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
+       dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
+       dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
+       dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
+       dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
+       dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+
+       dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
+       dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
+       dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
+       dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
+       dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
+       if (IS_I965GM(dev) || IS_GM45(dev)) {
+               dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
+               dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
+       }
+       i915_save_palette(dev, PIPE_B);
+       dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
+
+       /* CRT state */
+       dev_priv->saveADPA = I915_READ(ADPA);
+
+       /* LVDS state */
+       dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
+       dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
+       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       if (IS_I965G(dev))
+               dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               dev_priv->saveLVDS = I915_READ(LVDS);
+       if (!IS_I830(dev) && !IS_845G(dev))
+               dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
+       dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
+       dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
+       dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
+
+       /* FIXME: save TV & SDVO state */
+
+       /* FBC state */
+       dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
+       dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
+       dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
+       dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
+
+       /* Interrupt state */
+       dev_priv->saveIIR = I915_READ(IIR);
+       dev_priv->saveIER = I915_READ(IER);
+       dev_priv->saveIMR = I915_READ(IMR);
+
+       /* VGA state */
+       dev_priv->saveVGA0 = I915_READ(VGA0);
+       dev_priv->saveVGA1 = I915_READ(VGA1);
+       dev_priv->saveVGA_PD = I915_READ(VGA_PD);
+       dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
+
+       /* Clock gating state */
+       dev_priv->saveD_STATE = I915_READ(D_STATE);
+       dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS);
+
+       /* Cache mode state */
+       dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
+
+       /* Memory Arbitration state */
+       dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
+
+       /* Scratch space */
+       for (i = 0; i < 16; i++) {
+               dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2));
+               dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
+       }
+       for (i = 0; i < 3; i++)
+               dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
+
+       i915_save_vga(dev);
+
+       return 0;
+}
+
+int i915_restore_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
+
+       I915_WRITE(DSPARB, dev_priv->saveDSPARB);
+
+       /* Pipe & plane A info */
+       /* Prime the clock */
+       if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
+                          ~DPLL_VCO_ENABLE);
+               DRM_UDELAY(150);
+       }
+       I915_WRITE(FPA0, dev_priv->saveFPA0);
+       I915_WRITE(FPA1, dev_priv->saveFPA1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
+       DRM_UDELAY(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
+       DRM_UDELAY(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
+       I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
+       I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
+       I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
+       I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
+       I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
+       I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
+
+       /* Restore plane info */
+       I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
+       I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
+       I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
+       I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
+       I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
+               I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
+       }
+
+       I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
+
+       i915_restore_palette(dev, PIPE_A);
+       /* Enable the plane */
+       I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
+       I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
+
+       /* Pipe & plane B info */
+       if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
+               I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
+                          ~DPLL_VCO_ENABLE);
+               DRM_UDELAY(150);
+       }
+       I915_WRITE(FPB0, dev_priv->saveFPB0);
+       I915_WRITE(FPB1, dev_priv->saveFPB1);
+       /* Actually enable it */
+       I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
+       DRM_UDELAY(150);
+       if (IS_I965G(dev))
+               I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
+       DRM_UDELAY(150);
+
+       /* Restore mode */
+       I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
+       I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
+       I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
+       I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
+       I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
+       I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
+       I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
+
+       /* Restore plane info */
+       I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
+       I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
+       I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
+       I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
+       I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
+       if (IS_I965G(dev)) {
+               I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
+               I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
+       }
+
+       I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
+
+       i915_restore_palette(dev, PIPE_B);
+       /* Enable the plane */
+       I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
+       I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
+
+       /* CRT state */
+       I915_WRITE(ADPA, dev_priv->saveADPA);
+
+       /* LVDS state */
+       if (IS_I965G(dev))
+               I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               I915_WRITE(LVDS, dev_priv->saveLVDS);
+       if (!IS_I830(dev) && !IS_845G(dev))
+               I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
+
+       I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
+       I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
+       I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
+       I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
+       I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
+       I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+
+       /* FIXME: restore TV & SDVO state */
+
+       /* FBC info */
+       I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
+       I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
+       I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
+       I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
+
+       /* VGA state */
+       I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
+       I915_WRITE(VGA0, dev_priv->saveVGA0);
+       I915_WRITE(VGA1, dev_priv->saveVGA1);
+       I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
+       DRM_UDELAY(150);
+
+       /* Clock gating state */
+       I915_WRITE (D_STATE, dev_priv->saveD_STATE);
+       I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS);
+
+       /* Cache mode state */
+       I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
+
+       /* Memory arbitration state */
+       I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
+
+       for (i = 0; i < 16; i++) {
+               I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
+               I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
+       }
+       for (i = 0; i < 3; i++)
+               I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
+
+       i915_restore_vga(dev);
+
+       return 0;
+}
+
index 5572939fc7d19cb1f986833a22ce79a21ad1da0a..97ee566ef7492468ecb4c2489b5644d74f5cd5af 100644 (file)
@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = {
 static struct drm_driver driver = {
        .driver_features =
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
-           DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
-           DRIVER_IRQ_VBL,
+           DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .dev_priv_size = sizeof(drm_mga_buf_priv_t),
        .load = mga_driver_load,
        .unload = mga_driver_unload,
        .lastclose = mga_driver_lastclose,
        .dma_quiescent = mga_driver_dma_quiescent,
        .device_is_agp = mga_driver_device_is_agp,
-       .vblank_wait = mga_driver_vblank_wait,
+       .get_vblank_counter = mga_get_vblank_counter,
+       .enable_vblank = mga_enable_vblank,
+       .disable_vblank = mga_disable_vblank,
        .irq_preinstall = mga_driver_irq_preinstall,
        .irq_postinstall = mga_driver_irq_postinstall,
        .irq_uninstall = mga_driver_irq_uninstall,
@@ -64,20 +65,20 @@ static struct drm_driver driver = {
        .ioctls = mga_ioctls,
        .dma_ioctl = mga_dma_buffers,
        .fops = {
-                .owner = THIS_MODULE,
-                .open = drm_open,
-                .release = drm_release,
-                .ioctl = drm_ioctl,
-                .mmap = drm_mmap,
-                .poll = drm_poll,
-                .fasync = drm_fasync,
+               .owner = THIS_MODULE,
+               .open = drm_open,
+               .release = drm_release,
+               .ioctl = drm_ioctl,
+               .mmap = drm_mmap,
+               .poll = drm_poll,
+               .fasync = drm_fasync,
 #ifdef CONFIG_COMPAT
-                .compat_ioctl = mga_compat_ioctl,
+               .compat_ioctl = mga_compat_ioctl,
 #endif
-                },
+       },
        .pci_driver = {
-                .name = DRIVER_NAME,
-                .id_table = pciidlist,
+               .name = DRIVER_NAME,
+               .id_table = pciidlist,
        },
 
        .name = DRIVER_NAME,
index f6ebd24bd5871ebad2204c64195e3e3e31219401..88257c276eb9f640f4d5b3399acfe099900ed569 100644 (file)
@@ -120,6 +120,7 @@ typedef struct drm_mga_private {
        u32 clear_cmd;
        u32 maccess;
 
+       atomic_t vbl_received;          /**< Number of vblanks received. */
        wait_queue_head_t fence_queue;
        atomic_t last_fence_retired;
        u32 next_fence_to_post;
@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
 extern int mga_warp_init(drm_mga_private_t * dev_priv);
 
                                /* mga_irq.c */
+extern int mga_enable_vblank(struct drm_device *dev, int crtc);
+extern void mga_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
 extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
 extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
 extern void mga_driver_irq_preinstall(struct drm_device * dev);
-extern void mga_driver_irq_postinstall(struct drm_device * dev);
+extern int mga_driver_irq_postinstall(struct drm_device *dev);
 extern void mga_driver_irq_uninstall(struct drm_device * dev);
 extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
index 9302cb8f0f83bef1e99be219a9b977884d3f6d28..bab42f41188b0238356b4ef1ce80caeb87e6a6db 100644 (file)
@@ -1,5 +1,6 @@
 /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
- *
+ */
+/*
  * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
  *
  * The Weather Channel (TM) funded Tungsten Graphics to develop the
 #include "mga_drm.h"
 #include "mga_drv.h"
 
+u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+       const drm_mga_private_t *const dev_priv =
+               (drm_mga_private_t *) dev->dev_private;
+
+       if (crtc != 0)
+               return 0;
+
+       return atomic_read(&dev_priv->vbl_received);
+}
+
+
 irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
        /* VBLANK interrupt */
        if (status & MGA_VLINEPEN) {
                MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
-               atomic_inc(&dev->vbl_received);
-               DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals(dev);
+               atomic_inc(&dev_priv->vbl_received);
+               drm_handle_vblank(dev, 0);
                handled = 1;
        }
 
@@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
                const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
                const u32 prim_end = MGA_READ(MGA_PRIMEND);
 
+
                MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
 
                /* In addition to clearing the interrupt-pending bit, we
@@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
                handled = 1;
        }
 
-       if (handled) {
+       if (handled)
                return IRQ_HANDLED;
-       }
        return IRQ_NONE;
 }
 
-int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int mga_enable_vblank(struct drm_device *dev, int crtc)
 {
-       unsigned int cur_vblank;
-       int ret = 0;
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 
-       /* Assume that the user has missed the current sequence number
-        * by about a day rather than she wants to wait for years
-        * using vertical blanks...
-        */
-       DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(&dev->vbl_received))
-                     - *sequence) <= (1 << 23)));
+       if (crtc != 0) {
+               DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                         crtc);
+               return 0;
+       }
 
-       *sequence = cur_vblank;
+       MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+       return 0;
+}
 
-       return ret;
+
+void mga_disable_vblank(struct drm_device *dev, int crtc)
+{
+       if (crtc != 0) {
+               DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
+                         crtc);
+       }
+
+       /* Do *NOT* disable the vertical refresh interrupt.  MGA doesn't have
+        * a nice hardware counter that tracks the number of refreshes when
+        * the interrupt is disabled, and the kernel doesn't know the refresh
+        * rate to calculate an estimate.
+        */
+       /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
 }
 
 int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
@@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
        MGA_WRITE(MGA_ICLEAR, ~0);
 }
 
-void mga_driver_irq_postinstall(struct drm_device * dev)
+int mga_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+       int ret;
+
+       ret = drm_vblank_init(dev, 1);
+       if (ret)
+               return ret;
 
        DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
 
-       /* Turn on vertical blank interrupt and soft trap interrupt. */
-       MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+       /* Turn on soft trap interrupt.  Vertical blank interrupts are enabled
+        * in mga_enable_vblank.
+        */
+       MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
+       return 0;
 }
 
 void mga_driver_irq_uninstall(struct drm_device * dev)
index d3f8aade07b336be0d6d37d2a1e09913669d5680..b710fab21cb375e946d19ec099a1c1c81208a72a 100644 (file)
@@ -1022,7 +1022,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil
 
        switch (param->param) {
        case MGA_PARAM_IRQ_NR:
-               value = dev->irq;
+               value = drm_dev_to_irq(dev);
                break;
        case MGA_PARAM_CARD_TYPE:
                value = dev_priv->chipset;
index 6108e7587e12470daba9576ef185458f5fc545c1..3265d53ba91f0d966fb4aadbe0645cab227cd0ef 100644 (file)
@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
 static struct drm_driver driver = {
        .driver_features =
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
-           DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
-           DRIVER_IRQ_VBL,
+           DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .dev_priv_size = sizeof(drm_r128_buf_priv_t),
        .preclose = r128_driver_preclose,
        .lastclose = r128_driver_lastclose,
-       .vblank_wait = r128_driver_vblank_wait,
+       .get_vblank_counter = r128_get_vblank_counter,
+       .enable_vblank = r128_enable_vblank,
+       .disable_vblank = r128_disable_vblank,
        .irq_preinstall = r128_driver_irq_preinstall,
        .irq_postinstall = r128_driver_irq_postinstall,
        .irq_uninstall = r128_driver_irq_uninstall,
@@ -59,21 +60,20 @@ static struct drm_driver driver = {
        .ioctls = r128_ioctls,
        .dma_ioctl = r128_cce_buffers,
        .fops = {
-                .owner = THIS_MODULE,
-                .open = drm_open,
-                .release = drm_release,
-                .ioctl = drm_ioctl,
-                .mmap = drm_mmap,
-                .poll = drm_poll,
-                .fasync = drm_fasync,
+               .owner = THIS_MODULE,
+               .open = drm_open,
+               .release = drm_release,
+               .ioctl = drm_ioctl,
+               .mmap = drm_mmap,
+               .poll = drm_poll,
+               .fasync = drm_fasync,
 #ifdef CONFIG_COMPAT
-                .compat_ioctl = r128_compat_ioctl,
+               .compat_ioctl = r128_compat_ioctl,
 #endif
        },
-
        .pci_driver = {
-                .name = DRIVER_NAME,
-                .id_table = pciidlist,
+               .name = DRIVER_NAME,
+               .id_table = pciidlist,
        },
 
        .name = DRIVER_NAME,
@@ -87,6 +87,7 @@ static struct drm_driver driver = {
 static int __init r128_init(void)
 {
        driver.num_ioctls = r128_max_ioctl;
+
        return drm_init(&driver);
 }
 
index 011105e51ac660117c88a1e1a3d9db860702b325..5898b274279d216cf0630fed63af2480a7a0ebb4 100644 (file)
@@ -29,7 +29,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Kevin E. Martin <martin@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
- *    Michel Dänzer <daenzerm@student.ethz.ch>
+ *    Michel D�zer <daenzerm@student.ethz.ch>
  */
 
 #ifndef __R128_DRV_H__
@@ -97,6 +97,8 @@ typedef struct drm_r128_private {
        u32 crtc_offset;
        u32 crtc_offset_cntl;
 
+       atomic_t vbl_received;
+
        u32 color_fmt;
        unsigned int front_offset;
        unsigned int front_pitch;
@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
 extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
 extern int r128_do_cleanup_cce(struct drm_device * dev);
 
-extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
-
+extern int r128_enable_vblank(struct drm_device *dev, int crtc);
+extern void r128_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
 extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
 extern void r128_driver_irq_preinstall(struct drm_device * dev);
-extern void r128_driver_irq_postinstall(struct drm_device * dev);
+extern int r128_driver_irq_postinstall(struct drm_device *dev);
 extern void r128_driver_irq_uninstall(struct drm_device * dev);
 extern void r128_driver_lastclose(struct drm_device * dev);
 extern void r128_driver_preclose(struct drm_device * dev,
index c76fdca7662d78bcdb0cb83684ce2c9005a471c2..d7349012a680b35a0b50091e2e6e5f3bf70d6004 100644 (file)
 #include "r128_drm.h"
 #include "r128_drv.h"
 
+u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+       const drm_r128_private_t *dev_priv = dev->dev_private;
+
+       if (crtc != 0)
+               return 0;
+
+       return atomic_read(&dev_priv->vbl_received);
+}
+
 irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
        /* VBLANK interrupt */
        if (status & R128_CRTC_VBLANK_INT) {
                R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
-               atomic_inc(&dev->vbl_received);
-               DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals(dev);
+               atomic_inc(&dev_priv->vbl_received);
+               drm_handle_vblank(dev, 0);
                return IRQ_HANDLED;
        }
        return IRQ_NONE;
 }
 
-int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int r128_enable_vblank(struct drm_device *dev, int crtc)
 {
-       unsigned int cur_vblank;
-       int ret = 0;
+       drm_r128_private_t *dev_priv = dev->dev_private;
 
-       /* Assume that the user has missed the current sequence number
-        * by about a day rather than she wants to wait for years
-        * using vertical blanks...
-        */
-       DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(&dev->vbl_received))
-                     - *sequence) <= (1 << 23)));
+       if (crtc != 0) {
+               DRM_ERROR("%s:  bad crtc %d\n", __func__, crtc);
+               return -EINVAL;
+       }
 
-       *sequence = cur_vblank;
+       R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
+       return 0;
+}
+
+void r128_disable_vblank(struct drm_device *dev, int crtc)
+{
+       if (crtc != 0)
+               DRM_ERROR("%s:  bad crtc %d\n", __func__, crtc);
 
-       return ret;
+       /*
+        * FIXME: implement proper interrupt disable by using the vblank
+        * counter register (if available)
+        *
+        * R128_WRITE(R128_GEN_INT_CNTL,
+        *            R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
+        */
 }
 
 void r128_driver_irq_preinstall(struct drm_device * dev)
@@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
        R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
 }
 
-void r128_driver_irq_postinstall(struct drm_device * dev)
+int r128_driver_irq_postinstall(struct drm_device *dev)
 {
-       drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
-
-       /* Turn on VBL interrupt */
-       R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
+       return drm_vblank_init(dev, 1);
 }
 
 void r128_driver_irq_uninstall(struct drm_device * dev)
index 51a9afce7b9b9b5e9a9a965fc8091078d3edca05..f7a5b5740764040840421e990c27e377a1efac31 100644 (file)
@@ -1629,7 +1629,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
 
        switch (param->param) {
        case R128_PARAM_IRQ_NR:
-               value = dev->irq;
+               value = drm_dev_to_irq(dev);
                break;
        default:
                return -EINVAL;
index 248ab4a7d39fdb42a1073f48cceca3ed237d28ce..59a2132a8f57a5e833b83011191de047dc9ec43e 100644 (file)
@@ -71,7 +71,8 @@ static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 
 static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 {
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                return RS690_READ_MCIND(dev_priv, addr);
        else
                return RS480_READ_MCIND(dev_priv, addr);
@@ -82,7 +83,8 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
 
        if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
                return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
-       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+       else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+                ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
@@ -94,7 +96,8 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
 {
        if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
                R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
-       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+       else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+                ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
@@ -106,7 +109,8 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo
 {
        if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
                R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
-       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+       else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+                ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
@@ -122,15 +126,17 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
        if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
                R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
                R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
-       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+                ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
                RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
                RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
        } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
                R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
                R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
-       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) {
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
                RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
-               RADEON_WRITE(RS480_AGP_BASE_2, 0);
+               RADEON_WRITE(RS480_AGP_BASE_2, agp_base_hi);
        } else {
                RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
                if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
@@ -347,6 +353,7 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
                DRM_INFO("Loading R300 Microcode\n");
                for (i = 0; i < 256; i++) {
@@ -356,6 +363,7 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
                                     R300_cp_microcode[i][0]);
                }
        } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R423) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
                DRM_INFO("Loading R400 Microcode\n");
                for (i = 0; i < 256; i++) {
@@ -364,8 +372,9 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
                        RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
                                     R420_cp_microcode[i][0]);
                }
-       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
-               DRM_INFO("Loading RS690 Microcode\n");
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
+               DRM_INFO("Loading RS690/RS740 Microcode\n");
                for (i = 0; i < 256; i++) {
                        RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
                                     RS690_cp_microcode[i][1]);
@@ -626,8 +635,6 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
                     dev_priv->ring.size_l2qw);
 #endif
 
-       /* Start with assuming that writeback doesn't work */
-       dev_priv->writeback_works = 0;
 
        /* Initialize the scratch register pointer.  This will cause
         * the scratch register values to be written out to memory
@@ -646,8 +653,18 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
        RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
 
        /* Turn on bus mastering */
-       tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
-       RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
+               /* rs400, rs690/rs740 */
+               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS400_BUS_MASTER_DIS;
+               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+       } else if (!(((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
+                   ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R423))) {
+               /* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
+               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+       } /* PCIE cards appears to not need this */
 
        dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
        RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
@@ -674,6 +691,9 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
 {
        u32 tmp;
 
+       /* Start with assuming that writeback doesn't work */
+       dev_priv->writeback_works = 0;
+
        /* Writeback doesn't seem to work everywhere, test it here and possibly
         * enable it if it appears to work
         */
@@ -719,7 +739,8 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
                          dev_priv->gart_size);
 
                temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
-               if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+               if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                        IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
                                                             RS690_BLOCK_GFX_D3_EN));
                else
@@ -812,6 +833,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
        u32 tmp;
 
        if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740) ||
            (dev_priv->flags & RADEON_IS_IGPGART)) {
                radeon_set_igpgart(dev_priv, on);
                return;
@@ -1286,7 +1308,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
        radeon_cp_init_ring_buffer(dev, dev_priv);
 
        radeon_do_engine_reset(dev);
-       radeon_enable_interrupt(dev);
+       radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
 
        DRM_DEBUG("radeon_do_resume_cp() complete\n");
 
@@ -1708,6 +1730,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
        case CHIP_R300:
        case CHIP_R350:
        case CHIP_R420:
+       case CHIP_R423:
        case CHIP_RV410:
        case CHIP_RV515:
        case CHIP_R520:
index 637bd7faf132093764351e938c24198cd50424ee..71af746a4e4760d24c7c36e1141882b43117137a 100644 (file)
@@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device *dev, char *buf)
                        "r300"));
 }
 
+static int radeon_suspend(struct drm_device *dev, pm_message_t state)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       /* Disable *all* interrupts */
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+               RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
+       RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
+       return 0;
+}
+
+static int radeon_resume(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       /* Restore interrupt registers */
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+               RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
+       RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+       return 0;
+}
+
 static struct pci_device_id pciidlist[] = {
        radeon_PCI_IDS
 };
@@ -59,8 +81,7 @@ static struct pci_device_id pciidlist[] = {
 static struct drm_driver driver = {
        .driver_features =
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
-           DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
-           DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
+           DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
        .dev_priv_size = sizeof(drm_radeon_buf_priv_t),
        .load = radeon_driver_load,
        .firstopen = radeon_driver_firstopen,
@@ -69,8 +90,11 @@ static struct drm_driver driver = {
        .postclose = radeon_driver_postclose,
        .lastclose = radeon_driver_lastclose,
        .unload = radeon_driver_unload,
-       .vblank_wait = radeon_driver_vblank_wait,
-       .vblank_wait2 = radeon_driver_vblank_wait2,
+       .suspend = radeon_suspend,
+       .resume = radeon_resume,
+       .get_vblank_counter = radeon_get_vblank_counter,
+       .enable_vblank = radeon_enable_vblank,
+       .disable_vblank = radeon_disable_vblank,
        .dri_library_name = dri_library_name,
        .irq_preinstall = radeon_driver_irq_preinstall,
        .irq_postinstall = radeon_driver_irq_postinstall,
index 0993816931751234fd2705ad4158f61a055faf24..4dbb813910c3f85060bd956998d7a3a85a63a0b6 100644 (file)
@@ -122,9 +122,12 @@ enum radeon_family {
        CHIP_RV350,
        CHIP_RV380,
        CHIP_R420,
+       CHIP_R423,
        CHIP_RV410,
+       CHIP_RS400,
        CHIP_RS480,
        CHIP_RS690,
+       CHIP_RS740,
        CHIP_RV515,
        CHIP_R520,
        CHIP_RV530,
@@ -378,17 +381,17 @@ extern void radeon_mem_release(struct drm_file *file_priv,
                               struct mem_block *heap);
 
                                /* radeon_irq.c */
+extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
 extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
 
 extern void radeon_do_release(struct drm_device * dev);
-extern int radeon_driver_vblank_wait(struct drm_device * dev,
-                                    unsigned int *sequence);
-extern int radeon_driver_vblank_wait2(struct drm_device * dev,
-                                     unsigned int *sequence);
+extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
+extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
+extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
 extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
 extern void radeon_driver_irq_preinstall(struct drm_device * dev);
-extern void radeon_driver_irq_postinstall(struct drm_device * dev);
+extern int radeon_driver_irq_postinstall(struct drm_device *dev);
 extern void radeon_driver_irq_uninstall(struct drm_device * dev);
 extern void radeon_enable_interrupt(struct drm_device *dev);
 extern int radeon_vblank_crtc_get(struct drm_device *dev);
@@ -397,19 +400,22 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
 extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
 extern int radeon_driver_unload(struct drm_device *dev);
 extern int radeon_driver_firstopen(struct drm_device *dev);
-extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv);
-extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp);
+extern void radeon_driver_preclose(struct drm_device *dev,
+                                  struct drm_file *file_priv);
+extern void radeon_driver_postclose(struct drm_device *dev,
+                                   struct drm_file *file_priv);
 extern void radeon_driver_lastclose(struct drm_device * dev);
-extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
+extern int radeon_driver_open(struct drm_device *dev,
+                             struct drm_file *file_priv);
 extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
                                unsigned long arg);
 
 /* r300_cmdbuf.c */
 extern void r300_init_reg_flags(struct drm_device *dev);
 
-extern int r300_do_cp_cmdbuf(struct drm_device * dev,
+extern int r300_do_cp_cmdbuf(struct drm_device *dev,
                             struct drm_file *file_priv,
-                            drm_radeon_kcmd_buffer_t * cmdbuf);
+                            drm_radeon_kcmd_buffer_t *cmdbuf);
 
 /* Flags for stats.boxes
  */
@@ -434,8 +440,31 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 #      define RADEON_SCISSOR_1_ENABLE          (1 << 29)
 #      define RADEON_SCISSOR_2_ENABLE          (1 << 30)
 
+/*
+ * PCIE radeons (rv370/rv380, rv410, r423/r430/r480, r5xx)
+ * don't have an explicit bus mastering disable bit.  It's handled
+ * by the PCI D-states.  PMI_BM_DIS disables D-state bus master
+ * handling, not bus mastering itself.
+ */
 #define RADEON_BUS_CNTL                        0x0030
+/* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
 #      define RADEON_BUS_MASTER_DIS            (1 << 6)
+/* rs400, rs690/rs740 */
+#      define RS400_BUS_MASTER_DIS             (1 << 14)
+#      define RS400_MSI_REARM                  (1 << 20)
+/* see RS480_MSI_REARM in AIC_CNTL for rs480 */
+
+#define RADEON_BUS_CNTL1               0x0034
+#      define RADEON_PMI_BM_DIS                (1 << 2)
+#      define RADEON_PMI_INT_DIS               (1 << 3)
+
+#define RV370_BUS_CNTL                 0x004c
+#      define RV370_PMI_BM_DIS                 (1 << 5)
+#      define RV370_PMI_INT_DIS                (1 << 6)
+
+#define RADEON_MSI_REARM_EN            0x0160
+/* rv370/rv380, rv410, r423/r430/r480, r5xx */
+#      define RV370_MSI_REARM_EN               (1 << 0)
 
 #define RADEON_CLOCK_CNTL_DATA         0x000c
 #      define RADEON_PLL_WR_EN                 (1 << 7)
@@ -623,6 +652,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 #      define RADEON_SW_INT_TEST               (1 << 25)
 #      define RADEON_SW_INT_TEST_ACK           (1 << 25)
 #      define RADEON_SW_INT_FIRE               (1 << 26)
+#       define R500_DISPLAY_INT_STATUS          (1 << 0)
 
 #define RADEON_HOST_PATH_CNTL          0x0130
 #      define RADEON_HDP_SOFT_RESET            (1 << 26)
@@ -907,6 +937,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 
 #define RADEON_AIC_CNTL                        0x01d0
 #      define RADEON_PCIGART_TRANSLATE_EN      (1 << 0)
+#      define RS480_MSI_REARM                  (1 << 3)
 #define RADEON_AIC_STAT                        0x01d4
 #define RADEON_AIC_PT_BASE             0x01d8
 #define RADEON_AIC_LO_ADDR             0x01dc
@@ -1116,6 +1147,9 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
 
 #define R200_VAP_PVS_CNTL_1               0x22D0
 
+#define RADEON_CRTC_CRNT_FRAME 0x0214
+#define RADEON_CRTC2_CRNT_FRAME 0x0314
+
 #define R500_D1CRTC_STATUS 0x609c
 #define R500_D2CRTC_STATUS 0x689c
 #define R500_CRTC_V_BLANK (1<<0)
@@ -1200,7 +1234,8 @@ do {                                                              \
 
 #define IGP_WRITE_MCIND(addr, val)                             \
 do {                                                                   \
-       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)       \
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||   \
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))      \
                RS690_WRITE_MCIND(addr, val);                           \
        else                                                            \
                RS480_WRITE_MCIND(addr, val);                           \
index ee40d197deb7e8f2f7d6568e4c3b51e376c81ca7..5079f7054a2f67aa712bcf6c89fa4e98cb1835b9 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Authors:
  *    Keith Whitwell <keith@tungstengraphics.com>
- *    Michel Dänzer <michel@daenzer.net>
+ *    Michel D�zer <michel@daenzer.net>
  */
 
 #include "drmP.h"
 #include "radeon_drm.h"
 #include "radeon_drv.h"
 
-static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
-                                             u32 mask)
+void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
 {
-       u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if (state)
+               dev_priv->irq_enable_reg |= mask;
+       else
+               dev_priv->irq_enable_reg &= ~mask;
+
+       RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+}
+
+static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if (state)
+               dev_priv->r500_disp_irq_reg |= mask;
+       else
+               dev_priv->r500_disp_irq_reg &= ~mask;
+
+       RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
+}
+
+int radeon_enable_vblank(struct drm_device *dev, int crtc)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               switch (crtc) {
+               case 0:
+                       r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
+                       break;
+               case 1:
+                       r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       return EINVAL;
+               }
+       } else {
+               switch (crtc) {
+               case 0:
+                       radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
+                       break;
+               case 1:
+                       radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       return EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+void radeon_disable_vblank(struct drm_device *dev, int crtc)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               switch (crtc) {
+               case 0:
+                       r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
+                       break;
+               case 1:
+                       r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       break;
+               }
+       } else {
+               switch (crtc) {
+               case 0:
+                       radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
+                       break;
+               case 1:
+                       radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       break;
+               }
+       }
+}
+
+static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int)
+{
+       u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS);
+       u32 irq_mask = RADEON_SW_INT_TEST;
+
+       *r500_disp_int = 0;
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               /* vbl interrupts in a different place */
+
+               if (irqs & R500_DISPLAY_INT_STATUS) {
+                       /* if a display interrupt */
+                       u32 disp_irq;
+
+                       disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS);
+
+                       *r500_disp_int = disp_irq;
+                       if (disp_irq & R500_D1_VBLANK_INTERRUPT)
+                               RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK);
+                       if (disp_irq & R500_D2_VBLANK_INTERRUPT)
+                               RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK);
+               }
+               irq_mask |= R500_DISPLAY_INT_STATUS;
+       } else
+               irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT;
+
+       irqs &= irq_mask;
+
        if (irqs)
                RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
+
        return irqs;
 }
 
@@ -68,44 +184,33 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
        drm_radeon_private_t *dev_priv =
            (drm_radeon_private_t *) dev->dev_private;
        u32 stat;
+       u32 r500_disp_int;
 
        /* Only consider the bits we're interested in - others could be used
         * outside the DRM
         */
-       stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
-                                                 RADEON_CRTC_VBLANK_STAT |
-                                                 RADEON_CRTC2_VBLANK_STAT));
+       stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
        if (!stat)
                return IRQ_NONE;
 
        stat &= dev_priv->irq_enable_reg;
 
        /* SW interrupt */
-       if (stat & RADEON_SW_INT_TEST) {
+       if (stat & RADEON_SW_INT_TEST)
                DRM_WAKEUP(&dev_priv->swi_queue);
-       }
 
        /* VBLANK interrupt */
-       if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
-               int vblank_crtc = dev_priv->vblank_crtc;
-
-               if ((vblank_crtc &
-                    (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
-                   (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
-                       if (stat & RADEON_CRTC_VBLANK_STAT)
-                               atomic_inc(&dev->vbl_received);
-                       if (stat & RADEON_CRTC2_VBLANK_STAT)
-                               atomic_inc(&dev->vbl_received2);
-               } else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
-                          (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
-                          ((stat & RADEON_CRTC2_VBLANK_STAT) &&
-                           (vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
-                       atomic_inc(&dev->vbl_received);
-
-               DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals(dev);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
+                       drm_handle_vblank(dev, 0);
+               if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
+                       drm_handle_vblank(dev, 1);
+       } else {
+               if (stat & RADEON_CRTC_VBLANK_STAT)
+                       drm_handle_vblank(dev, 0);
+               if (stat & RADEON_CRTC2_VBLANK_STAT)
+                       drm_handle_vblank(dev, 1);
        }
-
        return IRQ_HANDLED;
 }
 
@@ -144,54 +249,31 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
        return ret;
 }
 
-static int radeon_driver_vblank_do_wait(struct drm_device * dev,
-                                       unsigned int *sequence, int crtc)
+u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
 {
-       drm_radeon_private_t *dev_priv =
-           (drm_radeon_private_t *) dev->dev_private;
-       unsigned int cur_vblank;
-       int ret = 0;
-       int ack = 0;
-       atomic_t *counter;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
 
-       if (crtc == DRM_RADEON_VBLANK_CRTC1) {
-               counter = &dev->vbl_received;
-               ack |= RADEON_CRTC_VBLANK_STAT;
-       } else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
-               counter = &dev->vbl_received2;
-               ack |= RADEON_CRTC2_VBLANK_STAT;
-       } else
+       if (crtc < 0 || crtc > 1) {
+               DRM_ERROR("Invalid crtc %d\n", crtc);
                return -EINVAL;
+       }
 
-       radeon_acknowledge_irqs(dev_priv, ack);
-
-       dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
-       /* Assume that the user has missed the current sequence number
-        * by about a day rather than she wants to wait for years
-        * using vertical blanks...
-        */
-       DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(counter))
-                     - *sequence) <= (1 << 23)));
-
-       *sequence = cur_vblank;
-
-       return ret;
-}
-
-int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
-{
-       return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
-}
-
-int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
-{
-       return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               if (crtc == 0)
+                       return RADEON_READ(R500_D1CRTC_FRAME_COUNT);
+               else
+                       return RADEON_READ(R500_D2CRTC_FRAME_COUNT);
+       } else {
+               if (crtc == 0)
+                       return RADEON_READ(RADEON_CRTC_CRNT_FRAME);
+               else
+                       return RADEON_READ(RADEON_CRTC2_CRNT_FRAME);
+       }
 }
 
 /* Needs the lock as it touches the ring.
@@ -234,46 +316,41 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
        return radeon_wait_irq(dev, irqwait->irq_seq);
 }
 
-void radeon_enable_interrupt(struct drm_device *dev)
-{
-       drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
-
-       dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
-       if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
-               dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
-
-       if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
-               dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
-
-       RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
-       dev_priv->irq_enabled = 1;
-}
-
 /* drm_dma.h hooks
 */
 void radeon_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_radeon_private_t *dev_priv =
            (drm_radeon_private_t *) dev->dev_private;
+       u32 dummy;
 
        /* Disable *all* interrupts */
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+               RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
 
        /* Clear bits if they're already high */
-       radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
-                                          RADEON_CRTC_VBLANK_STAT |
-                                          RADEON_CRTC2_VBLANK_STAT));
+       radeon_acknowledge_irqs(dev_priv, &dummy);
 }
 
-void radeon_driver_irq_postinstall(struct drm_device * dev)
+int radeon_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv =
            (drm_radeon_private_t *) dev->dev_private;
+       int ret;
 
        atomic_set(&dev_priv->swi_emitted, 0);
        DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
 
-       radeon_enable_interrupt(dev);
+       ret = drm_vblank_init(dev, 2);
+       if (ret)
+               return ret;
+
+       dev->max_vblank_count = 0x001fffff;
+
+       radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
+
+       return 0;
 }
 
 void radeon_driver_irq_uninstall(struct drm_device * dev)
@@ -285,6 +362,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
 
        dev_priv->irq_enabled = 0;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+               RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        /* Disable *all* interrupts */
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
 }
@@ -293,18 +372,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
 int radeon_vblank_crtc_get(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
-       u32 flag;
-       u32 value;
-
-       flag = RADEON_READ(RADEON_GEN_INT_CNTL);
-       value = 0;
-
-       if (flag & RADEON_CRTC_VBLANK_MASK)
-               value |= DRM_RADEON_VBLANK_CRTC1;
 
-       if (flag & RADEON_CRTC2_VBLANK_MASK)
-               value |= DRM_RADEON_VBLANK_CRTC2;
-       return value;
+       return dev_priv->vblank_crtc;
 }
 
 int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
@@ -315,6 +384,5 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
                return -EINVAL;
        }
        dev_priv->vblank_crtc = (unsigned int)value;
-       radeon_enable_interrupt(dev);
        return 0;
 }
index 11c146b49211de3581cbc2daaab9815af885cec9..5d7153fcc7b0063625a8232e66b6f89b09a042c3 100644 (file)
@@ -2997,7 +2997,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
                value = GET_SCRATCH(2);
                break;
        case RADEON_PARAM_IRQ_NR:
-               value = dev->irq;
+               value = drm_dev_to_irq(dev);
                break;
        case RADEON_PARAM_GART_BASE:
                value = dev_priv->gart_vm_start;
index b3878770fce13b64da9fa10dc190343a37c97800..af22111397d8cad6822cfa1b659c291ec885fa45 100644 (file)
@@ -41,7 +41,7 @@
 #define AGP_TYPE 1
 
 
-#if defined(CONFIG_FB_SIS)
+#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
 /* fb management via fb device */
 
 #define SIS_MM_ALIGN_SHIFT 0
@@ -57,7 +57,7 @@ static void *sis_sman_mm_allocate(void *private, unsigned long size,
        if (req.size == 0)
                return NULL;
        else
-               return (void *)~req.offset;
+               return (void *)(unsigned long)~req.offset;
 }
 
 static void sis_sman_mm_free(void *private, void *ref)
@@ -75,12 +75,12 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref)
        return ~((unsigned long)ref);
 }
 
-#else /* CONFIG_FB_SIS */
+#else /* CONFIG_FB_SIS[_MODULE] */
 
 #define SIS_MM_ALIGN_SHIFT 4
 #define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
 
-#endif /* CONFIG_FB_SIS */
+#endif /* CONFIG_FB_SIS[_MODULE] */
 
 static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
@@ -89,7 +89,7 @@ static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file
        int ret;
 
        mutex_lock(&dev->struct_mutex);
-#if defined(CONFIG_FB_SIS)
+#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
        {
                struct drm_sman_mm sman_mm;
                sman_mm.private = (void *)0xFFFFFFFF;
index 80c01cdfa37d54db94ec5a382f83ec4e6b026432..0993b441fc426c1f6e39b0c0ef5ec28c30660fde 100644 (file)
@@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = {
 static struct drm_driver driver = {
        .driver_features =
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
-           DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+           DRIVER_IRQ_SHARED,
        .load = via_driver_load,
        .unload = via_driver_unload,
        .context_dtor = via_final_context,
-       .vblank_wait = via_driver_vblank_wait,
+       .get_vblank_counter = via_get_vblank_counter,
+       .enable_vblank = via_enable_vblank,
+       .disable_vblank = via_disable_vblank,
        .irq_preinstall = via_driver_irq_preinstall,
        .irq_postinstall = via_driver_irq_postinstall,
        .irq_uninstall = via_driver_irq_uninstall,
@@ -59,17 +61,17 @@ static struct drm_driver driver = {
        .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = via_ioctls,
        .fops = {
-                .owner = THIS_MODULE,
-                .open = drm_open,
-                .release = drm_release,
-                .ioctl = drm_ioctl,
-                .mmap = drm_mmap,
-                .poll = drm_poll,
-                .fasync = drm_fasync,
-       },
+               .owner = THIS_MODULE,
+               .open = drm_open,
+               .release = drm_release,
+               .ioctl = drm_ioctl,
+               .mmap = drm_mmap,
+               .poll = drm_poll,
+               .fasync = drm_fasync,
+               },
        .pci_driver = {
-                .name = DRIVER_NAME,
-                .id_table = pciidlist,
+               .name = DRIVER_NAME,
+               .id_table = pciidlist,
        },
 
        .name = DRIVER_NAME,
index 2daae81874cdd049fdcd2ff9f0783eb15994fb53..cafcb844a2233879da8d8fb110658e963982b780 100644 (file)
@@ -75,6 +75,7 @@ typedef struct drm_via_private {
        struct timeval last_vblank;
        int last_vblank_valid;
        unsigned usec_per_vblank;
+       atomic_t vbl_received;
        drm_via_state_t hc_state;
        char pci_buf[VIA_PCI_BUF_SIZE];
        const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
@@ -130,21 +131,24 @@ extern int via_init_context(struct drm_device * dev, int context);
 extern int via_final_context(struct drm_device * dev, int context);
 
 extern int via_do_cleanup_map(struct drm_device * dev);
-extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
+extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
+extern int via_enable_vblank(struct drm_device *dev, int crtc);
+extern void via_disable_vblank(struct drm_device *dev, int crtc);
 
 extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
 extern void via_driver_irq_preinstall(struct drm_device * dev);
-extern void via_driver_irq_postinstall(struct drm_device * dev);
+extern int via_driver_irq_postinstall(struct drm_device *dev);
 extern void via_driver_irq_uninstall(struct drm_device * dev);
 
 extern int via_dma_cleanup(struct drm_device * dev);
 extern void via_init_command_verifier(void);
 extern int via_driver_dma_quiescent(struct drm_device * dev);
-extern void via_init_futex(drm_via_private_t * dev_priv);
-extern void via_cleanup_futex(drm_via_private_t * dev_priv);
-extern void via_release_futex(drm_via_private_t * dev_priv, int context);
+extern void via_init_futex(drm_via_private_t *dev_priv);
+extern void via_cleanup_futex(drm_via_private_t *dev_priv);
+extern void via_release_futex(drm_via_private_t *dev_priv, int context);
 
-extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv);
+extern void via_reclaim_buffers_locked(struct drm_device *dev,
+                                      struct drm_file *file_priv);
 extern void via_lastclose(struct drm_device *dev);
 
 extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
index c6bb978a110673821a3aa6db6e3cefd32bcc20ce..665d319b927b2d3a07cc25a65ebccbc33b1160aa 100644 (file)
@@ -43,7 +43,7 @@
 #define VIA_REG_INTERRUPT       0x200
 
 /* VIA_REG_INTERRUPT */
-#define VIA_IRQ_GLOBAL          (1 << 31)
+#define VIA_IRQ_GLOBAL   (1 << 31)
 #define VIA_IRQ_VBLANK_ENABLE   (1 << 19)
 #define VIA_IRQ_VBLANK_PENDING  (1 << 3)
 #define VIA_IRQ_HQV0_ENABLE     (1 << 11)
 
 static maskarray_t via_pro_group_a_irqs[] = {
        {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
-        0x00000000},
+        0x00000000 },
        {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
-        0x00000000},
+        0x00000000 },
        {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
         VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
        {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
         VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
 };
-static int via_num_pro_group_a =
-    sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
+static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
 static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
 
 static maskarray_t via_unichrome_irqs[] = {
@@ -86,14 +85,24 @@ static maskarray_t via_unichrome_irqs[] = {
        {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
         VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
 };
-static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t);
+static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
 static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
 
+
 static unsigned time_diff(struct timeval *now, struct timeval *then)
 {
        return (now->tv_usec >= then->tv_usec) ?
-           now->tv_usec - then->tv_usec :
-           1000000 - (then->tv_usec - now->tv_usec);
+               now->tv_usec - then->tv_usec :
+               1000000 - (then->tv_usec - now->tv_usec);
+}
+
+u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+       drm_via_private_t *dev_priv = dev->dev_private;
+       if (crtc != 0)
+               return 0;
+
+       return atomic_read(&dev_priv->vbl_received);
 }
 
 irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
@@ -108,23 +117,22 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
 
        status = VIA_READ(VIA_REG_INTERRUPT);
        if (status & VIA_IRQ_VBLANK_PENDING) {
-               atomic_inc(&dev->vbl_received);
-               if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
+               atomic_inc(&dev_priv->vbl_received);
+               if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
                        do_gettimeofday(&cur_vblank);
                        if (dev_priv->last_vblank_valid) {
                                dev_priv->usec_per_vblank =
-                                   time_diff(&cur_vblank,
-                                             &dev_priv->last_vblank) >> 4;
+                                       time_diff(&cur_vblank,
+                                                 &dev_priv->last_vblank) >> 4;
                        }
                        dev_priv->last_vblank = cur_vblank;
                        dev_priv->last_vblank_valid = 1;
                }
-               if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+               if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
                        DRM_DEBUG("US per vblank is: %u\n",
                                  dev_priv->usec_per_vblank);
                }
-               DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals(dev);
+               drm_handle_vblank(dev, 0);
                handled = 1;
        }
 
@@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
        /* Acknowlege interrupts */
        VIA_WRITE(VIA_REG_INTERRUPT, status);
 
+
        if (handled)
                return IRQ_HANDLED;
        else
@@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
        }
 }
 
-int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int via_enable_vblank(struct drm_device *dev, int crtc)
 {
-       drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
-       unsigned int cur_vblank;
-       int ret = 0;
+       drm_via_private_t *dev_priv = dev->dev_private;
+       u32 status;
 
-       DRM_DEBUG("\n");
-       if (!dev_priv) {
-               DRM_ERROR("called with no initialization\n");
+       if (crtc != 0) {
+               DRM_ERROR("%s:  bad crtc %d\n", __func__, crtc);
                return -EINVAL;
        }
 
-       viadrv_acknowledge_irqs(dev_priv);
+       status = VIA_READ(VIA_REG_INTERRUPT);
+       VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
+
+       VIA_WRITE8(0x83d4, 0x11);
+       VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
 
-       /* Assume that the user has missed the current sequence number
-        * by about a day rather than she wants to wait for years
-        * using vertical blanks...
-        */
+       return 0;
+}
+
+void via_disable_vblank(struct drm_device *dev, int crtc)
+{
+       drm_via_private_t *dev_priv = dev->dev_private;
 
-       DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(&dev->vbl_received)) -
-                     *sequence) <= (1 << 23)));
+       VIA_WRITE8(0x83d4, 0x11);
+       VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
 
-       *sequence = cur_vblank;
-       return ret;
+       if (crtc != 0)
+               DRM_ERROR("%s:  bad crtc %d\n", __func__, crtc);
 }
 
 static int
@@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
        return ret;
 }
 
+
 /*
  * drm_dma.h hooks
  */
@@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev)
        }
 }
 
-void via_driver_irq_postinstall(struct drm_device * dev)
+int via_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        u32 status;
 
-       DRM_DEBUG("\n");
-       if (dev_priv) {
-               status = VIA_READ(VIA_REG_INTERRUPT);
-               VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
-                         | dev_priv->irq_enable_mask);
+       DRM_DEBUG("via_driver_irq_postinstall\n");
+       if (!dev_priv)
+               return -EINVAL;
 
-               /* Some magic, oh for some data sheets ! */
+       drm_vblank_init(dev, 1);
+       status = VIA_READ(VIA_REG_INTERRUPT);
+       VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
+                 | dev_priv->irq_enable_mask);
 
-               VIA_WRITE8(0x83d4, 0x11);
-               VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
+       /* Some magic, oh for some data sheets ! */
+       VIA_WRITE8(0x83d4, 0x11);
+       VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
 
-       }
+       return 0;
 }
 
 void via_driver_irq_uninstall(struct drm_device * dev)
@@ -339,9 +354,6 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
        drm_via_irq_t *cur_irq = dev_priv->via_irqs;
        int force_sequence;
 
-       if (!dev->irq)
-               return -EINVAL;
-
        if (irqwait->request.irq >= dev_priv->num_irqs) {
                DRM_ERROR("Trying to wait on unknown irq %d\n",
                          irqwait->request.irq);
@@ -352,7 +364,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
        case VIA_IRQ_RELATIVE:
-               irqwait->request.sequence += atomic_read(&cur_irq->irq_received);
+               irqwait->request.sequence +=
+                       atomic_read(&cur_irq->irq_received);
                irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
        case VIA_IRQ_ABSOLUTE:
                break;
index e64094916e4fcf3f26b6482702c218a55583ec7f..f694cb5ededca2ccfc74bd712b60a0cd06248bce 100644 (file)
@@ -93,8 +93,7 @@ int via_final_context(struct drm_device *dev, int context)
        /* Last context, perform cleanup */
        if (dev->ctx_count == 1 && dev->dev_private) {
                DRM_DEBUG("Last Context\n");
-               if (dev->irq)
-                       drm_irq_uninstall(dev);
+               drm_irq_uninstall(dev);
                via_cleanup_futex(dev_priv);
                via_do_cleanup_map(dev);
        }
index 227642b044ae6b35f43aa902531911dc81ef1fa5..a8878244bb3c40432fe6b3420e32e338ae32f0ad 100644 (file)
@@ -3481,7 +3481,9 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
                                        }
                                        ctrlVal = 0;
                                        for (k = 0; k < state->MXL_Ctrl[i].size; k++)
-                                               ctrlVal += state->MXL_Ctrl[i].val[k] * (1 << k);
+                                               ctrlVal += state->
+                                                       MXL_Ctrl[i].val[k] *
+                                                       (1 << k);
                                } else
                                        return -1;
                        }
@@ -3581,7 +3583,7 @@ static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
 
 static u32 MXL_Ceiling(u32 value, u32 resolution)
 {
-       return (value/resolution + (value % resolution > 0 ? 1 : 0));
+       return value / resolution + (value % resolution > 0 ? 1 : 0);
 }
 
 /* Retrieve the Initialzation Registers */
@@ -3910,7 +3912,10 @@ static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
 
 static int mxl5005s_init(struct dvb_frontend *fe)
 {
+       struct mxl5005s_state *state = fe->tuner_priv;
+
        dprintk(1, "%s()\n", __func__);
+       state->current_mode = MXL_QAM;
        return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
 }
 
@@ -4092,7 +4097,6 @@ struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
        state->frontend = fe;
        state->config = config;
        state->i2c = i2c;
-       state->current_mode = MXL_QAM;
 
        printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n",
                config->i2c_address);
index 2a1aac1cc7552d33ec72e55073d873d72e323ce7..fb3f3b3adaba27c9fb2b1244f99914122f7c7364 100644 (file)
@@ -493,6 +493,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
        case TUNER_PHILIPS_FM1216ME_MK3:
        case TUNER_PHILIPS_FM1236_MK3:
        case TUNER_PHILIPS_FMD1216ME_MK3:
+       case TUNER_PHILIPS_FMD1216MEX_MK3:
        case TUNER_LG_NTSC_TAPE:
        case TUNER_PHILIPS_FM1256_IH3:
        case TUNER_TCL_MF02GIP_5N:
@@ -767,6 +768,7 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
 
        switch (priv->type) {
        case TUNER_PHILIPS_FMD1216ME_MK3:
+       case TUNER_PHILIPS_FMD1216MEX_MK3:
                if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
                    params->frequency >= 158870000)
                        buf[3] |= 0x08;
index 04961a1f44be66145f929dbc1f5cb2599371c41e..7c0bc064c008966b05316c842657dec7ae0972c7 100644 (file)
@@ -946,7 +946,7 @@ static struct tuner_params tuner_tena_9533_di_params[] = {
        },
 };
 
-/* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */
+/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
        { 16 * 160.00 /*MHz*/, 0x86, 0x51, },
@@ -984,6 +984,27 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
        },
 };
 
+static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
+               .has_tda9887 = 1,
+               .port1_active = 1,
+               .port2_active = 1,
+               .port2_fm_high_sensitivity = 1,
+               .port2_invert_for_secam_lc = 1,
+               .port1_set_for_fm_mono = 1,
+               .radio_if = 1,
+               .fm_gain_normal = 1,
+       },
+       {
+               .type   = TUNER_PARAM_TYPE_DIGITAL,
+               .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
+               .count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
+               .iffreq = 16 * 36.125, /*MHz*/
+       },
+};
 
 /* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
 
@@ -1663,6 +1684,16 @@ struct tunertype tuners[] = {
                .params = tuner_tcl_mf02gip_5n_params,
                .count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
        },
+       [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */
+               .name   = "Philips FMD1216MEX MK3 Hybrid Tuner",
+               .params = tuner_philips_fmd1216mex_mk3_params,
+               .count  = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params),
+               .min = 16 *  50.87,
+               .max = 16 * 858.00,
+               .stepsize = 166667,
+               .initdata = tua603x_agc112,
+               .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index f9c2bb917f54b5fe701268e527464491d2b19784..e12d13e0cbe9744b790c3b1089ac485aced7a2a8 100644 (file)
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
 static DEFINE_MUTEX(xc5000_list_mutex);
 static LIST_HEAD(hybrid_tuner_instance_list);
 
-#define dprintk(level,fmt, arg...) if (debug >= level) \
+#define dprintk(level, fmt, arg...) if (debug >= level) \
        printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
 #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
@@ -138,11 +138,11 @@ struct xc5000_priv {
    immediately the length of the following transaction.
 
 */
-typedef struct {
+struct XC_TV_STANDARD {
        char *Name;
        u16 AudioMode;
        u16 VideoMode;
-} XC_TV_STANDARD;
+};
 
 /* Tuner standards */
 #define MN_NTSC_PAL_BTSC       0
@@ -169,7 +169,7 @@ typedef struct {
 #define FM_Radio_INPUT2        21
 #define FM_Radio_INPUT1        22
 
-static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
        {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
        {"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
        {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
@@ -183,7 +183,7 @@ static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
        {"D/K-PAL-NICAM",     0x0E80, 0x8009},
        {"D/K-PAL-MONO",      0x1478, 0x8009},
        {"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
-       {"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
+       {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
        {"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
        {"L-SECAM-NICAM",     0x8E82, 0x0009},
        {"L'-SECAM-NICAM",    0x8E82, 0x4009},
@@ -307,9 +307,10 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
        unsigned int len, pos, index;
        u8 buf[XC_MAX_I2C_WRITE_LENGTH];
 
-       index=0;
-       while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
-               len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
+       index = 0;
+       while ((i2c_sequence[index] != 0xFF) ||
+               (i2c_sequence[index + 1] != 0xFF)) {
+               len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
                if (len == 0x0000) {
                        /* RESET command */
                        result = xc_reset(fe);
@@ -329,15 +330,17 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
                        buf[1] = i2c_sequence[index + 1];
                        pos = 2;
                        while (pos < len) {
-                               if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
-                                       nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
-                               } else {
+                               if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+                                       nbytes_to_send =
+                                               XC_MAX_I2C_WRITE_LENGTH;
+                               else
                                        nbytes_to_send = (len - pos + 2);
+                               for (i = 2; i < nbytes_to_send; i++) {
+                                       buf[i] = i2c_sequence[index + pos +
+                                               i - 2];
                                }
-                               for (i=2; i<nbytes_to_send; i++) {
-                                       buf[i] = i2c_sequence[index + pos + i - 2];
-                               }
-                               result = xc_send_i2c_data(priv, buf, nbytes_to_send);
+                               result = xc_send_i2c_data(priv, buf,
+                                       nbytes_to_send);
 
                                if (result != XC_RESULT_SUCCESS)
                                        return result;
@@ -386,8 +389,7 @@ static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
        dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
                rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
 
-       if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
-       {
+       if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
                rf_mode = XC_RF_MODE_CABLE;
                printk(KERN_ERR
                        "%s(), Invalid mode, defaulting to CABLE",
@@ -560,13 +562,13 @@ static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
                .flags = I2C_M_RD, .buf = buf, .len = len };
 
        if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-               printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
+               printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
                return -EREMOTEIO;
        }
        return 0;
 }
 
-static int xc5000_fwupload(struct dvb_frontendfe)
+static int xc5000_fwupload(struct dvb_frontend *fe)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
        const struct firmware *fw;
@@ -576,7 +578,8 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
        printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
                XC5000_DEFAULT_FIRMWARE);
 
-       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
+       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
+               &priv->i2c_props.adap->dev);
        if (ret) {
                printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
                ret = XC_RESULT_RESET_FAILURE;
@@ -592,7 +595,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
                ret = XC_RESULT_RESET_FAILURE;
        } else {
                printk(KERN_INFO "xc5000: firmware upload\n");
-               ret = xc_load_i2c_sequence(fe,  fw->data );
+               ret = xc_load_i2c_sequence(fe,  fw->data);
        }
 
 out:
@@ -651,7 +654,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
 
        dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
 
-       switch(params->u.vsb.modulation) {
+       switch (params->u.vsb.modulation) {
        case VSB_8:
        case VSB_16:
                dprintk(1, "%s() VSB modulation\n", __func__);
@@ -748,42 +751,42 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
        /* FIX ME: Some video standards may have several possible audio
                   standards. We simply default to one of them here.
         */
-       if(params->std & V4L2_STD_MN) {
+       if (params->std & V4L2_STD_MN) {
                /* default to BTSC audio standard */
                priv->video_standard = MN_NTSC_PAL_BTSC;
                goto tune_channel;
        }
 
-       if(params->std & V4L2_STD_PAL_BG) {
+       if (params->std & V4L2_STD_PAL_BG) {
                /* default to NICAM audio standard */
                priv->video_standard = BG_PAL_NICAM;
                goto tune_channel;
        }
 
-       if(params->std & V4L2_STD_PAL_I) {
+       if (params->std & V4L2_STD_PAL_I) {
                /* default to NICAM audio standard */
                priv->video_standard = I_PAL_NICAM;
                goto tune_channel;
        }
 
-       if(params->std & V4L2_STD_PAL_DK) {
+       if (params->std & V4L2_STD_PAL_DK) {
                /* default to NICAM audio standard */
                priv->video_standard = DK_PAL_NICAM;
                goto tune_channel;
        }
 
-       if(params->std & V4L2_STD_SECAM_DK) {
+       if (params->std & V4L2_STD_SECAM_DK) {
                /* default to A2 DK1 audio standard */
                priv->video_standard = DK_SECAM_A2DK1;
                goto tune_channel;
        }
 
-       if(params->std & V4L2_STD_SECAM_L) {
+       if (params->std & V4L2_STD_SECAM_L) {
                priv->video_standard = L_SECAM_NICAM;
                goto tune_channel;
        }
 
-       if(params->std & V4L2_STD_SECAM_LC) {
+       if (params->std & V4L2_STD_SECAM_LC) {
                priv->video_standard = LC_SECAM_NICAM;
                goto tune_channel;
        }
@@ -791,7 +794,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
 tune_channel:
        ret = xc_SetSignalSource(priv, priv->rf_mode);
        if (ret != XC_RESULT_SUCCESS) {
-       printk(KERN_ERR
+               printk(KERN_ERR
                        "xc5000: xc_SetSignalSource(%d) failed\n",
                        priv->rf_mode);
                return -EREMOTEIO;
@@ -863,7 +866,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
         * I2C transactions until calibration is complete.  This way we
         * don't have to rely on clock stretching working.
         */
-       xc_wait( 100 );
+       xc_wait(100);
 
        /* Default to "CABLE" mode */
        ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
@@ -885,15 +888,13 @@ static int xc5000_sleep(struct dvb_frontend *fe)
         */
 
        ret = xc_shutdown(priv);
-       if(ret != XC_RESULT_SUCCESS) {
+       if (ret != XC_RESULT_SUCCESS) {
                printk(KERN_ERR
                        "xc5000: %s() unable to shutdown tuner\n",
                        __func__);
                return -EREMOTEIO;
-       }
-       else {
+       } else
                return XC_RESULT_SUCCESS;
-       }
 }
 
 static int xc5000_init(struct dvb_frontend *fe)
@@ -989,7 +990,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
        if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
                goto fail;
 
-       switch(id) {
+       switch (id) {
        case XC_PRODUCT_ID_FW_LOADED:
                printk(KERN_INFO
                        "xc5000: Successfully identified at address 0x%02x\n",
index cf1a558e0e7f73c40cd8525f559563496bcef82f..f4c146698a0054783880fc931128a5fa6b492a34 100644 (file)
@@ -45,17 +45,17 @@ struct xc5000_config {
 
 #if defined(CONFIG_MEDIA_TUNER_XC5000) || \
     (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
-extern struct dvb_frontendxc5000_attach(struct dvb_frontend *fe,
+extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                                          struct i2c_adapter *i2c,
                                          struct xc5000_config *cfg);
 #else
-static inline struct dvb_frontendxc5000_attach(struct dvb_frontend *fe,
+static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                                                 struct i2c_adapter *i2c,
                                                 struct xc5000_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-#endif // CONFIG_MEDIA_TUNER_XC5000
+#endif
 
-#endif // __XC5000_H__
+#endif
index f7321448b4b1f2b14f3b0f3d6834b4199c7e350d..14e627ef6465f28dc88fc07bd5bd6c5c8e1e40af 100644 (file)
@@ -595,6 +595,18 @@ static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
        dm1105dvb_dma_unmap(dm1105dvb);
 }
 
+static struct stv0299_config sharp_z0194a_config = {
+       .demod_address = 0x68,
+       .inittab = sharp_z0194a_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .lock_output = STV0299_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
 static struct stv0288_config earda_config = {
        .demod_address = 0x68,
        .min_delay_ms = 100,
index f170e822fadce9016eeba24330d23101cbb01927..5689d1f1d44477bed202709e676041105b9b10ca 100644 (file)
@@ -47,6 +47,7 @@ static int dvb_shutdown_timeout;
 static int dvb_force_auto_inversion;
 static int dvb_override_tune_delay;
 static int dvb_powerdown_on_sleep = 1;
+static int dvb_mfe_wait_time = 5;
 
 module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
 MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
@@ -58,6 +59,8 @@ module_param(dvb_override_tune_delay, int, 0644);
 MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
 module_param(dvb_powerdown_on_sleep, int, 0644);
 MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
+module_param(dvb_mfe_wait_time, int, 0644);
+MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
 
 #define dprintk if (dvb_frontend_debug) printk
 
@@ -212,8 +215,9 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
 
 static void dvb_frontend_init(struct dvb_frontend *fe)
 {
-       dprintk ("DVB: initialising frontend %i (%s)...\n",
+       dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
                 fe->dvb->num,
+                fe->id,
                 fe->ops.info.name);
 
        if (fe->ops.init)
@@ -686,7 +690,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
        mb();
 
        fe_thread = kthread_run(dvb_frontend_thread, fe,
-               "kdvb-fe-%i", fe->dvb->num);
+               "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
        if (IS_ERR(fe_thread)) {
                ret = PTR_ERR(fe_thread);
                printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
@@ -710,8 +714,8 @@ static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
                *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
 
        if (*freq_min == 0 || *freq_max == 0)
-               printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
-                      fe->dvb->num);
+               printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
+                      fe->dvb->num,fe->id);
 }
 
 static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
@@ -724,8 +728,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
        dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
        if ((freq_min && parms->frequency < freq_min) ||
            (freq_max && parms->frequency > freq_max)) {
-               printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
-                      fe->dvb->num, parms->frequency, freq_min, freq_max);
+               printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
+                      fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
                return -EINVAL;
        }
 
@@ -735,8 +739,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
                     parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
                    (fe->ops.info.symbol_rate_max &&
                     parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
-                       printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
-                              fe->dvb->num, parms->u.qpsk.symbol_rate,
+                       printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+                              fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
                               fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
                        return -EINVAL;
                }
@@ -746,8 +750,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
                     parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
                    (fe->ops.info.symbol_rate_max &&
                     parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
-                       printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
-                              fe->dvb->num, parms->u.qam.symbol_rate,
+                       printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+                              fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
                               fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
                        return -EINVAL;
                }
@@ -899,30 +903,30 @@ void dtv_property_dump(struct dtv_property *tvp)
        int i;
 
        if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
-               printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n",
+               printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
                        __func__, tvp->cmd);
                return;
        }
 
-       printk("%s() tvp.cmd    = 0x%08x (%s)\n"
-               ,__FUNCTION__
+       dprintk("%s() tvp.cmd    = 0x%08x (%s)\n"
+               ,__func__
                ,tvp->cmd
                ,dtv_cmds[ tvp->cmd ].name);
 
        if(dtv_cmds[ tvp->cmd ].buffer) {
 
-               printk("%s() tvp.u.buffer.len = 0x%02x\n"
-                       ,__FUNCTION__
+               dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
+                       ,__func__
                        ,tvp->u.buffer.len);
 
                for(i = 0; i < tvp->u.buffer.len; i++)
-                       printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
-                               ,__FUNCTION__
+                       dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+                               ,__func__
                                ,i
                                ,tvp->u.buffer.data[i]);
 
        } else
-               printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+               dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
 }
 
 int is_legacy_delivery_system(fe_delivery_system_t s)
@@ -942,8 +946,6 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-       printk("%s()\n", __FUNCTION__);
-
        c->frequency = p->frequency;
        c->inversion = p->inversion;
 
@@ -998,27 +1000,25 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        struct dvb_frontend_parameters *p = &fepriv->parameters;
 
-       printk("%s()\n", __FUNCTION__);
-
        p->frequency = c->frequency;
        p->inversion = c->inversion;
 
        switch (fe->ops.info.type) {
        case FE_QPSK:
-               printk("%s() Preparing QPSK req\n", __FUNCTION__);
+               dprintk("%s() Preparing QPSK req\n", __func__);
                p->u.qpsk.symbol_rate = c->symbol_rate;
                p->u.qpsk.fec_inner = c->fec_inner;
                c->delivery_system = SYS_DVBS;
                break;
        case FE_QAM:
-               printk("%s() Preparing QAM req\n", __FUNCTION__);
+               dprintk("%s() Preparing QAM req\n", __func__);
                p->u.qam.symbol_rate = c->symbol_rate;
                p->u.qam.fec_inner = c->fec_inner;
                p->u.qam.modulation = c->modulation;
                c->delivery_system = SYS_DVBC_ANNEX_AC;
                break;
        case FE_OFDM:
-               printk("%s() Preparing OFDM req\n", __FUNCTION__);
+               dprintk("%s() Preparing OFDM req\n", __func__);
                if (c->bandwidth_hz == 6000000)
                        p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
                else if (c->bandwidth_hz == 7000000)
@@ -1036,7 +1036,7 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
                c->delivery_system = SYS_DVBT;
                break;
        case FE_ATSC:
-               printk("%s() Preparing VSB req\n", __FUNCTION__);
+               dprintk("%s() Preparing VSB req\n", __func__);
                p->u.vsb.modulation = c->modulation;
                if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
                        c->delivery_system = SYS_ATSC;
@@ -1055,14 +1055,13 @@ void dtv_property_adv_params_sync(struct dvb_frontend *fe)
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        struct dvb_frontend_parameters *p = &fepriv->parameters;
 
-       printk("%s()\n", __FUNCTION__);
-
        p->frequency = c->frequency;
        p->inversion = c->inversion;
 
        switch(c->modulation) {
        case PSK_8:
        case APSK_16:
+       case APSK_32:
        case QPSK:
                p->u.qpsk.symbol_rate = c->symbol_rate;
                p->u.qpsk.fec_inner = c->fec_inner;
@@ -1089,19 +1088,17 @@ void dtv_property_cache_submit(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-       printk("%s()\n", __FUNCTION__);
-
        /* For legacy delivery systems we don't need the delivery_system to
         * be specified, but we populate the older structures from the cache
         * so we can call set_frontend on older drivers.
         */
        if(is_legacy_delivery_system(c->delivery_system)) {
 
-               printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation);
+               dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);
                dtv_property_legacy_params_sync(fe);
 
        } else {
-               printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation);
+               dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);
 
                /* For advanced delivery systems / modulation types ...
                 * we seed the lecacy dvb_frontend_parameters structure
@@ -1123,8 +1120,6 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
 {
        int r = 0;
 
-       printk("%s()\n", __FUNCTION__);
-
        dtv_property_dump(tvp);
 
        /* Allow the frontend to validate incoming properties */
@@ -1198,7 +1193,6 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
 {
        int r = 0;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       printk("%s()\n", __FUNCTION__);
        dtv_property_dump(tvp);
 
        /* Allow the frontend to validate incoming properties */
@@ -1213,7 +1207,7 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
                /* Reset a cache of data specific to the frontend here. This does
                 * not effect hardware.
                 */
-               printk("%s() Flushing property cache\n", __FUNCTION__);
+               dprintk("%s() Flushing property cache\n", __func__);
                memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
                fe->dtv_property_cache.state = tvp->cmd;
                fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
@@ -1224,7 +1218,7 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
                 * ioctl.
                 */
                fe->dtv_property_cache.state = tvp->cmd;
-               printk("%s() Finalised property cache\n", __FUNCTION__);
+               dprintk("%s() Finalised property cache\n", __func__);
                dtv_property_cache_submit(fe);
 
                r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
@@ -1335,12 +1329,10 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
        dprintk("%s\n", __func__);
 
        if(cmd == FE_SET_PROPERTY) {
-               printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
-
                tvps = (struct dtv_properties __user *)parg;
 
-               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
-               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
 
                /* Put an arbitrary limit on the number of messages that can
                 * be sent at once */
@@ -1364,18 +1356,16 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
                        err |= (tvp + i)->result;
                }
 
-               if(fe->dtv_property_cache.state == DTV_TUNE) {
-                       printk("%s() Property cache is full, tuning\n", __FUNCTION__);
-               }
+               if(fe->dtv_property_cache.state == DTV_TUNE)
+                       dprintk("%s() Property cache is full, tuning\n", __func__);
 
        } else
        if(cmd == FE_GET_PROPERTY) {
-               printk("%s() FE_GET_PROPERTY\n", __FUNCTION__);
 
                tvps = (struct dtv_properties __user *)parg;
 
-               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
-               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
 
                /* Put an arbitrary limit on the number of messages that can
                 * be sent at once */
@@ -1704,13 +1694,53 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_adapter *adapter = fe->dvb;
        int ret;
 
        dprintk ("%s\n", __func__);
 
+       if (adapter->mfe_shared) {
+               mutex_lock (&adapter->mfe_lock);
+
+               if (adapter->mfe_dvbdev == NULL)
+                       adapter->mfe_dvbdev = dvbdev;
+
+               else if (adapter->mfe_dvbdev != dvbdev) {
+                       struct dvb_device
+                               *mfedev = adapter->mfe_dvbdev;
+                       struct dvb_frontend
+                               *mfe = mfedev->priv;
+                       struct dvb_frontend_private
+                               *mfepriv = mfe->frontend_priv;
+                       int mferetry = (dvb_mfe_wait_time << 1);
+
+                       mutex_unlock (&adapter->mfe_lock);
+                       while (mferetry-- && (mfedev->users != -1 ||
+                                       mfepriv->thread != NULL)) {
+                               if(msleep_interruptible(500)) {
+                                       if(signal_pending(current))
+                                               return -EINTR;
+                               }
+                       }
+
+                       mutex_lock (&adapter->mfe_lock);
+                       if(adapter->mfe_dvbdev != dvbdev) {
+                               mfedev = adapter->mfe_dvbdev;
+                               mfe = mfedev->priv;
+                               mfepriv = mfe->frontend_priv;
+                               if (mfedev->users != -1 ||
+                                               mfepriv->thread != NULL) {
+                                       mutex_unlock (&adapter->mfe_lock);
+                                       return -EBUSY;
+                               }
+                               adapter->mfe_dvbdev = dvbdev;
+                       }
+               }
+       }
+
        if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
                if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
-                       return ret;
+                       goto err0;
        }
 
        if ((ret = dvb_generic_open (inode, file)) < 0)
@@ -1730,6 +1760,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
                fepriv->events.eventr = fepriv->events.eventw = 0;
        }
 
+       if (adapter->mfe_shared)
+               mutex_unlock (&adapter->mfe_lock);
        return ret;
 
 err2:
@@ -1737,6 +1769,9 @@ err2:
 err1:
        if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
                fe->ops.ts_bus_ctrl(fe, 0);
+err0:
+       if (adapter->mfe_shared)
+               mutex_unlock (&adapter->mfe_lock);
        return ret;
 }
 
@@ -1806,8 +1841,9 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
        fe->dvb = dvb;
        fepriv->inversion = INVERSION_OFF;
 
-       printk ("DVB: registering frontend %i (%s)...\n",
+       printk ("DVB: registering adapter %i frontend %i (%s)...\n",
                fe->dvb->num,
+               fe->id,
                fe->ops.info.name);
 
        dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
index 3055301ff3cab3da0ee4a8ef555b9aa09c4a459d..db4a63b0a32e6e30a296e4b2ccae64f826ca8502 100644 (file)
@@ -222,6 +222,7 @@ struct dvb_frontend {
        struct dtv_frontend_properties dtv_property_cache;
 #define DVB_FRONTEND_COMPONENT_TUNER 0
        int (*callback)(void *adapter_priv, int component, int cmd, int arg);
+       int id;
 };
 
 extern int dvb_register_frontend(struct dvb_adapter *dvb,
index 665776d72a48c0456b712b25894760e60f48e4e8..a113744a56cc136c0355184b0af4504b0219970a 100644 (file)
@@ -326,6 +326,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
        adap->name = name;
        adap->module = module;
        adap->device = device;
+       adap->mfe_shared = 0;
+       adap->mfe_dvbdev = NULL;
+       mutex_init (&adap->mfe_lock);
 
        list_add_tail (&adap->list_head, &dvb_adapter_list);
 
index 89d12dc477a7b4f4017803a86d1bfaa6ef46b7ce..574e336bac35b7b8d81471a32fea7c2558fc530c 100644 (file)
@@ -62,6 +62,10 @@ struct dvb_adapter {
        struct device *device;
 
        struct module *module;
+
+       int mfe_shared;                 /* indicates mutually exclusive frontends */
+       struct dvb_device *mfe_dvbdev;  /* frontend device in use */
+       struct mutex mfe_lock;          /* access lock for thread creation */
 };
 
 
index ca53df61caa8fbc9d7e3b84c2a27c2b1bace533e..6286fbbe7fb5bd1178065d5618c817ab2da5a45d 100644 (file)
@@ -422,6 +422,18 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
        return 0;
 }
 
+static struct stv0299_config sharp_z0194a_config = {
+       .demod_address = 0x68,
+       .inittab = sharp_z0194a_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .lock_output = STV0299_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
 static struct cx24116_config dw2104_config = {
        .demod_address = 0x55,
        .mpg_clk_pos_pol = 0x01,
index 9430e03dba6c3fef4b744e28d7930b8ca0df09dd..5d1abe34bddb5cfc17694a7459877aaf0cbb86f7 100644 (file)
 #include "dvb_frontend.h"
 #include "cx22702.h"
 
-
 struct cx22702_state {
 
-       struct i2c_adapteri2c;
+       struct i2c_adapter *i2c;
 
        /* configuration settings */
-       const struct cx22702_configconfig;
+       const struct cx22702_config *config;
 
        struct dvb_frontend frontend;
 
@@ -49,10 +48,13 @@ struct cx22702_state {
 };
 
 static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
 #define dprintk        if (debug) printk
 
 /* Register values to initialise the demod */
-static u8 init_tab [] = {
+static u8 init_tab[] = {
        0x00, 0x00, /* Stop aquisition */
        0x0B, 0x06,
        0x09, 0x01,
@@ -80,65 +82,67 @@ static u8 init_tab [] = {
        0xfd, 0x00,
 };
 
-static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data)
+static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
 {
        int ret;
-       u8 buf [] = { reg, data };
-       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = {
+               .addr = state->config->demod_address, .flags = 0,
+                       .buf = buf, .len = 2 };
 
        ret = i2c_transfer(state->i2c, &msg, 1);
 
        if (ret != 1)
-               printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+               printk(KERN_ERR
+                       "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
                        __func__, reg, data, ret);
 
        return (ret != 1) ? -1 : 0;
 }
 
-static u8 cx22702_readreg (struct cx22702_state* state, u8 reg)
+static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
 {
        int ret;
-       u8 b0 [] = { reg };
-       u8 b1 [] = { 0 };
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
 
-       struct i2c_msg msg [] = {
-               { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-               { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+       struct i2c_msg msg[] = {
+               { .addr = state->config->demod_address, .flags = 0,
+                       .buf = b0, .len = 1 },
+               { .addr = state->config->demod_address, .flags = I2C_M_RD,
+                       .buf = b1, .len = 1 } };
 
        ret = i2c_transfer(state->i2c, msg, 2);
 
        if (ret != 2)
-               printk("%s: readreg error (ret == %i)\n", __func__, ret);
+               printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+                       __func__, ret);
 
        return b1[0];
 }
 
-static int cx22702_set_inversion (struct cx22702_state *state, int inversion)
+static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
 {
        u8 val;
 
        switch (inversion) {
-
-               case INVERSION_AUTO:
-                       return -EOPNOTSUPP;
-
-               case INVERSION_ON:
-                       val = cx22702_readreg (state, 0x0C);
-                       return cx22702_writereg (state, 0x0C, val | 0x01);
-
-               case INVERSION_OFF:
-                       val = cx22702_readreg (state, 0x0C);
-                       return cx22702_writereg (state, 0x0C, val & 0xfe);
-
-               default:
-                       return -EINVAL;
-
+       case INVERSION_AUTO:
+               return -EOPNOTSUPP;
+       case INVERSION_ON:
+               val = cx22702_readreg(state, 0x0C);
+               return cx22702_writereg(state, 0x0C, val | 0x01);
+       case INVERSION_OFF:
+               val = cx22702_readreg(state, 0x0C);
+               return cx22702_writereg(state, 0x0C, val & 0xfe);
+       default:
+               return -EINVAL;
        }
 
 }
 
 /* Retrieve the demod settings */
-static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p)
+static int cx22702_get_tps(struct cx22702_state *state,
+       struct dvb_ofdm_parameters *p)
 {
        u8 val;
 
@@ -146,180 +150,281 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet
        if (!(cx22702_readreg(state, 0x0A) & 0x20))
                return -EAGAIN;
 
-       val = cx22702_readreg (state, 0x01);
-       switch( (val&0x18)>>3) {
-               case 0: p->constellation =   QPSK; break;
-               case 1: p->constellation = QAM_16; break;
-               case 2: p->constellation = QAM_64; break;
+       val = cx22702_readreg(state, 0x01);
+       switch ((val & 0x18) >> 3) {
+       case 0:
+               p->constellation = QPSK;
+               break;
+       case 1:
+               p->constellation = QAM_16;
+               break;
+       case 2:
+               p->constellation = QAM_64;
+               break;
        }
-       switch( val&0x07 ) {
-               case 0: p->hierarchy_information = HIERARCHY_NONE; break;
-               case 1: p->hierarchy_information =    HIERARCHY_1; break;
-               case 2: p->hierarchy_information =    HIERARCHY_2; break;
-               case 3: p->hierarchy_information =    HIERARCHY_4; break;
+       switch (val & 0x07) {
+       case 0:
+               p->hierarchy_information = HIERARCHY_NONE;
+               break;
+       case 1:
+               p->hierarchy_information = HIERARCHY_1;
+               break;
+       case 2:
+               p->hierarchy_information = HIERARCHY_2;
+               break;
+       case 3:
+               p->hierarchy_information = HIERARCHY_4;
+               break;
        }
 
 
-       val = cx22702_readreg (state, 0x02);
-       switch( (val&0x38)>>3 ) {
-               case 0: p->code_rate_HP = FEC_1_2; break;
-               case 1: p->code_rate_HP = FEC_2_3; break;
-               case 2: p->code_rate_HP = FEC_3_4; break;
-               case 3: p->code_rate_HP = FEC_5_6; break;
-               case 4: p->code_rate_HP = FEC_7_8; break;
+       val = cx22702_readreg(state, 0x02);
+       switch ((val & 0x38) >> 3) {
+       case 0:
+               p->code_rate_HP = FEC_1_2;
+               break;
+       case 1:
+               p->code_rate_HP = FEC_2_3;
+               break;
+       case 2:
+               p->code_rate_HP = FEC_3_4;
+               break;
+       case 3:
+               p->code_rate_HP = FEC_5_6;
+               break;
+       case 4:
+               p->code_rate_HP = FEC_7_8;
+               break;
        }
-       switch( val&0x07 ) {
-               case 0: p->code_rate_LP = FEC_1_2; break;
-               case 1: p->code_rate_LP = FEC_2_3; break;
-               case 2: p->code_rate_LP = FEC_3_4; break;
-               case 3: p->code_rate_LP = FEC_5_6; break;
-               case 4: p->code_rate_LP = FEC_7_8; break;
+       switch (val & 0x07) {
+       case 0:
+               p->code_rate_LP = FEC_1_2;
+               break;
+       case 1:
+               p->code_rate_LP = FEC_2_3;
+               break;
+       case 2:
+               p->code_rate_LP = FEC_3_4;
+               break;
+       case 3:
+               p->code_rate_LP = FEC_5_6;
+               break;
+       case 4:
+               p->code_rate_LP = FEC_7_8;
+               break;
        }
 
-
-       val = cx22702_readreg (state, 0x03);
-       switch( (val&0x0c)>>2 ) {
-               case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
-               case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
-               case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
-               case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
+       val = cx22702_readreg(state, 0x03);
+       switch ((val & 0x0c) >> 2) {
+       case 0:
+               p->guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               p->guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               p->guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               p->guard_interval = GUARD_INTERVAL_1_4;
+               break;
        }
-       switch( val&0x03 ) {
-               case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
-               case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+       switch (val & 0x03) {
+       case 0:
+               p->transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 1:
+               p->transmission_mode = TRANSMISSION_MODE_8K;
+               break;
        }
 
        return 0;
 }
 
-static int cx22702_i2c_gate_ctrl(struct dvb_frontendfe, int enable)
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
-       dprintk ("%s(%d)\n", __func__, enable);
+       struct cx22702_state *state = fe->demodulator_priv;
+       dprintk("%s(%d)\n", __func__, enable);
        if (enable)
-               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
+               return cx22702_writereg(state, 0x0D,
+                       cx22702_readreg(state, 0x0D) & 0xfe);
        else
-               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
+               return cx22702_writereg(state, 0x0D,
+                       cx22702_readreg(state, 0x0D) | 1);
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22702_set_tps(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
 {
        u8 val;
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
 
        if (fe->ops.tuner_ops.set_params) {
                fe->ops.tuner_ops.set_params(fe, p);
-               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        /* set inversion */
-       cx22702_set_inversion (state, p->inversion);
+       cx22702_set_inversion(state, p->inversion);
 
        /* set bandwidth */
-       switch(p->u.ofdm.bandwidth) {
+       switch (p->u.ofdm.bandwidth) {
        case BANDWIDTH_6_MHZ:
-               cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 );
+               cx22702_writereg(state, 0x0C,
+                       (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20);
                break;
        case BANDWIDTH_7_MHZ:
-               cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 );
+               cx22702_writereg(state, 0x0C,
+                       (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10);
                break;
        case BANDWIDTH_8_MHZ:
-               cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf );
+               cx22702_writereg(state, 0x0C,
+                       cx22702_readreg(state, 0x0C) & 0xcf);
                break;
        default:
-               dprintk ("%s: invalid bandwidth\n",__func__);
+               dprintk("%s: invalid bandwidth\n", __func__);
                return -EINVAL;
        }
 
-
-       p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working
+       p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
 
        /* use auto configuration? */
-       if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) ||
-          (p->u.ofdm.constellation==QAM_AUTO) ||
-          (p->u.ofdm.code_rate_HP==FEC_AUTO) ||
-          (p->u.ofdm.code_rate_LP==FEC_AUTO) ||
-          (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) ||
-          (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) {
+       if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) ||
+          (p->u.ofdm.constellation == QAM_AUTO) ||
+          (p->u.ofdm.code_rate_HP == FEC_AUTO) ||
+          (p->u.ofdm.code_rate_LP == FEC_AUTO) ||
+          (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) ||
+          (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) {
 
                /* TPS Source - use hardware driven values */
                cx22702_writereg(state, 0x06, 0x10);
                cx22702_writereg(state, 0x07, 0x9);
                cx22702_writereg(state, 0x08, 0xC1);
-               cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
-               cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+               cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
+                       & 0xfc);
+               cx22702_writereg(state, 0x0C,
+                       (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
                cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
-               dprintk("%s: Autodetecting\n",__func__);
+               dprintk("%s: Autodetecting\n", __func__);
                return 0;
        }
 
        /* manually programmed values */
-       val=0;
-       switch(p->u.ofdm.constellation) {
-               case   QPSK: val = (val&0xe7); break;
-               case QAM_16: val = (val&0xe7)|0x08; break;
-               case QAM_64: val = (val&0xe7)|0x10; break;
-               default:
-                       dprintk ("%s: invalid constellation\n",__func__);
-                       return -EINVAL;
+       val = 0;
+       switch (p->u.ofdm.constellation) {
+       case QPSK:
+               val = (val & 0xe7);
+               break;
+       case QAM_16:
+               val = (val & 0xe7) | 0x08;
+               break;
+       case QAM_64:
+               val = (val & 0xe7) | 0x10;
+               break;
+       default:
+               dprintk("%s: invalid constellation\n", __func__);
+               return -EINVAL;
        }
-       switch(p->u.ofdm.hierarchy_information) {
-               case HIERARCHY_NONE: val = (val&0xf8); break;
-               case    HIERARCHY_1: val = (val&0xf8)|1; break;
-               case    HIERARCHY_2: val = (val&0xf8)|2; break;
-               case    HIERARCHY_4: val = (val&0xf8)|3; break;
-               default:
-                       dprintk ("%s: invalid hierarchy\n",__func__);
-                       return -EINVAL;
+       switch (p->u.ofdm.hierarchy_information) {
+       case HIERARCHY_NONE:
+               val = (val & 0xf8);
+               break;
+       case HIERARCHY_1:
+               val = (val & 0xf8) | 1;
+               break;
+       case HIERARCHY_2:
+               val = (val & 0xf8) | 2;
+               break;
+       case HIERARCHY_4:
+               val = (val & 0xf8) | 3;
+               break;
+       default:
+               dprintk("%s: invalid hierarchy\n", __func__);
+               return -EINVAL;
        }
-       cx22702_writereg (state, 0x06, val);
-
-       val=0;
-       switch(p->u.ofdm.code_rate_HP) {
-               case FEC_NONE:
-               case FEC_1_2: val = (val&0xc7); break;
-               case FEC_2_3: val = (val&0xc7)|0x08; break;
-               case FEC_3_4: val = (val&0xc7)|0x10; break;
-               case FEC_5_6: val = (val&0xc7)|0x18; break;
-               case FEC_7_8: val = (val&0xc7)|0x20; break;
-               default:
-                       dprintk ("%s: invalid code_rate_HP\n",__func__);
-                       return -EINVAL;
+       cx22702_writereg(state, 0x06, val);
+
+       val = 0;
+       switch (p->u.ofdm.code_rate_HP) {
+       case FEC_NONE:
+       case FEC_1_2:
+               val = (val & 0xc7);
+               break;
+       case FEC_2_3:
+               val = (val & 0xc7) | 0x08;
+               break;
+       case FEC_3_4:
+               val = (val & 0xc7) | 0x10;
+               break;
+       case FEC_5_6:
+               val = (val & 0xc7) | 0x18;
+               break;
+       case FEC_7_8:
+               val = (val & 0xc7) | 0x20;
+               break;
+       default:
+               dprintk("%s: invalid code_rate_HP\n", __func__);
+               return -EINVAL;
        }
-       switch(p->u.ofdm.code_rate_LP) {
-               case FEC_NONE:
-               case FEC_1_2: val = (val&0xf8); break;
-               case FEC_2_3: val = (val&0xf8)|1; break;
-               case FEC_3_4: val = (val&0xf8)|2; break;
-               case FEC_5_6: val = (val&0xf8)|3; break;
-               case FEC_7_8: val = (val&0xf8)|4; break;
-               default:
-                       dprintk ("%s: invalid code_rate_LP\n",__func__);
-                       return -EINVAL;
+       switch (p->u.ofdm.code_rate_LP) {
+       case FEC_NONE:
+       case FEC_1_2:
+               val = (val & 0xf8);
+               break;
+       case FEC_2_3:
+               val = (val & 0xf8) | 1;
+               break;
+       case FEC_3_4:
+               val = (val & 0xf8) | 2;
+               break;
+       case FEC_5_6:
+               val = (val & 0xf8) | 3;
+               break;
+       case FEC_7_8:
+               val = (val & 0xf8) | 4;
+               break;
+       default:
+               dprintk("%s: invalid code_rate_LP\n", __func__);
+               return -EINVAL;
        }
-       cx22702_writereg (state, 0x07, val);
-
-       val=0;
-       switch(p->u.ofdm.guard_interval) {
-               case GUARD_INTERVAL_1_32: val = (val&0xf3); break;
-               case GUARD_INTERVAL_1_16: val = (val&0xf3)|0x04; break;
-               case  GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break;
-               case  GUARD_INTERVAL_1_4: val = (val&0xf3)|0x0c; break;
-               default:
-                       dprintk ("%s: invalid guard_interval\n",__func__);
-                       return -EINVAL;
+       cx22702_writereg(state, 0x07, val);
+
+       val = 0;
+       switch (p->u.ofdm.guard_interval) {
+       case GUARD_INTERVAL_1_32:
+               val = (val & 0xf3);
+               break;
+       case GUARD_INTERVAL_1_16:
+               val = (val & 0xf3) | 0x04;
+               break;
+       case GUARD_INTERVAL_1_8:
+               val = (val & 0xf3) | 0x08;
+               break;
+       case GUARD_INTERVAL_1_4:
+               val = (val & 0xf3) | 0x0c;
+               break;
+       default:
+               dprintk("%s: invalid guard_interval\n", __func__);
+               return -EINVAL;
        }
-       switch(p->u.ofdm.transmission_mode) {
-               case TRANSMISSION_MODE_2K: val = (val&0xfc); break;
-               case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break;
-               default:
-                       dprintk ("%s: invalid transmission_mode\n",__func__);
-                       return -EINVAL;
+       switch (p->u.ofdm.transmission_mode) {
+       case TRANSMISSION_MODE_2K:
+               val = (val & 0xfc);
+               break;
+       case TRANSMISSION_MODE_8K:
+               val = (val & 0xfc) | 1;
+               break;
+       default:
+               dprintk("%s: invalid transmission_mode\n", __func__);
+               return -EINVAL;
        }
        cx22702_writereg(state, 0x08, val);
-       cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 );
-       cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+       cx22702_writereg(state, 0x0B,
+               (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
+       cx22702_writereg(state, 0x0C,
+               (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
 
        /* Begin channel aquisition */
        cx22702_writereg(state, 0x00, 0x01);
@@ -329,109 +434,111 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
 
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
-static int cx22702_init (struct dvb_frontend* fe)
+static int cx22702_init(struct dvb_frontend *fe)
 {
        int i;
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
 
-       cx22702_writereg (state, 0x00, 0x02);
+       cx22702_writereg(state, 0x00, 0x02);
 
        msleep(10);
 
-       for (i=0; i<sizeof(init_tab); i+=2)
-               cx22702_writereg (state, init_tab[i], init_tab[i+1]);
+       for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
+               cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
 
-       cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
+       cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
+               & 0x02);
 
        cx22702_i2c_gate_ctrl(fe, 0);
 
        return 0;
 }
 
-static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
        u8 reg0A;
        u8 reg23;
 
        *status = 0;
 
-       reg0A = cx22702_readreg (state, 0x0A);
-       reg23 = cx22702_readreg (state, 0x23);
+       reg0A = cx22702_readreg(state, 0x0A);
+       reg23 = cx22702_readreg(state, 0x23);
 
-       dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
-               ,__func__,reg0A,reg23);
+       dprintk("%s: status demod=0x%02x agc=0x%02x\n"
+               , __func__, reg0A, reg23);
 
-       if(reg0A & 0x10) {
+       if (reg0A & 0x10) {
                *status |= FE_HAS_LOCK;
                *status |= FE_HAS_VITERBI;
                *status |= FE_HAS_SYNC;
        }
 
-       if(reg0A & 0x20)
+       if (reg0A & 0x20)
                *status |= FE_HAS_CARRIER;
 
-       if(reg23 < 0xf0)
+       if (reg23 < 0xf0)
                *status |= FE_HAS_SIGNAL;
 
        return 0;
 }
 
-static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber)
+static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
 
-       if(cx22702_readreg (state, 0xE4) & 0x02) {
+       if (cx22702_readreg(state, 0xE4) & 0x02) {
                /* Realtime statistics */
-               *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
-                       | (cx22702_readreg (state, 0xDF)&0x7F);
+               *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+                       | (cx22702_readreg(state, 0xDF) & 0x7F);
        } else {
                /* Averagtine statistics */
-               *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
-                       | cx22702_readreg (state, 0xDF);
+               *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+                       | cx22702_readreg(state, 0xDF);
        }
 
        return 0;
 }
 
-static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+static int cx22702_read_signal_strength(struct dvb_frontend *fe,
+       u16 *signal_strength)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
 
        u16 rs_ber = 0;
-       rs_ber = cx22702_readreg (state, 0x23);
+       rs_ber = cx22702_readreg(state, 0x23);
        *signal_strength = (rs_ber << 8) | rs_ber;
 
        return 0;
 }
 
-static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
+static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
 
-       u16 rs_ber=0;
-       if(cx22702_readreg (state, 0xE4) & 0x02) {
+       u16 rs_ber = 0;
+       if (cx22702_readreg(state, 0xE4) & 0x02) {
                /* Realtime statistics */
-               rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
-                       | (cx22702_readreg (state, 0xDF)& 0x7F);
+               rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
+                       | (cx22702_readreg(state, 0xDF) & 0x7F);
        } else {
                /* Averagine statistics */
-               rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8
-                       | cx22702_readreg (state, 0xDF);
+               rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
+                       | cx22702_readreg(state, 0xDF);
        }
        *snr = ~rs_ber;
 
        return 0;
 }
 
-static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
 
        u8 _ucblocks;
 
        /* RS Uncorrectable Packet Count then reset */
-       _ucblocks = cx22702_readreg (state, 0xE3);
+       _ucblocks = cx22702_readreg(state, 0xE3);
        if (state->prevUCBlocks < _ucblocks)
                *ucblocks = (_ucblocks - state->prevUCBlocks);
        else
@@ -441,34 +548,36 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22702_get_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
 
-       u8 reg0C = cx22702_readreg (state, 0x0C);
+       u8 reg0C = cx22702_readreg(state, 0x0C);
 
        p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
-       return cx22702_get_tps (state, &p->u.ofdm);
+       return cx22702_get_tps(state, &p->u.ofdm);
 }
 
-static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+static int cx22702_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *tune)
 {
        tune->min_delay_ms = 1000;
        return 0;
 }
 
-static void cx22702_release(struct dvb_frontendfe)
+static void cx22702_release(struct dvb_frontend *fe)
 {
-       struct cx22702_statestate = fe->demodulator_priv;
+       struct cx22702_state *state = fe->demodulator_priv;
        kfree(state);
 }
 
 static struct dvb_frontend_ops cx22702_ops;
 
-struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
-                                   struct i2c_adapter* i2c)
+struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
+       struct i2c_adapter *i2c)
 {
-       struct cx22702_statestate = NULL;
+       struct cx22702_state *state = NULL;
 
        /* allocate memory for the internal state */
        state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
@@ -485,7 +594,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
                goto error;
 
        /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
+       memcpy(&state->frontend.ops, &cx22702_ops,
+               sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -493,6 +603,7 @@ error:
        kfree(state);
        return NULL;
 }
+EXPORT_SYMBOL(cx22702_attach);
 
 static struct dvb_frontend_ops cx22702_ops = {
 
@@ -525,11 +636,6 @@ static struct dvb_frontend_ops cx22702_ops = {
        .read_ucblocks = cx22702_read_ucblocks,
 };
 
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
 MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
 MODULE_AUTHOR("Steven Toth");
 MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(cx22702_attach);
index b1e465c6c2cec362c989f7a17a41e6c5c03a05f4..f154e1f428eb64c5a0924bbc6389c479bfe6f64d 100644 (file)
@@ -30,8 +30,7 @@
 
 #include <linux/dvb/frontend.h>
 
-struct cx22702_config
-{
+struct cx22702_config {
        /* the demodulator's i2c address */
        u8 demod_address;
 
@@ -41,16 +40,19 @@ struct cx22702_config
        u8 output_mode;
 };
 
-#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) && defined(MODULE))
-extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
-                                          struct i2c_adapter* i2c);
+#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \
+       && defined(MODULE))
+extern struct dvb_frontend *cx22702_attach(
+       const struct cx22702_config *config,
+       struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
-                                          struct i2c_adapter* i2c)
+static inline struct dvb_frontend *cx22702_attach(
+       const struct cx22702_config *config,
+       struct i2c_adapter *i2c)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-#endif // CONFIG_DVB_CX22702
+#endif
 
-#endif // CX22702_H
+#endif
index deb36f469adad00e0275e3a4e0d70a3b7368cb3c..b144b308a4dd336854226eb1c5ef2484b598b0c2 100644 (file)
 #include "dvb_frontend.h"
 #include "cx24116.h"
 
-static int debug = 0;
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
 #define dprintk(args...) \
        do { \
-               if (debug) printk ("cx24116: " args); \
+               if (debug) \
+                       printk(KERN_INFO "cx24116: " args); \
        } while (0)
 
 #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
@@ -68,13 +72,20 @@ static int debug = 0;
 #define CX24116_REG_UCB8    (0xca)
 #define CX24116_REG_CLKDIV  (0xf3)
 #define CX24116_REG_RATEDIV (0xf9)
-#define CX24116_REG_FECSTATUS (0x9c)    /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
+
+/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
+#define CX24116_REG_FECSTATUS (0x9c)
 
 /* FECSTATUS bits */
-#define CX24116_FEC_FECMASK   (0x1f)    /* mask to determine configured fec (not tuned) or actual fec (tuned) */
-#define CX24116_FEC_DVBS      (0x20)    /* Select DVB-S demodulator, else DVB-S2 */
+/* mask to determine configured fec (not tuned) or actual fec (tuned) */
+#define CX24116_FEC_FECMASK   (0x1f)
+
+/* Select DVB-S demodulator, else DVB-S2 */
+#define CX24116_FEC_DVBS      (0x20)
 #define CX24116_FEC_UNKNOWN   (0x40)    /* Unknown/unused */
-#define CX24116_FEC_PILOT     (0x80)    /* Pilot mode requested when tuning else always reset when tuned */
+
+/* Pilot mode requested when tuning else always reset when tuned */
+#define CX24116_FEC_PILOT     (0x80)
 
 /* arg buffer size */
 #define CX24116_ARGLEN (0x1e)
@@ -116,12 +127,17 @@ static int debug = 0;
 
 /* DiSEqC tone burst */
 static int toneburst = 1;
+module_param(toneburst, int, 0644);
+MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
+       "2=MESSAGE CACHE (default:1)");
 
 /* SNR measurements */
-static int esno_snr = 0;
+static int esno_snr;
+module_param(esno_snr, int, 0644);
+MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\
+       "1=ESNO(db * 10) (default:0)");
 
-enum cmds
-{
+enum cmds {
        CMD_SET_VCO     = 0x10,
        CMD_TUNEREQUEST = 0x11,
        CMD_MPEGCONFIG  = 0x13,
@@ -138,8 +154,7 @@ enum cmds
 };
 
 /* The Demod/Tuner can't easily provide these, we cache them */
-struct cx24116_tuning
-{
+struct cx24116_tuning {
        u32 frequency;
        u32 symbol_rate;
        fe_spectral_inversion_t inversion;
@@ -158,16 +173,14 @@ struct cx24116_tuning
 };
 
 /* Basic commands that are sent to the firmware */
-struct cx24116_cmd
-{
+struct cx24116_cmd {
        u8 len;
        u8 args[CX24116_ARGLEN];
 };
 
-struct cx24116_state
-{
-       struct i2c_adapter* i2c;
-       const struct cx24116_config* config;
+struct cx24116_state {
+       struct i2c_adapter *i2c;
+       const struct cx24116_config *config;
 
        struct dvb_frontend frontend;
 
@@ -179,19 +192,20 @@ struct cx24116_state
        struct cx24116_cmd dsec_cmd;
 };
 
-static int cx24116_writereg(struct cx24116_statestate, int reg, int data)
+static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
 {
        u8 buf[] = { reg, data };
        struct i2c_msg msg = { .addr = state->config->demod_address,
                .flags = 0, .buf = buf, .len = 2 };
        int err;
 
-       if (debug>1)
+       if (debug > 1)
                printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
-                                               __func__,reg, data);
+                       __func__, reg, data);
 
-       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-               printk("%s: writereg error(err == %i, reg == 0x%02x,"
+       err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1) {
+               printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
                         " value == 0x%02x)\n", __func__, err, reg, data);
                return -EREMOTEIO;
        }
@@ -200,7 +214,8 @@ static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
 }
 
 /* Bulk byte writes to a single I2C address, for 32k firmware load */
-static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
+static int cx24116_writeregN(struct cx24116_state *state, int reg,
+                            const u8 *data, u16 len)
 {
        int ret = -EREMOTEIO;
        struct i2c_msg msg;
@@ -221,12 +236,13 @@ static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16
        msg.buf = buf;
        msg.len = len + 1;
 
-       if (debug>1)
-               printk("cx24116: %s:  write regN 0x%02x, len = %d\n",
-                                               __func__,reg, len);
+       if (debug > 1)
+               printk(KERN_INFO "cx24116: %s:  write regN 0x%02x, len = %d\n",
+                       __func__, reg, len);
 
-       if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-               printk("%s: writereg error(err == %i, reg == 0x%02x\n",
+       ret = i2c_transfer(state->i2c, &msg, 1);
+       if (ret != 1) {
+               printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
                         __func__, ret, reg);
                ret = -EREMOTEIO;
        }
@@ -237,30 +253,35 @@ error:
        return ret;
 }
 
-static int cx24116_readreg(struct cx24116_statestate, u8 reg)
+static int cx24116_readreg(struct cx24116_state *state, u8 reg)
 {
        int ret;
        u8 b0[] = { reg };
        u8 b1[] = { 0 };
        struct i2c_msg msg[] = {
-               { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-               { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+               { .addr = state->config->demod_address, .flags = 0,
+                       .buf = b0, .len = 1 },
+               { .addr = state->config->demod_address, .flags = I2C_M_RD,
+                       .buf = b1, .len = 1 }
        };
 
        ret = i2c_transfer(state->i2c, msg, 2);
 
        if (ret != 2) {
-               printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
+               printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
+                       __func__, reg, ret);
                return ret;
        }
 
-       if (debug>1)
-               printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]);
+       if (debug > 1)
+               printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
+                       reg, b1[0]);
 
        return b1[0];
 }
 
-static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion)
+static int cx24116_set_inversion(struct cx24116_state *state,
+       fe_spectral_inversion_t inversion)
 {
        dprintk("%s(%d)\n", __func__, inversion);
 
@@ -308,10 +329,10 @@ static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_invers
  * Eg.(2/3) szap "Zone Horror"
  *
  * mask/val = 0x04, 0x20
- * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
+ * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
  *
  * mask/val = 0x04, 0x30
- * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
+ * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
  *
  * After tuning FECSTATUS contains actual FEC
  * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
@@ -389,18 +410,16 @@ struct cx24116_modfec {
   */
 };
 
-static int cx24116_lookup_fecmod(struct cx24116_statestate,
+static int cx24116_lookup_fecmod(struct cx24116_state *state,
        fe_modulation_t m, fe_code_rate_t f)
 {
        int i, ret = -EOPNOTSUPP;
 
        dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
 
-       for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++)
-       {
-               if( (m == CX24116_MODFEC_MODES[i].modulation) &&
-                       (f == CX24116_MODFEC_MODES[i].fec) )
-                       {
+       for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
+               if ((m == CX24116_MODFEC_MODES[i].modulation) &&
+                       (f == CX24116_MODFEC_MODES[i].fec)) {
                                ret = i;
                                break;
                        }
@@ -409,7 +428,8 @@ static int cx24116_lookup_fecmod(struct cx24116_state* state,
        return ret;
 }
 
-static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec)
+static int cx24116_set_fec(struct cx24116_state *state,
+       fe_modulation_t mod, fe_code_rate_t fec)
 {
        int ret = 0;
 
@@ -417,7 +437,7 @@ static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_
 
        ret = cx24116_lookup_fecmod(state, mod, fec);
 
-       if(ret < 0)
+       if (ret < 0)
                return ret;
 
        state->dnxt.fec = fec;
@@ -429,7 +449,7 @@ static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_
        return 0;
 }
 
-static int cx24116_set_symbolrate(struct cx24116_statestate, u32 rate)
+static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
 {
        dprintk("%s(%d)\n", __func__, rate);
 
@@ -446,42 +466,49 @@ static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
        return 0;
 }
 
-static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw);
+static int cx24116_load_firmware(struct dvb_frontend *fe,
+       const struct firmware *fw);
 
-static int cx24116_firmware_ondemand(struct dvb_frontendfe)
+static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        const struct firmware *fw;
        int ret = 0;
 
-       dprintk("%s()\n",__func__);
+       dprintk("%s()\n", __func__);
 
-       if (cx24116_readreg(state, 0x20) > 0)
-       {
+       if (cx24116_readreg(state, 0x20) > 0) {
 
                if (state->skip_fw_load)
                        return 0;
 
                /* Load firmware */
-               /* request the firmware, this will block until someone uploads it */
-               printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
-               ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
-               printk("%s: Waiting for firmware upload(2)...\n", __func__);
+               /* request the firmware, this will block until loaded */
+               printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
+                       __func__, CX24116_DEFAULT_FIRMWARE);
+               ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
+                       &state->i2c->dev);
+               printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
+                       __func__);
                if (ret) {
-                       printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
+                       printk(KERN_ERR "%s: No firmware uploaded "
+                               "(timeout or file not found?)\n", __func__);
                        return ret;
                }
 
-               /* Make sure we don't recurse back through here during loading */
+               /* Make sure we don't recurse back through here
+                * during loading */
                state->skip_fw_load = 1;
 
                ret = cx24116_load_firmware(fe, fw);
                if (ret)
-                       printk("%s: Writing firmware to device failed\n", __func__);
+                       printk(KERN_ERR "%s: Writing firmware to device failed\n",
+                               __func__);
 
                release_firmware(fw);
 
-               printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
+               printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
+                       ret == 0 ? "complete" : "failed");
 
                /* Ensure firmware is always loaded if required */
                state->skip_fw_load = 0;
@@ -490,8 +517,10 @@ static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
        return ret;
 }
 
-/* Take a basic firmware command structure, format it and forward it for processing */
-static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
+/* Take a basic firmware command structure, format it
+ * and forward it for processing
+ */
+static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        int i, ret;
@@ -499,49 +528,49 @@ static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
        dprintk("%s()\n", __func__);
 
        /* Load the firmware if required */
-       if ( (ret = cx24116_firmware_ondemand(fe)) != 0)
-       {
-               printk("%s(): Unable initialise the firmware\n", __func__);
+       ret = cx24116_firmware_ondemand(fe);
+       if (ret != 0) {
+               printk(KERN_ERR "%s(): Unable initialise the firmware\n",
+                       __func__);
                return ret;
        }
 
        /* Write the command */
-       for(i = 0; i < cmd->len ; i++)
-       {
+       for (i = 0; i < cmd->len ; i++) {
                dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
                cx24116_writereg(state, i, cmd->args[i]);
        }
 
        /* Start execution and wait for cmd to terminate */
        cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
-       while( cx24116_readreg(state, CX24116_REG_EXECUTE) )
-       {
+       while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
                msleep(10);
-               if(i++ > 64)
-               {
-                       /* Avoid looping forever if the firmware does no respond */
-                       printk("%s() Firmware not responding\n", __func__);
+               if (i++ > 64) {
+                       /* Avoid looping forever if the firmware does
+                               not respond */
+                       printk(KERN_WARNING "%s() Firmware not responding\n",
+                               __func__);
                        return -EREMOTEIO;
                }
        }
        return 0;
 }
 
-static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+static int cx24116_load_firmware(struct dvb_frontend *fe,
+       const struct firmware *fw)
 {
-       struct cx24116_statestate = fe->demodulator_priv;
+       struct cx24116_state *state = fe->demodulator_priv;
        struct cx24116_cmd cmd;
        int i, ret;
        unsigned char vers[4];
 
        dprintk("%s\n", __func__);
-       dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n"
-                       ,fw->size
-                       ,fw->data[0]
-                       ,fw->data[1]
-                       ,fw->data[ fw->size-2 ]
-                       ,fw->data[ fw->size-1 ]
-                       );
+       dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
+                       fw->size,
+                       fw->data[0],
+                       fw->data[1],
+                       fw->data[fw->size-2],
+                       fw->data[fw->size-1]);
 
        /* Toggle 88x SRST pin to reset demod */
        if (state->config->reset_device)
@@ -587,7 +616,7 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware
        cmd.args[0x07] = 0x9d;
        cmd.args[0x08] = 0xfc;
        cmd.args[0x09] = 0x06;
-       cmd.len= 0x0a;
+       cmd.len = 0x0a;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
@@ -598,7 +627,7 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware
        cmd.args[0x00] = CMD_TUNERINIT;
        cmd.args[0x01] = 0x00;
        cmd.args[0x02] = 0x00;
-       cmd.len= 0x03;
+       cmd.len = 0x03;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
@@ -615,36 +644,38 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware
        else
                cmd.args[0x04] = 0x02;
        cmd.args[0x05] = 0x00;
-       cmd.len= 0x06;
+       cmd.len = 0x06;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
 
        /* Firmware CMD 35: Get firmware version */
        cmd.args[0x00] = CMD_UPDFWVERS;
-       cmd.len= 0x02;
-       for(i=0; i<4; i++) {
+       cmd.len = 0x02;
+       for (i = 0; i < 4; i++) {
                cmd.args[0x01] = i;
                ret = cx24116_cmd_execute(fe, &cmd);
                if (ret != 0)
                        return ret;
-               vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX);
+               vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
        }
-       printk("%s: FW version %i.%i.%i.%i\n", __func__,
+       printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
                vers[0], vers[1], vers[2], vers[3]);
 
        return 0;
 }
 
-static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+static int cx24116_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t voltage)
 {
        /* The isl6421 module will override this function in the fops. */
-       dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__);
+       dprintk("%s() This should never appear if the isl6421 module "
+               "is loaded correctly\n", __func__);
 
        return -EOPNOTSUPP;
 }
 
-static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct cx24116_state *state = fe->demodulator_priv;
 
@@ -666,22 +697,23 @@ static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
        return 0;
 }
 
-static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber)
+static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct cx24116_state *state = fe->demodulator_priv;
 
        dprintk("%s()\n", __func__);
 
-       *ber =  ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) |
-               ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) |
-               ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8  ) |
-                 cx24116_readreg(state, CX24116_REG_BER0 );
+       *ber =  (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
+               (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
+               (cx24116_readreg(state, CX24116_REG_BER8)  << 8)  |
+                cx24116_readreg(state, CX24116_REG_BER0);
 
        return 0;
 }
 
 /* TODO Determine function and scale appropriately */
-static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+static int cx24116_read_signal_strength(struct dvb_frontend *fe,
+       u16 *signal_strength)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        struct cx24116_cmd cmd;
@@ -692,39 +724,43 @@ static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_str
 
        /* Firmware CMD 19: Get AGC */
        cmd.args[0x00] = CMD_GETAGC;
-       cmd.len= 0x01;
+       cmd.len = 0x01;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
 
-       sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) |
-               ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 );
-       *signal_strength= 0 - sig_reading;
+       sig_reading =
+               (cx24116_readreg(state,
+                       CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
+               (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
+       *signal_strength = 0 - sig_reading;
 
-       dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength);
+       dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
+               __func__, sig_reading, *signal_strength);
 
        return 0;
 }
 
 /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
-static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr)
+static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        u8 snr_reading;
        static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
-               0x00000,0x0199A,0x03333,0x04ccD,0x06667,
-                       0x08000,0x0999A,0x0b333,0x0cccD,0x0e667,
-               0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 };
+               0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
+               0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
+               0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
+               0x18000 };
 
        dprintk("%s()\n", __func__);
 
        snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
 
-       if(snr_reading >= 0xa0 /* 100% */)
+       if (snr_reading >= 0xa0 /* 100% */)
                *snr = 0xffff;
        else
-               *snr = snr_tab [ ( snr_reading & 0xf0 )   >> 4 ] +
-                       ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 );
+               *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
+                       (snr_tab[(snr_reading & 0x0f)] >> 4);
 
        dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
                snr_reading, *snr);
@@ -736,7 +772,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr)
  * ESNO, from 0->30db (values 0->300). We provide this value by
  * default.
  */
-static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr)
+static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
 {
        struct cx24116_state *state = fe->demodulator_priv;
 
@@ -750,7 +786,7 @@ static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr)
        return 0;
 }
 
-static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
+static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        if (esno_snr == 1)
                return cx24116_read_snr_esno(fe, snr);
@@ -758,27 +794,27 @@ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
                return cx24116_read_snr_pct(fe, snr);
 }
 
-static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
        struct cx24116_state *state = fe->demodulator_priv;
 
        dprintk("%s()\n", __func__);
 
-       *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) |
+       *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
                cx24116_readreg(state, CX24116_REG_UCB0);
 
        return 0;
 }
 
 /* Overwrite the current tuning params, we are about to tune */
-static void cx24116_clone_params(struct dvb_frontendfe)
+static void cx24116_clone_params(struct dvb_frontend *fe)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
 }
 
 /* Wait for LNB */
-static int cx24116_wait_for_lnb(struct dvb_frontendfe)
+static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        int i;
@@ -787,7 +823,7 @@ static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
                cx24116_readreg(state, CX24116_REG_QSTATUS));
 
        /* Wait for up to 300 ms */
-       for(i = 0; i < 30 ; i++) {
+       for (i = 0; i < 30 ; i++) {
                if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
                        return 0;
                msleep(10);
@@ -798,20 +834,21 @@ static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
        return -ETIMEDOUT; /* -EBUSY ? */
 }
 
-static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+static int cx24116_set_tone(struct dvb_frontend *fe,
+       fe_sec_tone_mode_t tone)
 {
        struct cx24116_cmd cmd;
        int ret;
 
        dprintk("%s(%d)\n", __func__, tone);
-       if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) {
-               printk("%s: Invalid, tone=%d\n", __func__, tone);
+       if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+               printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
                return -EINVAL;
        }
 
        /* Wait for LNB ready */
        ret = cx24116_wait_for_lnb(fe);
-       if(ret != 0)
+       if (ret != 0)
                return ret;
 
        /* Min delay time after DiSEqC send */
@@ -820,7 +857,7 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
        /* This is always done before the tone is set */
        cmd.args[0x00] = CMD_SET_TONEPRE;
        cmd.args[0x01] = 0x00;
-       cmd.len= 0x02;
+       cmd.len = 0x02;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
@@ -836,11 +873,11 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
                cmd.args[0x03] = 0x01;
                break;
        case SEC_TONE_OFF:
-               dprintk("%s: setting tone off\n",__func__);
+               dprintk("%s: setting tone off\n", __func__);
                cmd.args[0x03] = 0x00;
                break;
        }
-       cmd.len= 0x04;
+       cmd.len = 0x04;
 
        /* Min delay time before DiSEqC send */
        msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
@@ -849,7 +886,7 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 }
 
 /* Initialise DiSEqC */
-static int cx24116_diseqc_init(struct dvb_frontendfe)
+static int cx24116_diseqc_init(struct dvb_frontend *fe)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        struct cx24116_cmd cmd;
@@ -864,7 +901,7 @@ static int cx24116_diseqc_init(struct dvb_frontend* fe)
        cmd.args[0x05] = 0x28;
        cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
        cmd.args[0x07] = 0x01;
-       cmd.len= 0x08;
+       cmd.len = 0x08;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
@@ -878,36 +915,38 @@ static int cx24116_diseqc_init(struct dvb_frontend* fe)
        /* Unknown */
        state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
        state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
-       state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
+       /* Continuation flag? */
+       state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
 
        /* DiSEqC message length */
        state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
 
        /* Command length */
-       state->dsec_cmd.len= CX24116_DISEQC_MSGOFS;
+       state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
 
        return 0;
 }
 
 /* Send DiSEqC message with derived burst (hack) || previous burst */
-static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d)
+static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
+       struct dvb_diseqc_master_cmd *d)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        int i, ret;
 
        /* Dump DiSEqC message */
        if (debug) {
-               printk("cx24116: %s(", __func__);
-               for(i = 0 ; i < d->msg_len ;) {
-                       printk("0x%02x", d->msg[i]);
-                       if(++i < d->msg_len)
-                               printk(", ");
-                       }
+               printk(KERN_INFO "cx24116: %s(", __func__);
+               for (i = 0 ; i < d->msg_len ;) {
+                       printk(KERN_INFO "0x%02x", d->msg[i]);
+                       if (++i < d->msg_len)
+                               printk(KERN_INFO ", ");
+               }
                printk(") toneburst=%d\n", toneburst);
        }
 
        /* Validate length */
-       if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
+       if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
                return -EINVAL;
 
        /* DiSEqC message */
@@ -918,18 +957,19 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
        state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
 
        /* Command length */
-       state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
+       state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
+               state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
 
        /* DiSEqC toneburst */
-       if(toneburst == CX24116_DISEQC_MESGCACHE)
+       if (toneburst == CX24116_DISEQC_MESGCACHE)
                /* Message is cached */
                return 0;
 
-       else if(toneburst == CX24116_DISEQC_TONEOFF)
+       else if (toneburst == CX24116_DISEQC_TONEOFF)
                /* Message is sent without burst */
                state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
 
-       else if(toneburst == CX24116_DISEQC_TONECACHE) {
+       else if (toneburst == CX24116_DISEQC_TONECACHE) {
                /*
                 * Message is sent with derived else cached burst
                 *
@@ -948,15 +988,17 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
                 *              Y = VOLTAGE             (0=13V, 1=18V)
                 *              Z = BAND                (0=LOW, 1=HIGH(22K))
                 */
-               if(d->msg_len >= 4 && d->msg[2] == 0x38)
-                       state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2);
-               if(debug)
-                       dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]);
+               if (d->msg_len >= 4 && d->msg[2] == 0x38)
+                       state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+                               ((d->msg[3] & 4) >> 2);
+               if (debug)
+                       dprintk("%s burst=%d\n", __func__,
+                               state->dsec_cmd.args[CX24116_DISEQC_BURST]);
        }
 
        /* Wait for LNB ready */
        ret = cx24116_wait_for_lnb(fe);
-       if(ret != 0)
+       if (ret != 0)
                return ret;
 
        /* Wait for voltage/min repeat delay */
@@ -964,7 +1006,7 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
 
        /* Command */
        ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
-       if(ret != 0)
+       if (ret != 0)
                return ret;
        /*
         * Wait for send
@@ -976,29 +1018,33 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
         *  12.5ms burst        +
         * >15ms delay            (XXX determine if FW does this, see set_tone)
         */
-       msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) );
+       msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
+               ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
 
        return 0;
 }
 
 /* Send DiSEqC burst */
-static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
+       fe_sec_mini_cmd_t burst)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        int ret;
 
-       dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst);
+       dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
 
        /* DiSEqC burst */
        if (burst == SEC_MINI_A)
-               state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
-       else if(burst == SEC_MINI_B)
-               state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B;
+               state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+                       CX24116_DISEQC_MINI_A;
+       else if (burst == SEC_MINI_B)
+               state->dsec_cmd.args[CX24116_DISEQC_BURST] =
+                       CX24116_DISEQC_MINI_B;
        else
                return -EINVAL;
 
        /* DiSEqC toneburst */
-       if(toneburst != CX24116_DISEQC_MESGCACHE)
+       if (toneburst != CX24116_DISEQC_MESGCACHE)
                /* Burst is cached */
                return 0;
 
@@ -1006,7 +1052,7 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
 
        /* Wait for LNB ready */
        ret = cx24116_wait_for_lnb(fe);
-       if(ret != 0)
+       if (ret != 0)
                return ret;
 
        /* Wait for voltage/min repeat delay */
@@ -1014,7 +1060,7 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
 
        /* Command */
        ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
-       if(ret != 0)
+       if (ret != 0)
                return ret;
 
        /*
@@ -1027,34 +1073,32 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
         *  12.5ms burst        +
         * >15ms delay            (XXX determine if FW does this, see set_tone)
         */
-       msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 );
+       msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
 
        return 0;
 }
 
-static void cx24116_release(struct dvb_frontendfe)
+static void cx24116_release(struct dvb_frontend *fe)
 {
-       struct cx24116_statestate = fe->demodulator_priv;
-       dprintk("%s\n",__func__);
+       struct cx24116_state *state = fe->demodulator_priv;
+       dprintk("%s\n", __func__);
        kfree(state);
 }
 
 static struct dvb_frontend_ops cx24116_ops;
 
-struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
-                                   struct i2c_adapter* i2c)
+struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
+       struct i2c_adapter *i2c)
 {
-       struct cx24116_statestate = NULL;
+       struct cx24116_state *state = NULL;
        int ret;
 
-       dprintk("%s\n",__func__);
+       dprintk("%s\n", __func__);
 
        /* allocate memory for the internal state */
        state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
-       if (state == NULL) {
-               printk("Unable to kmalloc\n");
+       if (state == NULL)
                goto error1;
-       }
 
        /* setup the state */
        memset(state, 0, sizeof(struct cx24116_state));
@@ -1063,32 +1107,36 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
        state->i2c = i2c;
 
        /* check if the demod is present */
-       ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
+       ret = (cx24116_readreg(state, 0xFF) << 8) |
+               cx24116_readreg(state, 0xFE);
        if (ret != 0x0501) {
-               printk("Invalid probe, probably not a CX24116 device\n");
+               printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
                goto error2;
        }
 
        /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
+       memcpy(&state->frontend.ops, &cx24116_ops,
+               sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
 error2: kfree(state);
 error1: return NULL;
 }
+EXPORT_SYMBOL(cx24116_attach);
+
 /*
  * Initialise or wake up device
  *
  * Power config will reset and load initial firmware if required
  */
-static int cx24116_initfe(struct dvb_frontendfe)
+static int cx24116_initfe(struct dvb_frontend *fe)
 {
-       struct cx24116_statestate = fe->demodulator_priv;
+       struct cx24116_state *state = fe->demodulator_priv;
        struct cx24116_cmd cmd;
        int ret;
 
-       dprintk("%s()\n",__func__);
+       dprintk("%s()\n", __func__);
 
        /* Power on */
        cx24116_writereg(state, 0xe0, 0);
@@ -1098,9 +1146,9 @@ static int cx24116_initfe(struct dvb_frontend* fe)
        /* Firmware CMD 36: Power config */
        cmd.args[0x00] = CMD_TUNERSLEEP;
        cmd.args[0x01] = 0;
-       cmd.len= 0x02;
+       cmd.len = 0x02;
        ret = cx24116_cmd_execute(fe, &cmd);
-       if(ret != 0)
+       if (ret != 0)
                return ret;
 
        return cx24116_diseqc_init(fe);
@@ -1109,20 +1157,20 @@ static int cx24116_initfe(struct dvb_frontend* fe)
 /*
  * Put device to sleep
  */
-static int cx24116_sleep(struct dvb_frontendfe)
+static int cx24116_sleep(struct dvb_frontend *fe)
 {
-       struct cx24116_statestate = fe->demodulator_priv;
+       struct cx24116_state *state = fe->demodulator_priv;
        struct cx24116_cmd cmd;
        int ret;
 
-       dprintk("%s()\n",__func__);
+       dprintk("%s()\n", __func__);
 
        /* Firmware CMD 36: Power config */
        cmd.args[0x00] = CMD_TUNERSLEEP;
        cmd.args[0x01] = 1;
-       cmd.len= 0x02;
+       cmd.len = 0x02;
        ret = cx24116_cmd_execute(fe, &cmd);
-       if(ret != 0)
+       if (ret != 0)
                return ret;
 
        /* Power off (Shutdown clocks) */
@@ -1133,13 +1181,15 @@ static int cx24116_sleep(struct dvb_frontend* fe)
        return 0;
 }
 
-static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+static int cx24116_set_property(struct dvb_frontend *fe,
+       struct dtv_property *tvp)
 {
        dprintk("%s(..)\n", __func__);
        return 0;
 }
 
-static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+static int cx24116_get_property(struct dvb_frontend *fe,
+       struct dtv_property *tvp)
 {
        dprintk("%s(..)\n", __func__);
        return 0;
@@ -1148,7 +1198,8 @@ static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tv
 /* dvb-core told us to tune, the tv property cache will be complete,
  * it's safe for is to pull values and use them for tuning purposes.
  */
-static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24116_set_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1156,96 +1207,102 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        fe_status_t tunerstat;
        int i, status, ret, retune;
 
-       dprintk("%s()\n",__func__);
+       dprintk("%s()\n", __func__);
 
-       switch(c->delivery_system) {
-               case SYS_DVBS:
-                       dprintk("%s: DVB-S delivery system selected\n",__func__);
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               dprintk("%s: DVB-S delivery system selected\n", __func__);
 
-                       /* Only QPSK is supported for DVB-S */
-                       if(c->modulation != QPSK) {
-                               dprintk("%s: unsupported modulation selected (%d)\n",
-                                       __func__, c->modulation);
-                               return -EOPNOTSUPP;
-                       }
+               /* Only QPSK is supported for DVB-S */
+               if (c->modulation != QPSK) {
+                       dprintk("%s: unsupported modulation selected (%d)\n",
+                               __func__, c->modulation);
+                       return -EOPNOTSUPP;
+               }
 
-                       /* Pilot doesn't exist in DVB-S, turn bit off */
-                       state->dnxt.pilot_val = CX24116_PILOT_OFF;
-                       retune = 1;
+               /* Pilot doesn't exist in DVB-S, turn bit off */
+               state->dnxt.pilot_val = CX24116_PILOT_OFF;
+               retune = 1;
 
-                       /* DVB-S only supports 0.35 */
-                       if(c->rolloff != ROLLOFF_35) {
-                               dprintk("%s: unsupported rolloff selected (%d)\n",
-                                       __func__, c->rolloff);
-                               return -EOPNOTSUPP;
-                       }
-                       state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
-                       break;
+               /* DVB-S only supports 0.35 */
+               if (c->rolloff != ROLLOFF_35) {
+                       dprintk("%s: unsupported rolloff selected (%d)\n",
+                               __func__, c->rolloff);
+                       return -EOPNOTSUPP;
+               }
+               state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+               break;
 
-               case SYS_DVBS2:
-                       dprintk("%s: DVB-S2 delivery system selected\n",__func__);
-
-                       /*
-                        * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
-                        * but not hardware auto detection
-                        */
-                       if(c->modulation != PSK_8 && c->modulation != QPSK) {
-                               dprintk("%s: unsupported modulation selected (%d)\n",
-                                       __func__, c->modulation);
-                               return -EOPNOTSUPP;
-                       }
+       case SYS_DVBS2:
+               dprintk("%s: DVB-S2 delivery system selected\n", __func__);
 
-                       switch(c->pilot) {
-                               case PILOT_AUTO:        /* Not supported but emulated */
-                                       retune = 2;     /* Fall-through */
-                               case PILOT_OFF:
-                                       state->dnxt.pilot_val = CX24116_PILOT_OFF;
-                                       break;
-                               case PILOT_ON:
-                                       state->dnxt.pilot_val = CX24116_PILOT_ON;
-                                       break;
-                               default:
-                                       dprintk("%s: unsupported pilot mode selected (%d)\n",
-                                               __func__, c->pilot);
-                                       return -EOPNOTSUPP;
-                       }
+               /*
+                * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
+                * but not hardware auto detection
+                */
+               if (c->modulation != PSK_8 && c->modulation != QPSK) {
+                       dprintk("%s: unsupported modulation selected (%d)\n",
+                               __func__, c->modulation);
+                       return -EOPNOTSUPP;
+               }
 
-                       switch(c->rolloff) {
-                               case ROLLOFF_20:
-                                       state->dnxt.rolloff_val= CX24116_ROLLOFF_020;
-                                       break;
-                               case ROLLOFF_25:
-                                       state->dnxt.rolloff_val= CX24116_ROLLOFF_025;
-                                       break;
-                               case ROLLOFF_35:
-                                       state->dnxt.rolloff_val= CX24116_ROLLOFF_035;
-                                       break;
-                               case ROLLOFF_AUTO:      /* Rolloff must be explicit */
-                               default:
-                                       dprintk("%s: unsupported rolloff selected (%d)\n",
-                                               __func__, c->rolloff);
-                                       return -EOPNOTSUPP;
-                       }
+               switch (c->pilot) {
+               case PILOT_AUTO:        /* Not supported but emulated */
+                       state->dnxt.pilot_val = (c->modulation == QPSK)
+                               ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
+                       retune = 2;
+                       break;
+               case PILOT_OFF:
+                       state->dnxt.pilot_val = CX24116_PILOT_OFF;
+                       break;
+               case PILOT_ON:
+                       state->dnxt.pilot_val = CX24116_PILOT_ON;
                        break;
+               default:
+                       dprintk("%s: unsupported pilot mode selected (%d)\n",
+                               __func__, c->pilot);
+                       return -EOPNOTSUPP;
+               }
 
+               switch (c->rolloff) {
+               case ROLLOFF_20:
+                       state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
+                       break;
+               case ROLLOFF_25:
+                       state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
+                       break;
+               case ROLLOFF_35:
+                       state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+                       break;
+               case ROLLOFF_AUTO:      /* Rolloff must be explicit */
                default:
-                       dprintk("%s: unsupported delivery system selected (%d)\n",
-                               __func__, c->delivery_system);
+                       dprintk("%s: unsupported rolloff selected (%d)\n",
+                               __func__, c->rolloff);
                        return -EOPNOTSUPP;
+               }
+               break;
+
+       default:
+               dprintk("%s: unsupported delivery system selected (%d)\n",
+                       __func__, c->delivery_system);
+               return -EOPNOTSUPP;
        }
        state->dnxt.modulation = c->modulation;
        state->dnxt.frequency = c->frequency;
        state->dnxt.pilot = c->pilot;
        state->dnxt.rolloff = c->rolloff;
 
-       if ((ret = cx24116_set_inversion(state, c->inversion)) !=  0)
+       ret = cx24116_set_inversion(state, c->inversion);
+       if (ret !=  0)
                return ret;
 
        /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
-       if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) !=  0)
+       ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
+       if (ret !=  0)
                return ret;
 
-       if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) !=  0)
+       ret = cx24116_set_symbolrate(state, c->symbol_rate);
+       if (ret !=  0)
                return ret;
 
        /* discard the 'current' tuning parameters and prepare to tune */
@@ -1271,7 +1328,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        /* Set/Reset B/W */
        cmd.args[0x00] = CMD_BANDWIDTH;
        cmd.args[0x01] = 0x01;
-       cmd.len= 0x02;
+       cmd.len = 0x02;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
@@ -1319,7 +1376,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
                cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
        }
 
-       cmd.len= 0x13;
+       cmd.len = 0x13;
 
        /* We need to support pilot and non-pilot tuning in the
         * driver automatically. This is a workaround for because
@@ -1327,12 +1384,13 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
         */
        do {
                /* Reset status register */
-               status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK;
+               status = cx24116_readreg(state, CX24116_REG_SSTATUS)
+                       & CX24116_SIGNAL_MASK;
                cx24116_writereg(state, CX24116_REG_SSTATUS, status);
 
                /* Tune */
                ret = cx24116_cmd_execute(fe, &cmd);
-               if( ret != 0 )
+               if (ret != 0)
                        break;
 
                /*
@@ -1341,28 +1399,27 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
                 * If we are able to tune then generally it occurs within 100ms.
                 * If it takes longer, try a different toneburst setting.
                 */
-               for(i = 0; i < 50 ; i++) {
+               for (i = 0; i < 50 ; i++) {
                        cx24116_read_status(fe, &tunerstat);
                        status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
-                       if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
-                               dprintk("%s: Tuned\n",__func__);
+                       if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
+                               dprintk("%s: Tuned\n", __func__);
                                goto tuned;
                        }
                        msleep(10);
                }
 
-               dprintk("%s: Not tuned\n",__func__);
+               dprintk("%s: Not tuned\n", __func__);
 
                /* Toggle pilot bit when in auto-pilot */
-               if(state->dcur.pilot == PILOT_AUTO)
+               if (state->dcur.pilot == PILOT_AUTO)
                        cmd.args[0x07] ^= CX24116_PILOT_ON;
-       }
-       while(--retune);
+       } while (--retune);
 
 tuned:  /* Set/Reset B/W */
        cmd.args[0x00] = CMD_BANDWIDTH;
        cmd.args[0x01] = 0x00;
-       cmd.len= 0x02;
+       cmd.len = 0x02;
        ret = cx24116_cmd_execute(fe, &cmd);
        if (ret != 0)
                return ret;
@@ -1407,17 +1464,7 @@ static struct dvb_frontend_ops cx24116_ops = {
        .set_frontend = cx24116_set_frontend,
 };
 
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-module_param(toneburst, int, 0644);
-MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
-
-module_param(esno_snr, int, 0644);
-MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)");
-
 MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
 MODULE_AUTHOR("Steven Toth");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(cx24116_attach);
index 8dbcec268394eb7030b8dcae1c45c5f55d78dfed..4cb3ddd6c6261f7ce3c15d96550b2c56832ce651 100644 (file)
 
 #include <linux/dvb/frontend.h>
 
-struct cx24116_config
-{
+struct cx24116_config {
        /* the demodulator's i2c address */
        u8 demod_address;
 
        /* Need to set device param for start_dma */
-       int (*set_ts_params)(struct dvb_frontendfe, int is_punctured);
+       int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 
        /* Need to reset device during firmware loading */
-       int (*reset_device)(struct dvb_frontendfe);
+       int (*reset_device)(struct dvb_frontend *fe);
 
        /* Need to set MPEG parameters */
        u8 mpg_clk_pos_pol:0x02;
 };
 
 #if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE)
-extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
-                                          struct i2c_adapter* i2c);
+extern struct dvb_frontend *cx24116_attach(
+       const struct cx24116_config *config,
+       struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
-                                                 struct i2c_adapter* i2c)
+static inline struct dvb_frontend *cx24116_attach(
+       const struct cx24116_config *config,
+       struct i2c_adapter *i2c)
 {
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-#endif // CONFIG_DVB_CX24116
+#endif
 
 #endif /* CX24116_H */
index 7156157cb34b2ec9f06c9af3b17e14e84d460f82..1a8c36f76061a83d6df460eec40eae4342bce299 100644 (file)
 #define XTAL 10111000
 
 static int force_band;
+module_param(force_band, int, 0644);
+MODULE_PARM_DESC(force_band, "Force a specific band select "\
+       "(1-9, default:off).");
+
 static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
 
 #define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0)
 #define err(args...)  do { printk(KERN_ERR  "CX24123: " args); } while (0)
@@ -46,10 +52,9 @@ static int debug;
                } \
        } while (0)
 
-struct cx24123_state
-{
-       struct i2c_adapter* i2c;
-       const struct cx24123_config* config;
+struct cx24123_state {
+       struct i2c_adapter *i2c;
+       const struct cx24123_config *config;
 
        struct dvb_frontend frontend;
 
@@ -70,8 +75,7 @@ struct cx24123_state
 };
 
 /* Various tuner defaults need to be established for a given symbol rate Sps */
-static struct
-{
+static struct cx24123_AGC_val {
        u32 symbolrate_low;
        u32 symbolrate_high;
        u32 VCAprogdata;
@@ -109,8 +113,7 @@ static struct
  * fixme: The bounds on the bands do not match the doc in real life.
  * fixme: Some of them have been moved, other might need adjustment.
  */
-static struct
-{
+static struct cx24123_bandselect_val {
        u32 freq_low;
        u32 freq_high;
        u32 VCOdivider;
@@ -249,7 +252,8 @@ static int cx24123_i2c_writereg(struct cx24123_state *state,
 
        /* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */
 
-       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+       err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1) {
                printk("%s: writereg error(err == %i, reg == 0x%02x,"
                         " data == 0x%02x)\n", __func__, err, reg, data);
                return err;
@@ -284,7 +288,8 @@ static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg)
 #define cx24123_writereg(state, reg, val) \
        cx24123_i2c_writereg(state, state->config->demod_address, reg, val)
 
-static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
+static int cx24123_set_inversion(struct cx24123_state *state,
+       fe_spectral_inversion_t inversion)
 {
        u8 nom_reg = cx24123_readreg(state, 0x0e);
        u8 auto_reg = cx24123_readreg(state, 0x10);
@@ -311,7 +316,8 @@ static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_invers
        return 0;
 }
 
-static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion)
+static int cx24123_get_inversion(struct cx24123_state *state,
+       fe_spectral_inversion_t *inversion)
 {
        u8 val;
 
@@ -328,18 +334,20 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers
        return 0;
 }
 
-static int cx24123_set_fec(struct cx24123_statestate, fe_code_rate_t fec)
+static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec)
 {
        u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07;
 
-       if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
+       if ((fec < FEC_NONE) || (fec > FEC_AUTO))
                fec = FEC_AUTO;
 
        /* Set the soft decision threshold */
-       if(fec == FEC_1_2)
-               cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) | 0x01);
+       if (fec == FEC_1_2)
+               cx24123_writereg(state, 0x43,
+                       cx24123_readreg(state, 0x43) | 0x01);
        else
-               cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) & ~0x01);
+               cx24123_writereg(state, 0x43,
+                       cx24123_readreg(state, 0x43) & ~0x01);
 
        switch (fec) {
        case FEC_1_2:
@@ -388,11 +396,11 @@ static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
        return 0;
 }
 
-static int cx24123_get_fec(struct cx24123_statestate, fe_code_rate_t *fec)
+static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec)
 {
        int ret;
 
-       ret = cx24123_readreg (state, 0x1b);
+       ret = cx24123_readreg(state, 0x1b);
        if (ret < 0)
                return ret;
        ret = ret & 0x07;
@@ -433,16 +441,16 @@ static u32 cx24123_int_log2(u32 a, u32 b)
 {
        u32 exp, nearest = 0;
        u32 div = a / b;
-       if(a % b >= b / 2) ++div;
-       if(div < (1 << 31))
-       {
-               for(exp = 1; div > exp; nearest++)
+       if (a % b >= b / 2)
+               ++div;
+       if (div < (1 << 31)) {
+               for (exp = 1; div > exp; nearest++)
                        exp += exp;
        }
        return nearest;
 }
 
-static int cx24123_set_symbolrate(struct cx24123_statestate, u32 srate)
+static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
 {
        u32 tmp, sample_rate, ratio, sample_gain;
        u8 pll_mult;
@@ -498,9 +506,9 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
 
        cx24123_writereg(state, 0x01, pll_mult * 6);
 
-       cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f );
-       cx24123_writereg(state, 0x09, (ratio >>  8) & 0xff );
-       cx24123_writereg(state, 0x0a, (ratio      ) & 0xff );
+       cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f);
+       cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff);
+       cx24123_writereg(state, 0x0a, ratio & 0xff);
 
        /* also set the demodulator sample gain */
        sample_gain = cx24123_int_log2(sample_rate, srate);
@@ -514,10 +522,12 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
 }
 
 /*
- * Based on the required frequency and symbolrate, the tuner AGC has to be configured
- * and the correct band selected. Calculate those values
+ * Based on the required frequency and symbolrate, the tuner AGC has
+ * to be configured and the correct band selected.
+ * Calculate those values.
  */
-static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_pll_calculate(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        u32 ndiv = 0, adiv = 0, vco_div = 0;
@@ -525,6 +535,8 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
        int pump = 2;
        int band = 0;
        int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
+       struct cx24123_bandselect_val *bsv = NULL;
+       struct cx24123_AGC_val *agcv = NULL;
 
        /* Defaults for low freq, low rate */
        state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
@@ -532,58 +544,65 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
        state->bandselectarg = cx24123_bandselect_vals[0].progdata;
        vco_div = cx24123_bandselect_vals[0].VCOdivider;
 
-       /* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */
-       for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++)
-       {
-               if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
-                   (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
-                       state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
-                       state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
-                       state->FILTune = cx24123_AGC_vals[i].FILTune;
+       /* For the given symbol rate, determine the VCA, VGA and
+        * FILTUNE programming bits */
+       for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) {
+               agcv = &cx24123_AGC_vals[i];
+               if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) &&
+                   (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) {
+                       state->VCAarg = agcv->VCAprogdata;
+                       state->VGAarg = agcv->VGAprogdata;
+                       state->FILTune = agcv->FILTune;
                }
        }
 
        /* determine the band to use */
-       if(force_band < 1 || force_band > num_bands)
-       {
-               for (i = 0; i < num_bands; i++)
-               {
-                       if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
-                           (cx24123_bandselect_vals[i].freq_high >= p->frequency) )
+       if (force_band < 1 || force_band > num_bands) {
+               for (i = 0; i < num_bands; i++) {
+                       bsv = &cx24123_bandselect_vals[i];
+                       if ((bsv->freq_low <= p->frequency) &&
+                               (bsv->freq_high >= p->frequency))
                                band = i;
                }
-       }
-       else
+       } else
                band = force_band - 1;
 
        state->bandselectarg = cx24123_bandselect_vals[band].progdata;
        vco_div = cx24123_bandselect_vals[band].VCOdivider;
 
        /* determine the charge pump current */
-       if ( p->frequency < (cx24123_bandselect_vals[band].freq_low + cx24123_bandselect_vals[band].freq_high)/2 )
+       if (p->frequency < (cx24123_bandselect_vals[band].freq_low +
+               cx24123_bandselect_vals[band].freq_high) / 2)
                pump = 0x01;
        else
                pump = 0x02;
 
        /* Determine the N/A dividers for the requested lband freq (in kHz). */
-       /* Note: the reference divider R=10, frequency is in KHz, XTAL is in Hz */
-       ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff;
-       adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f;
+       /* Note: the reference divider R=10, frequency is in KHz,
+        * XTAL is in Hz */
+       ndiv = (((p->frequency * vco_div * 10) /
+               (2 * XTAL / 1000)) / 32) & 0x1ff;
+       adiv = (((p->frequency * vco_div * 10) /
+               (2 * XTAL / 1000)) % 32) & 0x1f;
 
        if (adiv == 0 && ndiv > 0)
                ndiv--;
 
-       /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */
-       state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv;
+       /* control bits 11, refdiv 11, charge pump polarity 1,
+        * charge pump current, ndiv, adiv */
+       state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) |
+               (pump << 14) | (ndiv << 5) | adiv;
 
        return 0;
 }
 
 /*
  * Tuner data is 21 bits long, must be left-aligned in data.
- * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip.
+ * Tuner cx24109 is written through a dedicated 3wire interface
+ * on the demod chip.
  */
-static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data)
+static int cx24123_pll_writereg(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p, u32 data)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        unsigned long timeout;
@@ -610,7 +629,7 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
 
        /* send another 8 bytes, wait for the send to be completed */
        timeout = jiffies + msecs_to_jiffies(40);
-       cx24123_writereg(state, 0x22, (data>>8) & 0xff );
+       cx24123_writereg(state, 0x22, (data >> 8) & 0xff);
        while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
                if (time_after(jiffies, timeout)) {
                        err("%s:  demodulator is not responding, "\
@@ -620,9 +639,10 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
                msleep(10);
        }
 
-       /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */
+       /* send the lower 5 bits of this byte, padded with 3 LBB,
+        * wait for the send to be completed */
        timeout = jiffies + msecs_to_jiffies(40);
-       cx24123_writereg(state, 0x22, (data) & 0xff );
+       cx24123_writereg(state, 0x22, (data) & 0xff);
        while ((cx24123_readreg(state, 0x20) & 0x80)) {
                if (time_after(jiffies, timeout)) {
                        err("%s:  demodulator is not responding," \
@@ -639,7 +659,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
        return 0;
 }
 
-static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_pll_tune(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
@@ -690,7 +711,7 @@ static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start)
        return cx24123_writereg(state, 0x23, r);
 }
 
-static int cx24123_initfe(struct dvb_frontendfe)
+static int cx24123_initfe(struct dvb_frontend *fe)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        int i;
@@ -699,19 +720,22 @@ static int cx24123_initfe(struct dvb_frontend* fe)
 
        /* Configure the demod to a good set of defaults */
        for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
-               cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
+               cx24123_writereg(state, cx24123_regdata[i].reg,
+                       cx24123_regdata[i].data);
 
        /* Set the LNB polarity */
-       if(state->config->lnb_polarity)
-               cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02);
+       if (state->config->lnb_polarity)
+               cx24123_writereg(state, 0x32,
+                       cx24123_readreg(state, 0x32) | 0x02);
 
        if (state->config->dont_use_pll)
-       cx24123_repeater_mode(state, 1, 0);
+               cx24123_repeater_mode(state, 1, 0);
 
        return 0;
 }
 
-static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+static int cx24123_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t voltage)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
@@ -740,7 +764,7 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(200);
        while (!(cx24123_readreg(state, 0x29) & 0x40)) {
-               if(time_after(jiffies, timeout)) {
+               if (time_after(jiffies, timeout)) {
                        err("%s: diseqc queue not ready, " \
                                "command may be lost.\n", __func__);
                        break;
@@ -749,7 +773,8 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
        }
 }
 
-static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
+static int cx24123_send_diseqc_msg(struct dvb_frontend *fe,
+       struct dvb_diseqc_master_cmd *cmd)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        int i, val, tone;
@@ -771,20 +796,21 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
                cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
 
        val = cx24123_readreg(state, 0x29);
-       cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
+       cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) |
+               ((cmd->msg_len-3) & 3));
 
        /* wait for diseqc message to finish sending */
        cx24123_wait_for_diseqc(state);
 
        /* restart continuous tone if enabled */
-       if (tone & 0x10) {
+       if (tone & 0x10)
                cx24123_writereg(state, 0x29, tone & ~0x40);
-       }
 
        return 0;
 }
 
-static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+static int cx24123_diseqc_send_burst(struct dvb_frontend *fe,
+       fe_sec_mini_cmd_t burst)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        int val, tone;
@@ -814,13 +840,13 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
        cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
        /* restart continuous tone if enabled */
-       if (tone & 0x10) {
+       if (tone & 0x10)
                cx24123_writereg(state, 0x29, tone & ~0x40);
-       }
+
        return 0;
 }
 
-static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        int sync = cx24123_readreg(state, 0x14);
@@ -853,8 +879,9 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
 }
 
 /*
- * Configured to return the measurement of errors in blocks, because no UCBLOCKS value
- * is available, so this value doubles up to satisfy both measurements
+ * Configured to return the measurement of errors in blocks,
+ * because no UCBLOCKS value is available, so this value doubles up
+ * to satisfy both measurements.
  */
 static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
@@ -876,7 +903,8 @@ static int cx24123_read_signal_strength(struct dvb_frontend *fe,
 {
        struct cx24123_state *state = fe->demodulator_priv;
 
-       *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+       /* larger = better */
+       *signal_strength = cx24123_readreg(state, 0x3b) << 8;
 
        dprintk("Signal strength = %d\n", *signal_strength);
 
@@ -907,7 +935,7 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
        if (state->config->set_ts_params)
                state->config->set_ts_params(fe, 0);
 
-       state->currentfreq=p->frequency;
+       state->currentfreq = p->frequency;
        state->currentsymbolrate = p->u.qpsk.symbol_rate;
 
        cx24123_set_inversion(state, p->inversion);
@@ -932,7 +960,8 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
        return 0;
 }
 
-static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_get_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
 {
        struct cx24123_state *state = fe->demodulator_priv;
 
@@ -952,7 +981,7 @@ static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        return 0;
 }
 
-static int cx24123_set_tone(struct dvb_frontendfe, fe_sec_tone_mode_t tone)
+static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
@@ -977,8 +1006,8 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
        return 0;
 }
 
-static int cx24123_tune(struct dvb_frontendfe,
-                       struct dvb_frontend_parametersparams,
+static int cx24123_tune(struct dvb_frontend *fe,
+                       struct dvb_frontend_parameters *params,
                        unsigned int mode_flags,
                        unsigned int *delay,
                        fe_status_t *status)
@@ -997,12 +1026,12 @@ static int cx24123_tune(struct dvb_frontend* fe,
 
 static int cx24123_get_algo(struct dvb_frontend *fe)
 {
-       return 1; //FE_ALGO_HW
+       return 1; /* FE_ALGO_HW */
 }
 
-static void cx24123_release(struct dvb_frontendfe)
+static void cx24123_release(struct dvb_frontend *fe)
 {
-       struct cx24123_statestate = fe->demodulator_priv;
+       struct cx24123_state *state = fe->demodulator_priv;
        dprintk("\n");
        i2c_del_adapter(&state->tuner_i2c_adapter);
        kfree(state);
@@ -1013,7 +1042,7 @@ static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap,
 {
        struct cx24123_state *state = i2c_get_adapdata(i2c_adap);
        /* this repeater closes after the first stop */
-    cx24123_repeater_mode(state, 1, 1);
+       cx24123_repeater_mode(state, 1, 1);
        return i2c_transfer(state->i2c, msg, num);
 }
 
@@ -1037,8 +1066,8 @@ EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter);
 
 static struct dvb_frontend_ops cx24123_ops;
 
-struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
-                                   struct i2c_adapteri2c)
+struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
+                                   struct i2c_adapter *i2c)
 {
        struct cx24123_state *state =
                kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
@@ -1057,20 +1086,25 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
        /* check if the demod is there */
        state->demod_rev = cx24123_readreg(state, 0x00);
        switch (state->demod_rev) {
-       case 0xe1: info("detected CX24123C\n"); break;
-       case 0xd1: info("detected CX24123\n"); break;
+       case 0xe1:
+               info("detected CX24123C\n");
+               break;
+       case 0xd1:
+               info("detected CX24123\n");
+               break;
        default:
                err("wrong demod revision: %x\n", state->demod_rev);
                goto error;
        }
 
        /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
+       memcpy(&state->frontend.ops, &cx24123_ops,
+               sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
-    /* create tuner i2c adapter */
-    if (config->dont_use_pll)
-       cx24123_repeater_mode(state, 1, 0);
+       /* create tuner i2c adapter */
+       if (config->dont_use_pll)
+               cx24123_repeater_mode(state, 1, 0);
 
        strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
                sizeof(state->tuner_i2c_adapter.name));
@@ -1079,7 +1113,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
        state->tuner_i2c_adapter.algo_data = NULL;
        i2c_set_adapdata(&state->tuner_i2c_adapter, state);
        if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
-       err("tuner i2c bus could not be initialized\n");
+               err("tuner i2c bus could not be initialized\n");
                goto error;
        }
 
@@ -1090,6 +1124,7 @@ error:
 
        return NULL;
 }
+EXPORT_SYMBOL(cx24123_attach);
 
 static struct dvb_frontend_ops cx24123_ops = {
 
@@ -1126,15 +1161,8 @@ static struct dvb_frontend_ops cx24123_ops = {
        .get_frontend_algo = cx24123_get_algo,
 };
 
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
-module_param(force_band, int, 0644);
-MODULE_PARM_DESC(force_band, "Force a specific band select (1-9, default:off).");
-
 MODULE_DESCRIPTION("DVB Frontend module for Conexant " \
        "CX24123/CX24109/CX24113 hardware");
 MODULE_AUTHOR("Steven Toth");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(cx24123_attach);
index cc6b411d6d20ba76da2a535ad103f854eec71690..51ae866e9fed631df412eaeb44866439c5137a68 100644 (file)
 
 #include <linux/dvb/frontend.h>
 
-struct cx24123_config
-{
+struct cx24123_config {
        /* the demodulator's i2c address */
        u8 demod_address;
 
        /* Need to set device param for start_dma */
-       int (*set_ts_params)(struct dvb_frontendfe, int is_punctured);
+       int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 
        /* 0 = LNB voltage normal, 1 = LNB voltage inverted */
        int lnb_polarity;
@@ -39,7 +38,8 @@ struct cx24123_config
        void (*agc_callback) (struct dvb_frontend *);
 };
 
-#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) && defined(MODULE))
+#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \
+       && defined(MODULE))
 extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
                                           struct i2c_adapter *i2c);
 extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
@@ -56,6 +56,6 @@ static struct i2c_adapter *
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-#endif // CONFIG_DVB_CX24123
+#endif
 
 #endif /* CX24123_H */
index 7500a1c53e68b50cef235c1e1ef1d73b21836f84..cf4d8936bb83f515b49cbb300c9a892bb24a28fb 100644 (file)
 
 struct s5h1409_state {
 
-       struct i2c_adapteri2c;
+       struct i2c_adapter *i2c;
 
        /* configuration settings */
-       const struct s5h1409_configconfig;
+       const struct s5h1409_config *config;
 
        struct dvb_frontend frontend;
 
@@ -48,6 +48,9 @@ struct s5h1409_state {
 };
 
 static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
 #define dprintk        if (debug) printk
 
 /* Register values to initialise the demod, this will set VSB by default */
@@ -299,10 +302,10 @@ static struct qam256_snr_tab {
 };
 
 /* 8 bit registers, 16 bit values */
-static int s5h1409_writereg(struct s5h1409_statestate, u8 reg, u16 data)
+static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data)
 {
        int ret;
-       u8 buf [] = { reg, data >> 8,  data & 0xff };
+       u8 buf[] = { reg, data >> 8,  data & 0xff };
 
        struct i2c_msg msg = { .addr = state->config->demod_address,
                               .flags = 0, .buf = buf, .len = 3 };
@@ -310,19 +313,19 @@ static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
        ret = i2c_transfer(state->i2c, &msg, 1);
 
        if (ret != 1)
-               printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+               printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, "
                       "ret == %i)\n", __func__, reg, data, ret);
 
        return (ret != 1) ? -1 : 0;
 }
 
-static u16 s5h1409_readreg(struct s5h1409_statestate, u8 reg)
+static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg)
 {
        int ret;
-       u8 b0 [] = { reg };
-       u8 b1 [] = { 0, 0 };
+       u8 b0[] = { reg };
+       u8 b1[] = { 0, 0 };
 
-       struct i2c_msg msg [] = {
+       struct i2c_msg msg[] = {
                { .addr = state->config->demod_address, .flags = 0,
                  .buf = b0, .len = 1 },
                { .addr = state->config->demod_address, .flags = I2C_M_RD,
@@ -335,9 +338,9 @@ static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
        return (b1[0] << 8) | b1[1];
 }
 
-static int s5h1409_softreset(struct dvb_frontendfe)
+static int s5h1409_softreset(struct dvb_frontend *fe)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s()\n", __func__);
 
@@ -349,11 +352,11 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
 }
 
 #define S5H1409_VSB_IF_FREQ 5380
-#define S5H1409_QAM_IF_FREQ state->config->qam_if
+#define S5H1409_QAM_IF_FREQ (state->config->qam_if)
 
-static int s5h1409_set_if_freq(struct dvb_frontendfe, int KHz)
+static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(%d KHz)\n", __func__, KHz);
 
@@ -376,26 +379,26 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
        return 0;
 }
 
-static int s5h1409_set_spectralinversion(struct dvb_frontendfe, int inverted)
+static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(%d)\n", __func__, inverted);
 
-       if(inverted == 1)
+       if (inverted == 1)
                return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
        else
                return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
 }
 
-static int s5h1409_enable_modulation(struct dvb_frontendfe,
+static int s5h1409_enable_modulation(struct dvb_frontend *fe,
                                     fe_modulation_t m)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(0x%08x)\n", __func__, m);
 
-       switch(m) {
+       switch (m) {
        case VSB_8:
                dprintk("%s() VSB_8\n", __func__);
                if (state->if_freq != S5H1409_VSB_IF_FREQ)
@@ -422,9 +425,9 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
        return 0;
 }
 
-static int s5h1409_i2c_gate_ctrl(struct dvb_frontendfe, int enable)
+static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(%d)\n", __func__, enable);
 
@@ -434,9 +437,9 @@ static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
                return s5h1409_writereg(state, 0xf3, 0);
 }
 
-static int s5h1409_set_gpio(struct dvb_frontendfe, int enable)
+static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(%d)\n", __func__, enable);
 
@@ -448,18 +451,18 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
                        s5h1409_readreg(state, 0xe3) & 0xfeff);
 }
 
-static int s5h1409_sleep(struct dvb_frontendfe, int enable)
+static int s5h1409_sleep(struct dvb_frontend *fe, int enable)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(%d)\n", __func__, enable);
 
        return s5h1409_writereg(state, 0xf2, enable);
 }
 
-static int s5h1409_register_reset(struct dvb_frontendfe)
+static int s5h1409_register_reset(struct dvb_frontend *fe)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s()\n", __func__);
 
@@ -483,7 +486,7 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
                reg &= 0xff;
 
                s5h1409_writereg(state, 0x96, 0x00c);
-               if ((reg < 0x38) || (reg > 0x68) ) {
+               if ((reg < 0x38) || (reg > 0x68)) {
                        s5h1409_writereg(state, 0x93, 0x3332);
                        s5h1409_writereg(state, 0x9e, 0x2c37);
                } else {
@@ -514,7 +517,7 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
 
                        s5h1409_writereg(state, 0x96, 0x20);
                        s5h1409_writereg(state, 0xad,
-                               ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
+                               (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
                        s5h1409_writereg(state, 0xab,
                                s5h1409_readreg(state, 0xab) & 0xeffe);
                }
@@ -529,10 +532,10 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1409_set_frontend (struct dvb_frontend* fe,
+static int s5h1409_set_frontend(struct dvb_frontend *fe,
                                 struct dvb_frontend_parameters *p)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(frequency=%d)\n", __func__, p->frequency);
 
@@ -546,9 +549,11 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
        msleep(100);
 
        if (fe->ops.tuner_ops.set_params) {
-               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
                fe->ops.tuner_ops.set_params(fe, p);
-               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        /* Optimize the demod for QAM */
@@ -592,17 +597,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
 
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
-static int s5h1409_init (struct dvb_frontend* fe)
+static int s5h1409_init(struct dvb_frontend *fe)
 {
        int i;
 
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
        dprintk("%s()\n", __func__);
 
        s5h1409_sleep(fe, 0);
        s5h1409_register_reset(fe);
 
-       for (i=0; i < ARRAY_SIZE(init_tab); i++)
+       for (i = 0; i < ARRAY_SIZE(init_tab); i++)
                s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
 
        /* The datasheet says that after initialisation, VSB is default */
@@ -627,9 +632,9 @@ static int s5h1409_init (struct dvb_frontend* fe)
        return 0;
 }
 
-static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
        u16 reg;
        u32 tuner_status = 0;
 
@@ -637,12 +642,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
 
        /* Get the demodulator status */
        reg = s5h1409_readreg(state, 0xf1);
-       if(reg & 0x1000)
+       if (reg & 0x1000)
                *status |= FE_HAS_VITERBI;
-       if(reg & 0x8000)
+       if (reg & 0x8000)
                *status |= FE_HAS_LOCK | FE_HAS_SYNC;
 
-       switch(state->config->status_mode) {
+       switch (state->config->status_mode) {
        case S5H1409_DEMODLOCKING:
                if (*status & FE_HAS_VITERBI)
                        *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
@@ -668,12 +673,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
        return 0;
 }
 
-static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
 {
        int i, ret = -EINVAL;
        dprintk("%s()\n", __func__);
 
-       for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+       for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
                if (v < qam256_snr_tab[i].val) {
                        *snr = qam256_snr_tab[i].data;
                        ret = 0;
@@ -683,12 +688,12 @@ static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
        return ret;
 }
 
-static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
 {
        int i, ret = -EINVAL;
        dprintk("%s()\n", __func__);
 
-       for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+       for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
                if (v < qam64_snr_tab[i].val) {
                        *snr = qam64_snr_tab[i].data;
                        ret = 0;
@@ -698,12 +703,12 @@ static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
        return ret;
 }
 
-static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
 {
        int i, ret = -EINVAL;
        dprintk("%s()\n", __func__);
 
-       for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+       for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
                if (v > vsb_snr_tab[i].val) {
                        *snr = vsb_snr_tab[i].data;
                        ret = 0;
@@ -714,13 +719,13 @@ static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
        return ret;
 }
 
-static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
+static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
        u16 reg;
        dprintk("%s()\n", __func__);
 
-       switch(state->current_modulation) {
+       switch (state->current_modulation) {
        case QAM_64:
                reg = s5h1409_readreg(state, 0xf0) & 0xff;
                return s5h1409_qam64_lookup_snr(fe, snr, reg);
@@ -737,30 +742,30 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
        return -EINVAL;
 }
 
-static int s5h1409_read_signal_strength(struct dvb_frontendfe,
-                                       u16signal_strength)
+static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
+                                       u16 *signal_strength)
 {
        return s5h1409_read_snr(fe, signal_strength);
 }
 
-static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        *ucblocks = s5h1409_readreg(state, 0xb5);
 
        return 0;
 }
 
-static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber)
+static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        return s5h1409_read_ucblocks(fe, ber);
 }
 
-static int s5h1409_get_frontend(struct dvb_frontendfe,
+static int s5h1409_get_frontend(struct dvb_frontend *fe,
                                struct dvb_frontend_parameters *p)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
 
        p->frequency = state->current_frequency;
        p->u.vsb.modulation = state->current_modulation;
@@ -768,25 +773,25 @@ static int s5h1409_get_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int s5h1409_get_tune_settings(struct dvb_frontendfe,
+static int s5h1409_get_tune_settings(struct dvb_frontend *fe,
                                     struct dvb_frontend_tune_settings *tune)
 {
        tune->min_delay_ms = 1000;
        return 0;
 }
 
-static void s5h1409_release(struct dvb_frontendfe)
+static void s5h1409_release(struct dvb_frontend *fe)
 {
-       struct s5h1409_statestate = fe->demodulator_priv;
+       struct s5h1409_state *state = fe->demodulator_priv;
        kfree(state);
 }
 
 static struct dvb_frontend_ops s5h1409_ops;
 
-struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
-                                   struct i2c_adapteri2c)
+struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
+                                   struct i2c_adapter *i2c)
 {
-       struct s5h1409_statestate = NULL;
+       struct s5h1409_state *state = NULL;
        u16 reg;
 
        /* allocate memory for the internal state */
@@ -825,6 +830,7 @@ error:
        kfree(state);
        return NULL;
 }
+EXPORT_SYMBOL(s5h1409_attach);
 
 static struct dvb_frontend_ops s5h1409_ops = {
 
@@ -850,14 +856,10 @@ static struct dvb_frontend_ops s5h1409_ops = {
        .release              = s5h1409_release,
 };
 
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
 MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
 MODULE_AUTHOR("Steven Toth");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(s5h1409_attach);
 
 /*
  * Local variables:
index d1a1d2eb8e111247c06eee1f5d38e41e817a6322..070d9743e330ca3da4d99a5e843a592a5e7e6a53 100644 (file)
@@ -24,8 +24,7 @@
 
 #include <linux/dvb/frontend.h>
 
-struct s5h1409_config
-{
+struct s5h1409_config {
        /* the demodulator's i2c address */
        u8 demod_address;
 
@@ -60,12 +59,14 @@ struct s5h1409_config
        u16 mpeg_timing;
 };
 
-#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
-extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
-                                          struct i2c_adapter* i2c);
+#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \
+       && defined(MODULE))
+extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
+                                          struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
-                                                 struct i2c_adapter* i2c)
+static inline struct dvb_frontend *s5h1409_attach(
+       const struct s5h1409_config *config,
+       struct i2c_adapter *i2c)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
index 2da1a3763de93ce16eba814d3ee8ff5a6ffc0d1e..2febfb5a846bc0922e31d75daf779c7cb0fe5ed3 100644 (file)
@@ -343,7 +343,7 @@ static int s5h1411_writereg(struct s5h1411_state *state,
        u8 addr, u8 reg, u16 data)
 {
        int ret;
-       u8 buf [] = { reg, data >> 8,  data & 0xff };
+       u8 buf[] = { reg, data >> 8,  data & 0xff };
 
        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
 
@@ -359,10 +359,10 @@ static int s5h1411_writereg(struct s5h1411_state *state,
 static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
 {
        int ret;
-       u8 b0 [] = { reg };
-       u8 b1 [] = { 0, 0 };
+       u8 b0[] = { reg };
+       u8 b1[] = { 0, 0 };
 
-       struct i2c_msg msg [] = {
+       struct i2c_msg msg[] = {
                { .addr = addr, .flags = 0, .buf = b0, .len = 1 },
                { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
 
index 04e7f1cc1403ef1fb6f197f18cec99827e6d3453..2a8bbcd44cd02a40f86921eac66bcf5455076391 100644 (file)
@@ -195,7 +195,7 @@ static struct init_tab {
 static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 {
        int ret;
-       u8 buf [] = { reg, data };
+       u8 buf[] = { reg, data };
        struct i2c_msg msg = {
                .addr = state->config->demod_address,
                .flags = 0, .buf = buf, .len = 2 };
@@ -213,9 +213,9 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 {
        int ret;
-       u8 b0 [] = { reg };
-       u8 b1 [] = { 0 };
-       struct i2c_msg msg [] = {
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
                { .addr = state->config->demod_address,
                        .flags = 0, .buf = b0, .len = 1 },
                { .addr = state->config->demod_address,
@@ -393,43 +393,89 @@ static int tda10048_get_tps(struct tda10048_state *state,
 
        val = tda10048_readreg(state, TDA10048_OUT_CONF2);
        switch ((val & 0x60) >> 5) {
-       case 0: p->constellation =   QPSK; break;
-       case 1: p->constellation = QAM_16; break;
-       case 2: p->constellation = QAM_64; break;
+       case 0:
+               p->constellation = QPSK;
+               break;
+       case 1:
+               p->constellation = QAM_16;
+               break;
+       case 2:
+               p->constellation = QAM_64;
+               break;
        }
        switch ((val & 0x18) >> 3) {
-       case 0: p->hierarchy_information = HIERARCHY_NONE; break;
-       case 1: p->hierarchy_information =    HIERARCHY_1; break;
-       case 2: p->hierarchy_information =    HIERARCHY_2; break;
-       case 3: p->hierarchy_information =    HIERARCHY_4; break;
+       case 0:
+               p->hierarchy_information = HIERARCHY_NONE;
+               break;
+       case 1:
+               p->hierarchy_information = HIERARCHY_1;
+               break;
+       case 2:
+               p->hierarchy_information = HIERARCHY_2;
+               break;
+       case 3:
+               p->hierarchy_information = HIERARCHY_4;
+               break;
        }
        switch (val & 0x07) {
-       case 0: p->code_rate_HP = FEC_1_2; break;
-       case 1: p->code_rate_HP = FEC_2_3; break;
-       case 2: p->code_rate_HP = FEC_3_4; break;
-       case 3: p->code_rate_HP = FEC_5_6; break;
-       case 4: p->code_rate_HP = FEC_7_8; break;
+       case 0:
+               p->code_rate_HP = FEC_1_2;
+               break;
+       case 1:
+               p->code_rate_HP = FEC_2_3;
+               break;
+       case 2:
+               p->code_rate_HP = FEC_3_4;
+               break;
+       case 3:
+               p->code_rate_HP = FEC_5_6;
+               break;
+       case 4:
+               p->code_rate_HP = FEC_7_8;
+               break;
        }
 
        val = tda10048_readreg(state, TDA10048_OUT_CONF3);
        switch (val & 0x07) {
-       case 0: p->code_rate_LP = FEC_1_2; break;
-       case 1: p->code_rate_LP = FEC_2_3; break;
-       case 2: p->code_rate_LP = FEC_3_4; break;
-       case 3: p->code_rate_LP = FEC_5_6; break;
-       case 4: p->code_rate_LP = FEC_7_8; break;
+       case 0:
+               p->code_rate_LP = FEC_1_2;
+               break;
+       case 1:
+               p->code_rate_LP = FEC_2_3;
+               break;
+       case 2:
+               p->code_rate_LP = FEC_3_4;
+               break;
+       case 3:
+               p->code_rate_LP = FEC_5_6;
+               break;
+       case 4:
+               p->code_rate_LP = FEC_7_8;
+               break;
        }
 
        val = tda10048_readreg(state, TDA10048_OUT_CONF1);
        switch ((val & 0x0c) >> 2) {
-       case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
-       case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
-       case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
-       case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
+       case 0:
+               p->guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               p->guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               p->guard_interval =  GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               p->guard_interval =  GUARD_INTERVAL_1_4;
+               break;
        }
        switch (val & 0x02) {
-       case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
-       case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+       case 0:
+               p->transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 1:
+               p->transmission_mode = TRANSMISSION_MODE_8K;
+               break;
        }
 
        return 0;
index d2876d2e17695a36691c9a7a4fdc0ff2f3ff19b0..07f3fc0998f67a0c58a958d370b77d9554682174 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef Z0194A
 #define Z0194A
 
-static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe,
+static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe,
                                         u32 srate, u32 ratio)
 {
        u8 aclk = 0;
@@ -40,7 +40,7 @@ static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe,
        return 0;
 }
 
-static u8 sharp_z0194a__inittab[] = {
+static u8 sharp_z0194a_inittab[] = {
        0x01, 0x15,
        0x02, 0x00,
        0x03, 0x00,
@@ -82,16 +82,4 @@ static u8 sharp_z0194a__inittab[] = {
        0xff, 0xff
 };
 
-static struct stv0299_config sharp_z0194a_config = {
-       .demod_address = 0x68,
-       .inittab = sharp_z0194a__inittab,
-       .mclk = 88000000UL,
-       .invert = 1,
-       .skip_reinit = 0,
-       .lock_output = STV0299_LOCKOUTPUT_1,
-       .volt13_op0_op1 = STV0299_VOLT13_OP1,
-       .min_delay_ms = 100,
-       .set_symbol_rate = sharp_z0194a__set_symbol_rate,
-};
-
 #endif
index 9da260fe3fd12313c0e633567ca818770e4afac4..6f9b773604401309191704207a0035cc0892029a 100644 (file)
@@ -42,6 +42,10 @@ struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
        { USB_DEVICE(0x2040, 0x5510),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5520),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5530),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
        { USB_DEVICE(0x2040, 0x5580),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
        { USB_DEVICE(0x2040, 0x5590),
index e51d707e58d35aa7acc905cc0f017f07584be16b..04cd7c04bdde7babfe5d8efbf61a903a94b837e8 100644 (file)
@@ -359,7 +359,7 @@ config USB_SI470X
          computer's USB port.
 
          To compile this driver as a module, choose M here: the
-         module will be called radio-silabs.
+         module will be called radio-si470x.
 
 config USB_MR800
        tristate "AverMedia MR 800 USB FM radio support"
index f6cedcd3ab97b82b532b16a03137eb0fd5c7e75f..5920cd306975aa7983cc2bd892141780cbef6970 100644 (file)
  *             - hardware frequency seek support
  *             - afc indication
  *             - more safety checks, let si470x_get_freq return errno
+ *             - vidioc behavior corrected according to v4l2 spec
  *
  * ToDo:
  * - add firmware download/update support
 /* USB Device ID List */
 static struct usb_device_id si470x_usb_driver_id_table[] = {
        /* Silicon Labs USB FM Radio Reference Design */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
        /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
        /* Terminating entry */
        { }
 };
@@ -157,7 +158,7 @@ MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
 
 /* Radio Nr */
 static int radio_nr = -1;
-module_param(radio_nr, int, 0);
+module_param(radio_nr, int, 0444);
 MODULE_PARM_DESC(radio_nr, "Radio Nr");
 
 /* Spacing (kHz) */
@@ -165,42 +166,42 @@ MODULE_PARM_DESC(radio_nr, "Radio Nr");
 /* 1: 100 kHz (Europe, Japan) */
 /* 2:  50 kHz */
 static unsigned short space = 2;
-module_param(space, ushort, 0);
-MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
+module_param(space, ushort, 0444);
+MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
 
 /* Bottom of Band (MHz) */
 /* 0: 87.5 - 108 MHz (USA, Europe)*/
 /* 1: 76   - 108 MHz (Japan wide band) */
 /* 2: 76   -  90 MHz (Japan) */
 static unsigned short band = 1;
-module_param(band, ushort, 0);
-MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
+module_param(band, ushort, 0444);
+MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
 
 /* De-emphasis */
 /* 0: 75 us (USA) */
 /* 1: 50 us (Europe, Australia, Japan) */
 static unsigned short de = 1;
-module_param(de, ushort, 0);
-MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
+module_param(de, ushort, 0444);
+MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
 
 /* USB timeout */
 static unsigned int usb_timeout = 500;
-module_param(usb_timeout, uint, 0);
+module_param(usb_timeout, uint, 0644);
 MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
 
 /* Tune timeout */
 static unsigned int tune_timeout = 3000;
-module_param(tune_timeout, uint, 0);
+module_param(tune_timeout, uint, 0644);
 MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
 
 /* Seek timeout */
 static unsigned int seek_timeout = 5000;
-module_param(seek_timeout, uint, 0);
+module_param(seek_timeout, uint, 0644);
 MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
 
 /* RDS buffer blocks */
 static unsigned int rds_buf = 100;
-module_param(rds_buf, uint, 0);
+module_param(rds_buf, uint, 0444);
 MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
 
 /* RDS maximum block errors */
@@ -209,7 +210,7 @@ static unsigned short max_rds_errors = 1;
 /* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
 /* 2 means 3-5  errors requiring correction */
 /* 3 means   6+ errors or errors in checkword, correction not possible */
-module_param(max_rds_errors, ushort, 0);
+module_param(max_rds_errors, ushort, 0644);
 MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
 
 /* RDS poll frequency */
@@ -218,7 +219,7 @@ static unsigned int rds_poll_time = 40;
 /* 50 is used by radio-cadet */
 /* 75 should be okay */
 /* 80 is the usual RDS receive interval */
-module_param(rds_poll_time, uint, 0);
+module_param(rds_poll_time, uint, 0644);
 MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
 
 
@@ -667,23 +668,29 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
        int retval;
 
        /* Spacing (kHz) */
-       switch (space) {
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
        /* 0: 200 kHz (USA, Australia) */
-       case 0 : spacing = 0.200 * FREQ_MUL; break;
+       case 0:
+               spacing = 0.200 * FREQ_MUL; break;
        /* 1: 100 kHz (Europe, Japan) */
-       case 1 : spacing = 0.100 * FREQ_MUL; break;
+       case 1:
+               spacing = 0.100 * FREQ_MUL; break;
        /* 2:  50 kHz */
-       default: spacing = 0.050 * FREQ_MUL; break;
+       default:
+               spacing = 0.050 * FREQ_MUL; break;
        };
 
        /* Bottom of Band (MHz) */
-       switch (band) {
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
        /* 0: 87.5 - 108 MHz (USA, Europe) */
-       case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+       case 0:
+               band_bottom = 87.5 * FREQ_MUL; break;
        /* 1: 76   - 108 MHz (Japan wide band) */
-       default: band_bottom = 76   * FREQ_MUL; break;
+       default:
+               band_bottom = 76   * FREQ_MUL; break;
        /* 2: 76   -  90 MHz (Japan) */
-       case 2 : band_bottom = 76   * FREQ_MUL; break;
+       case 2:
+               band_bottom = 76   * FREQ_MUL; break;
        };
 
        /* read channel */
@@ -706,23 +713,29 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
        unsigned short chan;
 
        /* Spacing (kHz) */
-       switch (space) {
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
        /* 0: 200 kHz (USA, Australia) */
-       case 0 : spacing = 0.200 * FREQ_MUL; break;
+       case 0:
+               spacing = 0.200 * FREQ_MUL; break;
        /* 1: 100 kHz (Europe, Japan) */
-       case 1 : spacing = 0.100 * FREQ_MUL; break;
+       case 1:
+               spacing = 0.100 * FREQ_MUL; break;
        /* 2:  50 kHz */
-       default: spacing = 0.050 * FREQ_MUL; break;
+       default:
+               spacing = 0.050 * FREQ_MUL; break;
        };
 
        /* Bottom of Band (MHz) */
-       switch (band) {
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
        /* 0: 87.5 - 108 MHz (USA, Europe) */
-       case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+       case 0:
+               band_bottom = 87.5 * FREQ_MUL; break;
        /* 1: 76   - 108 MHz (Japan wide band) */
-       default: band_bottom = 76   * FREQ_MUL; break;
+       default:
+               band_bottom = 76   * FREQ_MUL; break;
        /* 2: 76   -  90 MHz (Japan) */
-       case 2 : band_bottom = 76   * FREQ_MUL; break;
+       case 2:
+               band_bottom = 76   * FREQ_MUL; break;
        };
 
        /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
@@ -1164,7 +1177,6 @@ static const struct file_operations si470x_fops = {
  * si470x_v4l2_queryctrl - query control
  */
 static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
-/* HINT: the disabled controls are only here to satify kradio and such apps */
        {
                .id             = V4L2_CID_AUDIO_VOLUME,
                .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -1174,18 +1186,6 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
                .step           = 1,
                .default_value  = 15,
        },
-       {
-               .id             = V4L2_CID_AUDIO_BALANCE,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_BASS,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_TREBLE,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
        {
                .id             = V4L2_CID_AUDIO_MUTE,
                .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -1195,10 +1195,6 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
                .step           = 1,
                .default_value  = 1,
        },
-       {
-               .id             = V4L2_CID_AUDIO_LOUDNESS,
-               .flags          = V4L2_CTRL_FLAG_DISABLED,
-       },
 };
 
 
@@ -1219,57 +1215,35 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
 }
 
 
-/*
- * si470x_vidioc_g_input - get input
- */
-static int si470x_vidioc_g_input(struct file *file, void *priv,
-               unsigned int *i)
-{
-       *i = 0;
-
-       return 0;
-}
-
-
-/*
- * si470x_vidioc_s_input - set input
- */
-static int si470x_vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
-       int retval = 0;
-
-       /* safety checks */
-       if (i != 0)
-               retval = -EINVAL;
-
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": set input failed with %d\n", retval);
-       return retval;
-}
-
-
 /*
  * si470x_vidioc_queryctrl - enumerate control items
  */
 static int si470x_vidioc_queryctrl(struct file *file, void *priv,
                struct v4l2_queryctrl *qc)
 {
-       unsigned char i;
+       unsigned char i = 0;
        int retval = -EINVAL;
 
-       /* safety checks */
-       if (!qc->id)
+       /* abort if qc->id is below V4L2_CID_BASE */
+       if (qc->id < V4L2_CID_BASE)
                goto done;
 
+       /* search video control */
        for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
                if (qc->id == si470x_v4l2_queryctrl[i].id) {
                        memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
-                       retval = 0;
+                       retval = 0; /* found */
                        break;
                }
        }
 
+       /* disable unsupported base controls */
+       /* to satisfy kradio and such apps */
+       if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
+               qc->flags = V4L2_CTRL_FLAG_DISABLED;
+               retval = 0;
+       }
+
 done:
        if (retval < 0)
                printk(KERN_WARNING DRIVER_NAME
@@ -1360,44 +1334,13 @@ done:
 static int si470x_vidioc_g_audio(struct file *file, void *priv,
                struct v4l2_audio *audio)
 {
-       int retval = 0;
-
-       /* safety checks */
-       if (audio->index != 0) {
-               retval = -EINVAL;
-               goto done;
-       }
-
+       /* driver constants */
+       audio->index = 0;
        strcpy(audio->name, "Radio");
        audio->capability = V4L2_AUDCAP_STEREO;
+       audio->mode = 0;
 
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": get audio failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_s_audio - set audio attributes
- */
-static int si470x_vidioc_s_audio(struct file *file, void *priv,
-               struct v4l2_audio *audio)
-{
-       int retval = 0;
-
-       /* safety checks */
-       if (audio->index != 0) {
-               retval = -EINVAL;
-               goto done;
-       }
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": set audio failed with %d\n", retval);
-       return retval;
+       return 0;
 }
 
 
@@ -1415,7 +1358,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
                retval = -EIO;
                goto done;
        }
-       if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
+       if (tuner->index != 0) {
                retval = -EINVAL;
                goto done;
        }
@@ -1424,8 +1367,13 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
        if (retval < 0)
                goto done;
 
+       /* driver constants */
        strcpy(tuner->name, "FM");
-       switch (band) {
+       tuner->type = V4L2_TUNER_RADIO;
+       tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+
+       /* range limits */
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
        /* 0: 87.5 - 108 MHz (USA, Europe, default) */
        default:
                tuner->rangelow  =  87.5 * FREQ_MUL;
@@ -1442,14 +1390,18 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
                tuner->rangehigh =  90   * FREQ_MUL;
                break;
        };
-       tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       tuner->capability = V4L2_TUNER_CAP_LOW;
 
-       /* Stereo indicator == Stereo (instead of Mono) */
+       /* stereo indicator == stereo (instead of mono) */
        if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
-               tuner->audmode = V4L2_TUNER_MODE_STEREO;
+               tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
        else
+               tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+       /* mono/stereo selector */
+       if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 1)
                tuner->audmode = V4L2_TUNER_MODE_MONO;
+       else
+               tuner->audmode = V4L2_TUNER_MODE_STEREO;
 
        /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
        tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
@@ -1474,22 +1426,27 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
                struct v4l2_tuner *tuner)
 {
        struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
+       int retval = -EINVAL;
 
        /* safety checks */
        if (radio->disconnected) {
                retval = -EIO;
                goto done;
        }
-       if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
-               retval = -EINVAL;
+       if (tuner->index != 0)
                goto done;
-       }
 
-       if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+       /* mono/stereo selector */
+       switch (tuner->audmode) {
+       case V4L2_TUNER_MODE_MONO:
                radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
-       else
+               break;
+       case V4L2_TUNER_MODE_STEREO:
                radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
+               break;
+       default:
+               goto done;
+       }
 
        retval = si470x_set_register(radio, POWERCFG);
 
@@ -1515,11 +1472,12 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
                retval = -EIO;
                goto done;
        }
-       if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+       if (freq->tuner != 0) {
                retval = -EINVAL;
                goto done;
        }
 
+       freq->type = V4L2_TUNER_RADIO;
        retval = si470x_get_freq(radio, &freq->frequency);
 
 done:
@@ -1544,7 +1502,7 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
                retval = -EIO;
                goto done;
        }
-       if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+       if (freq->tuner != 0) {
                retval = -EINVAL;
                goto done;
        }
@@ -1573,7 +1531,7 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
                retval = -EIO;
                goto done;
        }
-       if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) {
+       if (seek->tuner != 0) {
                retval = -EINVAL;
                goto done;
        }
@@ -1588,15 +1546,16 @@ done:
        return retval;
 }
 
+
+/*
+ * si470x_ioctl_ops - video device ioctl operations
+ */
 static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
        .vidioc_querycap        = si470x_vidioc_querycap,
-       .vidioc_g_input         = si470x_vidioc_g_input,
-       .vidioc_s_input         = si470x_vidioc_s_input,
        .vidioc_queryctrl       = si470x_vidioc_queryctrl,
        .vidioc_g_ctrl          = si470x_vidioc_g_ctrl,
        .vidioc_s_ctrl          = si470x_vidioc_s_ctrl,
        .vidioc_g_audio         = si470x_vidioc_g_audio,
-       .vidioc_s_audio         = si470x_vidioc_s_audio,
        .vidioc_g_tuner         = si470x_vidioc_g_tuner,
        .vidioc_s_tuner         = si470x_vidioc_s_tuner,
        .vidioc_g_frequency     = si470x_vidioc_g_frequency,
@@ -1604,14 +1563,15 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
        .vidioc_s_hw_freq_seek  = si470x_vidioc_s_hw_freq_seek,
 };
 
+
 /*
- * si470x_viddev_tamples - video device interface
+ * si470x_viddev_template - video device interface
  */
 static struct video_device si470x_viddev_template = {
        .fops                   = &si470x_fops,
-       .ioctl_ops              = &si470x_ioctl_ops,
        .name                   = DRIVER_NAME,
        .release                = video_device_release,
+       .ioctl_ops              = &si470x_ioctl_ops,
 };
 
 
index f794f2dbfb327be6c979baedcfd6decca8f3df67..e0eb4f321442c638253ff79f3e7f9f125e3403f7 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
 #include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-
-#define I2C_NAME(x) (x)->name
-
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* ----------------------------------------------------------------------- */
 
 struct adv7170 {
@@ -80,21 +61,12 @@ struct adv7170 {
        int sat;
 };
 
-#define   I2C_ADV7170        0xd4
-#define   I2C_ADV7171        0x54
-
-static char adv7170_name[] = "adv7170";
-static char adv7171_name[] = "adv7171";
-
 static char *inputs[] = { "pass_through", "play_back" };
 static char *norms[] = { "PAL", "NTSC" };
 
 /* ----------------------------------------------------------------------- */
 
-static inline int
-adv7170_write (struct i2c_client *client,
-              u8                 reg,
-              u8                 value)
+static inline int adv7170_write(struct i2c_client *client, u8 reg, u8 value)
 {
        struct adv7170 *encoder = i2c_get_clientdata(client);
 
@@ -102,17 +74,13 @@ adv7170_write (struct i2c_client *client,
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int
-adv7170_read (struct i2c_client *client,
-             u8                 reg)
+static inline int adv7170_read(struct i2c_client *client, u8 reg)
 {
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int
-adv7170_write_block (struct i2c_client *client,
-                    const u8          *data,
-                    unsigned int       len)
+static int adv7170_write_block(struct i2c_client *client,
+                    const u8 *data, unsigned int len)
 {
        int ret = -1;
        u8 reg;
@@ -133,33 +101,25 @@ adv7170_write_block (struct i2c_client *client,
                                    encoder->reg[reg++] = data[1];
                                len -= 2;
                                data += 2;
-                       } while (len >= 2 && data[0] == reg &&
-                                block_len < 32);
-                       if ((ret = i2c_master_send(client, block_data,
-                                                  block_len)) < 0)
+                       } while (len >= 2 && data[0] == reg && block_len < 32);
+                       ret = i2c_master_send(client, block_data, block_len);
+                       if (ret < 0)
                                break;
                }
        } else {
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       if ((ret = adv7170_write(client, reg,
-                                                *data++)) < 0)
+                       ret = adv7170_write(client, reg, *data++);
+                       if (ret < 0)
                                break;
                        len -= 2;
                }
        }
-
        return ret;
 }
 
 /* ----------------------------------------------------------------------- */
-// Output filter:  S-Video  Composite
-
-#define MR050       0x11       //0x09
-#define MR060       0x14       //0x0c
-
-//---------------------------------------------------------------------------
 
 #define TR0MODE     0x4c
 #define TR0RST     0x80
@@ -167,7 +127,6 @@ adv7170_write_block (struct i2c_client *client,
 #define TR1CAPT            0x00
 #define TR1PLAY            0x00
 
-
 static const unsigned char init_NTSC[] = {
        0x00, 0x10,             // MR0
        0x01, 0x20,             // MR1
@@ -227,15 +186,11 @@ static const unsigned char init_PAL[] = {
 };
 
 
-static int
-adv7170_command (struct i2c_client *client,
-                unsigned int       cmd,
-                void *             arg)
+static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct adv7170 *encoder = i2c_get_clientdata(client);
 
        switch (cmd) {
-
        case 0:
 #if 0
                /* This is just for testing!!! */
@@ -254,18 +209,16 @@ adv7170_command (struct i2c_client *client,
                             VIDEO_ENCODER_NTSC;
                cap->inputs = 2;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case ENCODER_SET_NORM:
        {
                int iarg = *(int *) arg;
 
-               dprintk(1, KERN_DEBUG "%s_command: set norm %d",
-                       I2C_NAME(client), iarg);
+               v4l_dbg(1, debug, client, "set norm %d\n", iarg);
 
                switch (iarg) {
-
                case VIDEO_MODE_NTSC:
                        adv7170_write_block(client, init_NTSC,
                                            sizeof(init_NTSC));
@@ -285,16 +238,13 @@ adv7170_command (struct i2c_client *client,
                        break;
 
                default:
-                       dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
-                              I2C_NAME(client), iarg);
+                       v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
                        return -EINVAL;
-
                }
-               dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
-                       norms[iarg]);
+               v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
                encoder->norm = iarg;
-       }
                break;
+       }
 
        case ENCODER_SET_INPUT:
        {
@@ -304,19 +254,17 @@ adv7170_command (struct i2c_client *client,
                 *iarg = 1: input is from ZR36060
                 *iarg = 2: color bar */
 
-               dprintk(1, KERN_DEBUG "%s_command: set input from %s\n",
-                       I2C_NAME(client),
+               v4l_dbg(1, debug, client, "set input from %s\n",
                        iarg == 0 ? "decoder" : "ZR36060");
 
                switch (iarg) {
-
                case 0:
                        adv7170_write(client, 0x01, 0x20);
                        adv7170_write(client, 0x08, TR1CAPT);   /* TR1 */
                        adv7170_write(client, 0x02, 0x0e);      // Enable genlock
                        adv7170_write(client, 0x07, TR0MODE | TR0RST);
                        adv7170_write(client, 0x07, TR0MODE);
-                       //udelay(10);
+                       /* udelay(10); */
                        break;
 
                case 1:
@@ -325,20 +273,17 @@ adv7170_command (struct i2c_client *client,
                        adv7170_write(client, 0x02, 0x08);
                        adv7170_write(client, 0x07, TR0MODE | TR0RST);
                        adv7170_write(client, 0x07, TR0MODE);
-                       //udelay(10);
+                       /* udelay(10); */
                        break;
 
                default:
-                       dprintk(1, KERN_ERR "%s: illegal input: %d\n",
-                               I2C_NAME(client), iarg);
+                       v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
                        return -EINVAL;
-
                }
-               dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
-                       inputs[iarg]);
+               v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
                encoder->input = iarg;
-       }
                break;
+       }
 
        case ENCODER_SET_OUTPUT:
        {
@@ -348,16 +293,16 @@ adv7170_command (struct i2c_client *client,
                if (*iarg != 0) {
                        return -EINVAL;
                }
-       }
                break;
+       }
 
        case ENCODER_ENABLE_OUTPUT:
        {
                int *iarg = arg;
 
                encoder->enable = !!*iarg;
-       }
                break;
+       }
 
        default:
                return -EINVAL;
@@ -368,149 +313,67 @@ adv7170_command (struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] =
-    { I2C_ADV7170 >> 1, (I2C_ADV7170 >> 1) + 1,
-       I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
+static unsigned short normal_i2c[] = {
+       0xd4 >> 1, 0xd6 >> 1,   /* adv7170 IDs */
+       0x54 >> 1, 0x56 >> 1,   /* adv7171 IDs */
        I2C_CLIENT_END
 };
 
-static unsigned short ignore = I2C_CLIENT_END;
+I2C_CLIENT_INSMOD;
 
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
-
-static struct i2c_driver i2c_driver_adv7170;
-
-static int
-adv7170_detect_client (struct i2c_adapter *adapter,
-                      int                 address,
-                      int                 kind)
+static int adv7170_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       int i;
-       struct i2c_client *client;
        struct adv7170 *encoder;
-       char *dname;
-
-       dprintk(1,
-               KERN_INFO
-               "adv7170.c: detecting adv7170 client on address 0x%x\n",
-               address << 1);
+       int i;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_adv7170;
-       if ((client->addr == I2C_ADV7170 >> 1) ||
-           (client->addr == (I2C_ADV7170 >> 1) + 1)) {
-               dname = adv7170_name;
-       } else if ((client->addr == I2C_ADV7171 >> 1) ||
-                  (client->addr == (I2C_ADV7171 >> 1) + 1)) {
-               dname = adv7171_name;
-       } else {
-               /* We should never get here!!! */
-               kfree(client);
-               return 0;
-       }
-       strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
-       if (encoder == NULL) {
-               kfree(client);
+       if (encoder == NULL)
                return -ENOMEM;
-       }
        encoder->norm = VIDEO_MODE_NTSC;
        encoder->input = 0;
        encoder->enable = 1;
        i2c_set_clientdata(client, encoder);
 
-       i = i2c_attach_client(client);
-       if (i) {
-               kfree(client);
-               kfree(encoder);
-               return i;
-       }
-
        i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
        if (i >= 0) {
                i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
                i = adv7170_write(client, 0x07, TR0MODE);
                i = adv7170_read(client, 0x12);
-               dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%02x\n",
-                       I2C_NAME(client), i & 1, client->addr << 1);
-       }
-       if (i < 0) {
-               dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
-                      I2C_NAME(client), i);
+               v4l_dbg(1, debug, client, "revision %d\n", i & 1);
        }
-
+       if (i < 0)
+               v4l_dbg(1, debug, client, "init error 0x%x\n", i);
        return 0;
 }
 
-static int
-adv7170_attach_adapter (struct i2c_adapter *adapter)
-{
-       dprintk(1,
-               KERN_INFO
-               "adv7170.c: starting probe for adapter %s (0x%x)\n",
-               I2C_NAME(adapter), adapter->id);
-       return i2c_probe(adapter, &addr_data, &adv7170_detect_client);
-}
-
-static int
-adv7170_detach_client (struct i2c_client *client)
+static int adv7170_remove(struct i2c_client *client)
 {
-       struct adv7170 *encoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(encoder);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_adv7170 = {
-       .driver = {
-               .name = "adv7170",      /* name */
-       },
-
-       .id = I2C_DRIVERID_ADV7170,
+static const struct i2c_device_id adv7170_id[] = {
+       { "adv7170", 0 },
+       { "adv7171", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adv7170_id);
 
-       .attach_adapter = adv7170_attach_adapter,
-       .detach_client = adv7170_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "adv7170",
+       .driverid = I2C_DRIVERID_ADV7170,
        .command = adv7170_command,
+       .probe = adv7170_probe,
+       .remove = adv7170_remove,
+       .id_table = adv7170_id,
 };
-
-static int __init
-adv7170_init (void)
-{
-       return i2c_add_driver(&i2c_driver_adv7170);
-}
-
-static void __exit
-adv7170_exit (void)
-{
-       i2c_del_driver(&i2c_driver_adv7170);
-}
-
-module_init(adv7170_init);
-module_exit(adv7170_exit);
index 8ee07a68f7026527ed2eb4e5f8624955f27464d6..6008e84653f1d67fd13eaaf7946c3913494e4f03 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
 #include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-
-#define I2C_NAME(s) (s)->name
-
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* ----------------------------------------------------------------------- */
 
 struct adv7175 {
@@ -77,33 +58,23 @@ struct adv7175 {
 #define   I2C_ADV7175        0xd4
 #define   I2C_ADV7176        0x54
 
-static char adv7175_name[] = "adv7175";
-static char adv7176_name[] = "adv7176";
-
 static char *inputs[] = { "pass_through", "play_back", "color_bar" };
 static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" };
 
 /* ----------------------------------------------------------------------- */
 
-static inline int
-adv7175_write (struct i2c_client *client,
-              u8                 reg,
-              u8                 value)
+static inline int adv7175_write(struct i2c_client *client, u8 reg, u8 value)
 {
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int
-adv7175_read (struct i2c_client *client,
-             u8                 reg)
+static inline int adv7175_read(struct i2c_client *client, u8 reg)
 {
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int
-adv7175_write_block (struct i2c_client *client,
-                    const u8          *data,
-                    unsigned int       len)
+static int adv7175_write_block(struct i2c_client *client,
+                    const u8 *data, unsigned int len)
 {
        int ret = -1;
        u8 reg;
@@ -123,18 +94,17 @@ adv7175_write_block (struct i2c_client *client,
                                reg++;
                                len -= 2;
                                data += 2;
-                       } while (len >= 2 && data[0] == reg &&
-                                block_len < 32);
-                       if ((ret = i2c_master_send(client, block_data,
-                                                  block_len)) < 0)
+                       } while (len >= 2 && data[0] == reg && block_len < 32);
+                       ret = i2c_master_send(client, block_data, block_len);
+                       if (ret < 0)
                                break;
                }
        } else {
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       if ((ret = adv7175_write(client, reg,
-                                                *data++)) < 0)
+                       ret = adv7175_write(client, reg, *data++);
+                       if (ret < 0)
                                break;
                        len -= 2;
                }
@@ -143,13 +113,11 @@ adv7175_write_block (struct i2c_client *client,
        return ret;
 }
 
-static void
-set_subcarrier_freq (struct i2c_client *client,
-                    int                pass_through)
+static void set_subcarrier_freq(struct i2c_client *client, int pass_through)
 {
        /* for some reason pass_through NTSC needs
         * a different sub-carrier freq to remain stable. */
-       if(pass_through)
+       if (pass_through)
                adv7175_write(client, 0x02, 0x00);
        else
                adv7175_write(client, 0x02, 0x55);
@@ -160,12 +128,12 @@ set_subcarrier_freq (struct i2c_client *client,
 }
 
 /* ----------------------------------------------------------------------- */
-// Output filter:  S-Video  Composite
+/* Output filter:  S-Video  Composite */
 
-#define MR050       0x11       //0x09
-#define MR060       0x14       //0x0c
+#define MR050       0x11       /* 0x09 */
+#define MR060       0x14       /* 0x0c */
 
-//---------------------------------------------------------------------------
+/* ----------------------------------------------------------------------- */
 
 #define TR0MODE     0x46
 #define TR0RST     0x80
@@ -216,15 +184,11 @@ static const unsigned char init_ntsc[] = {
        0x06, 0x1a,             /* subc. phase */
 };
 
-static int
-adv7175_command (struct i2c_client *client,
-                unsigned int       cmd,
-                void              *arg)
+static int adv7175_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct adv7175 *encoder = i2c_get_clientdata(client);
 
        switch (cmd) {
-
        case 0:
                /* This is just for testing!!! */
                adv7175_write_block(client, init_common,
@@ -242,15 +206,14 @@ adv7175_command (struct i2c_client *client,
                             VIDEO_ENCODER_SECAM; /* well, hacky */
                cap->inputs = 2;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case ENCODER_SET_NORM:
        {
                int iarg = *(int *) arg;
 
                switch (iarg) {
-
                case VIDEO_MODE_NTSC:
                        adv7175_write_block(client, init_ntsc,
                                            sizeof(init_ntsc));
@@ -284,16 +247,13 @@ adv7175_command (struct i2c_client *client,
                        adv7175_write(client, 0x07, TR0MODE);
                        break;
                default:
-                       dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
-                               I2C_NAME(client), iarg);
+                       v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
                        return -EINVAL;
-
                }
-               dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
-                       norms[iarg]);
+               v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
                encoder->norm = iarg;
-       }
                break;
+       }
 
        case ENCODER_SET_INPUT:
        {
@@ -304,7 +264,6 @@ adv7175_command (struct i2c_client *client,
                 *iarg = 2: color bar */
 
                switch (iarg) {
-
                case 0:
                        adv7175_write(client, 0x01, 0x00);
 
@@ -331,7 +290,7 @@ adv7175_command (struct i2c_client *client,
                        adv7175_write(client, 0x0d, 0x49);
                        adv7175_write(client, 0x07, TR0MODE | TR0RST);
                        adv7175_write(client, 0x07, TR0MODE);
-                       //udelay(10);
+                       /* udelay(10); */
                        break;
 
                case 2:
@@ -343,39 +302,35 @@ adv7175_command (struct i2c_client *client,
                        adv7175_write(client, 0x0d, 0x49);
                        adv7175_write(client, 0x07, TR0MODE | TR0RST);
                        adv7175_write(client, 0x07, TR0MODE);
-                       //udelay(10);
+                       /* udelay(10); */
                        break;
 
                default:
-                       dprintk(1, KERN_ERR "%s: illegal input: %d\n",
-                               I2C_NAME(client), iarg);
+                       v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
                        return -EINVAL;
-
                }
-               dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
-                       inputs[iarg]);
+               v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
                encoder->input = iarg;
-       }
                break;
+       }
 
        case ENCODER_SET_OUTPUT:
        {
                int *iarg = arg;
 
                /* not much choice of outputs */
-               if (*iarg != 0) {
+               if (*iarg != 0)
                        return -EINVAL;
-               }
-       }
                break;
+       }
 
        case ENCODER_ENABLE_OUTPUT:
        {
                int *iarg = arg;
 
                encoder->enable = !!*iarg;
-       }
                break;
+       }
 
        default:
                return -EINVAL;
@@ -390,145 +345,67 @@ adv7175_command (struct i2c_client *client,
  * Generic i2c probe
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
-static unsigned short normal_i2c[] =
-    { I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
+static unsigned short normal_i2c[] = {
+       I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
        I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
        I2C_CLIENT_END
 };
 
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
-
-static struct i2c_driver i2c_driver_adv7175;
+I2C_CLIENT_INSMOD;
 
-static int
-adv7175_detect_client (struct i2c_adapter *adapter,
-                      int                 address,
-                      int                 kind)
+static int adv7175_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        int i;
-       struct i2c_client *client;
        struct adv7175 *encoder;
-       char *dname;
-
-       dprintk(1,
-               KERN_INFO
-               "adv7175.c: detecting adv7175 client on address 0x%x\n",
-               address << 1);
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_adv7175;
-       if ((client->addr == I2C_ADV7175 >> 1) ||
-           (client->addr == (I2C_ADV7175 >> 1) + 1)) {
-               dname = adv7175_name;
-       } else if ((client->addr == I2C_ADV7176 >> 1) ||
-                  (client->addr == (I2C_ADV7176 >> 1) + 1)) {
-               dname = adv7176_name;
-       } else {
-               /* We should never get here!!! */
-               kfree(client);
-               return 0;
-       }
-       strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
-       if (encoder == NULL) {
-               kfree(client);
+       if (encoder == NULL)
                return -ENOMEM;
-       }
        encoder->norm = VIDEO_MODE_PAL;
        encoder->input = 0;
        encoder->enable = 1;
        i2c_set_clientdata(client, encoder);
 
-       i = i2c_attach_client(client);
-       if (i) {
-               kfree(client);
-               kfree(encoder);
-               return i;
-       }
-
        i = adv7175_write_block(client, init_common, sizeof(init_common));
        if (i >= 0) {
                i = adv7175_write(client, 0x07, TR0MODE | TR0RST);
                i = adv7175_write(client, 0x07, TR0MODE);
                i = adv7175_read(client, 0x12);
-               dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%x\n",
-                       I2C_NAME(client), i & 1, client->addr << 1);
+               v4l_dbg(1, debug, client, "revision %d\n", i & 1);
        }
-       if (i < 0) {
-               dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
-                       I2C_NAME(client), i);
-       }
-
+       if (i < 0)
+               v4l_dbg(1, debug, client, "init error 0x%x\n", i);
        return 0;
 }
 
-static int
-adv7175_attach_adapter (struct i2c_adapter *adapter)
-{
-       dprintk(1,
-               KERN_INFO
-               "adv7175.c: starting probe for adapter %s (0x%x)\n",
-               I2C_NAME(adapter), adapter->id);
-       return i2c_probe(adapter, &addr_data, &adv7175_detect_client);
-}
-
-static int
-adv7175_detach_client (struct i2c_client *client)
+static int adv7175_remove(struct i2c_client *client)
 {
-       struct adv7175 *encoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(encoder);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_adv7175 = {
-       .driver = {
-               .name = "adv7175",      /* name */
-       },
-
-       .id = I2C_DRIVERID_ADV7175,
+static const struct i2c_device_id adv7175_id[] = {
+       { "adv7175", 0 },
+       { "adv7176", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adv7175_id);
 
-       .attach_adapter = adv7175_attach_adapter,
-       .detach_client = adv7175_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "adv7175",
+       .driverid = I2C_DRIVERID_ADV7175,
        .command = adv7175_command,
+       .probe = adv7175_probe,
+       .remove = adv7175_remove,
+       .id_table = adv7175_id,
 };
-
-static int __init
-adv7175_init (void)
-{
-       return i2c_add_driver(&i2c_driver_adv7175);
-}
-
-static void __exit
-adv7175_exit (void)
-{
-       i2c_del_driver(&i2c_driver_adv7175);
-}
-
-module_init(adv7175_init);
-module_exit(adv7175_exit);
index 5f07a8a072b64ed119c7c7b39e760c7bd985ea8e..d60123b413f59a2e16a5225c38a336b3b47f85b0 100644 (file)
@@ -90,6 +90,7 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
        case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
        case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
        case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
+       case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
        case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
        case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
                break;
@@ -185,7 +186,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
 }
 
 /* table of devices that work with this driver */
-struct usb_device_id au0828_usb_id_table [] = {
+struct usb_device_id au0828_usb_id_table[] = {
        { USB_DEVICE(0x2040, 0x7200),
                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
        { USB_DEVICE(0x2040, 0x7240),
@@ -198,6 +199,8 @@ struct usb_device_id au0828_usb_id_table [] = {
                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
        { USB_DEVICE(0x2040, 0x721b),
                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+       { USB_DEVICE(0x2040, 0x721e),
+               .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
        { USB_DEVICE(0x2040, 0x721f),
                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
        { USB_DEVICE(0x2040, 0x7280),
index d856de9f742f03521d62af59f0b91d0e441089e6..5765e86563761a3f2647104c294ccce1bce1c0d2 100644 (file)
@@ -91,7 +91,8 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
                status = usb_control_msg(dev->usbdev,
                                usb_sndctrlpipe(dev->usbdev, 0),
                                request,
-                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               USB_DIR_OUT | USB_TYPE_VENDOR |
+                                       USB_RECIP_DEVICE,
                                value, index,
                                cp, size, 1000);
 
index f0fcdb4769d73697e8d8a4ac9381854f2b9208f0..a882cf546d0aa5a0e0c1ff798a0b0b7f109d3c9e 100644 (file)
@@ -173,7 +173,8 @@ static int start_urb_transfer(struct au0828_dev *dev)
                purb->status = -EINPROGRESS;
                usb_fill_bulk_urb(purb,
                                  dev->usbdev,
-                                 usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE),
+                                 usb_rcvbulkpipe(dev->usbdev,
+                                       _AU0828_BULKPIPE),
                                  purb->transfer_buffer,
                                  URB_BUFSIZE,
                                  urb_completion,
index ddd2a7964dec25f179fdf7633ffca9ccf690a3cf..a07b7b88e5b8198148d00f748edcef316e98974a 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
 #include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <linux/video_decoder.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-
-#define I2C_NAME(s) (s)->name
-
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* ----------------------------------------------------------------------- */
 
 struct bt819 {
@@ -97,14 +78,9 @@ static struct timing timing_data[] = {
        {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
 };
 
-#define   I2C_BT819        0x8a
-
 /* ----------------------------------------------------------------------- */
 
-static inline int
-bt819_write (struct i2c_client *client,
-            u8                 reg,
-            u8                 value)
+static inline int bt819_write(struct i2c_client *client, u8 reg, u8 value)
 {
        struct bt819 *decoder = i2c_get_clientdata(client);
 
@@ -112,24 +88,15 @@ bt819_write (struct i2c_client *client,
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int
-bt819_setbit (struct i2c_client *client,
-             u8                 reg,
-             u8                 bit,
-             u8                 value)
+static inline int bt819_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
 {
        struct bt819 *decoder = i2c_get_clientdata(client);
 
        return bt819_write(client, reg,
-                          (decoder->
-                           reg[reg] & ~(1 << bit)) |
-                           (value ? (1 << bit) : 0));
+               (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
 }
 
-static int
-bt819_write_block (struct i2c_client *client,
-                  const u8          *data,
-                  unsigned int       len)
+static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
 {
        int ret = -1;
        u8 reg;
@@ -150,10 +117,9 @@ bt819_write_block (struct i2c_client *client,
                                    decoder->reg[reg++] = data[1];
                                len -= 2;
                                data += 2;
-                       } while (len >= 2 && data[0] == reg &&
-                                block_len < 32);
-                       if ((ret = i2c_master_send(client, block_data,
-                                                  block_len)) < 0)
+                       } while (len >= 2 && data[0] == reg && block_len < 32);
+                       ret = i2c_master_send(client, block_data, block_len);
+                       if (ret < 0)
                                break;
                }
        } else {
@@ -169,20 +135,17 @@ bt819_write_block (struct i2c_client *client,
        return ret;
 }
 
-static inline int
-bt819_read (struct i2c_client *client,
-           u8                 reg)
+static inline int bt819_read(struct i2c_client *client, u8 reg)
 {
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int
-bt819_init (struct i2c_client *client)
+static int bt819_init(struct i2c_client *client)
 {
        struct bt819 *decoder = i2c_get_clientdata(client);
 
        static unsigned char init[] = {
-               //0x1f, 0x00,     /* Reset */
+               /*0x1f, 0x00,*/     /* Reset */
                0x01, 0x59,     /* 0x01 input format */
                0x02, 0x00,     /* 0x02 temporal decimation */
                0x03, 0x12,     /* 0x03 Cropping msb */
@@ -218,12 +181,10 @@ bt819_init (struct i2c_client *client)
        struct timing *timing = &timing_data[decoder->norm];
 
        init[0x03 * 2 - 1] =
-           (((timing->vdelay >> 8) & 0x03) << 6) | (((timing->
-                                                      vactive >> 8) &
-                                                     0x03) << 4) |
-           (((timing->hdelay >> 8) & 0x03) << 2) | ((timing->
-                                                     hactive >> 8) &
-                                                    0x03);
+           (((timing->vdelay >> 8) & 0x03) << 6) |
+           (((timing->vactive >> 8) & 0x03) << 4) |
+           (((timing->hdelay >> 8) & 0x03) << 2) |
+           ((timing->hactive >> 8) & 0x03);
        init[0x04 * 2 - 1] = timing->vdelay & 0xff;
        init[0x05 * 2 - 1] = timing->vactive & 0xff;
        init[0x06 * 2 - 1] = timing->hdelay & 0xff;
@@ -238,27 +199,22 @@ bt819_init (struct i2c_client *client)
 
        /* init */
        return bt819_write_block(client, init, sizeof(init));
-
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int
-bt819_command (struct i2c_client *client,
-              unsigned int       cmd,
-              void              *arg)
+static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        int temp;
 
        struct bt819 *decoder = i2c_get_clientdata(client);
 
-       if (!decoder->initialized) {    // First call to bt819_init could be
-               bt819_init(client);     // without #FRST = 0
+       if (!decoder->initialized) {    /* First call to bt819_init could be */
+               bt819_init(client);     /* without #FRST = 0 */
                decoder->initialized = 1;
        }
 
        switch (cmd) {
-
        case 0:
                /* This is just for testing!!! */
                bt819_init(client);
@@ -274,8 +230,8 @@ bt819_command (struct i2c_client *client,
                             VIDEO_DECODER_CCIR;
                cap->inputs = 8;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case DECODER_GET_STATUS:
        {
@@ -285,9 +241,9 @@ bt819_command (struct i2c_client *client,
 
                status = bt819_read(client, 0x00);
                res = 0;
-               if ((status & 0x80)) {
+               if ((status & 0x80))
                        res |= DECODER_STATUS_GOOD;
-               }
+
                switch (decoder->norm) {
                case VIDEO_MODE_NTSC:
                        res |= DECODER_STATUS_NTSC;
@@ -297,28 +253,25 @@ bt819_command (struct i2c_client *client,
                        break;
                default:
                case VIDEO_MODE_AUTO:
-                       if ((status & 0x10)) {
+                       if ((status & 0x10))
                                res |= DECODER_STATUS_PAL;
-                       } else {
+                       else
                                res |= DECODER_STATUS_NTSC;
-                       }
                        break;
                }
                res |= DECODER_STATUS_COLOR;
                *iarg = res;
 
-               dprintk(1, KERN_INFO "%s: get status %x\n", I2C_NAME(client),
-                       *iarg);
-       }
+               v4l_dbg(1, debug, client, "get status %x\n", *iarg);
                break;
+       }
 
        case DECODER_SET_NORM:
        {
                int *iarg = arg;
                struct timing *timing = NULL;
 
-               dprintk(1, KERN_INFO "%s: set norm %x\n", I2C_NAME(client),
-                       *iarg);
+               v4l_dbg(1, debug, client, "set norm %x\n", *iarg);
 
                switch (*iarg) {
                case VIDEO_MODE_NTSC:
@@ -327,7 +280,7 @@ bt819_command (struct i2c_client *client,
                        bt819_setbit(client, 0x01, 5, 0);
                        bt819_write(client, 0x18, 0x68);
                        bt819_write(client, 0x19, 0x5d);
-                       //bt819_setbit(client, 0x1a,  5, 1);
+                       /* bt819_setbit(client, 0x1a,  5, 1); */
                        timing = &timing_data[VIDEO_MODE_NTSC];
                        break;
                case VIDEO_MODE_PAL:
@@ -336,7 +289,7 @@ bt819_command (struct i2c_client *client,
                        bt819_setbit(client, 0x01, 5, 1);
                        bt819_write(client, 0x18, 0x7f);
                        bt819_write(client, 0x19, 0x72);
-                       //bt819_setbit(client, 0x1a,  5, 0);
+                       /* bt819_setbit(client, 0x1a,  5, 0); */
                        timing = &timing_data[VIDEO_MODE_PAL];
                        break;
                case VIDEO_MODE_AUTO:
@@ -344,10 +297,7 @@ bt819_command (struct i2c_client *client,
                        bt819_setbit(client, 0x01, 1, 0);
                        break;
                default:
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: unsupported norm %d\n",
-                               I2C_NAME(client), *iarg);
+                       v4l_dbg(1, debug, client, "unsupported norm %x\n", *iarg);
                        return -EINVAL;
                }
 
@@ -366,19 +316,17 @@ bt819_command (struct i2c_client *client,
                }
 
                decoder->norm = *iarg;
-       }
                break;
+       }
 
        case DECODER_SET_INPUT:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_INFO "%s: set input %x\n", I2C_NAME(client),
-                       *iarg);
+               v4l_dbg(1, debug, client, "set input %x\n", *iarg);
 
-               if (*iarg < 0 || *iarg > 7) {
+               if (*iarg < 0 || *iarg > 7)
                        return -EINVAL;
-               }
 
                if (decoder->input != *iarg) {
                        decoder->input = *iarg;
@@ -391,52 +339,42 @@ bt819_command (struct i2c_client *client,
                                bt819_setbit(client, 0x1a, 1, 0);
                        }
                }
-       }
                break;
+       }
 
        case DECODER_SET_OUTPUT:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_INFO "%s: set output %x\n", I2C_NAME(client),
-                       *iarg);
+               v4l_dbg(1, debug, client, "set output %x\n", *iarg);
 
                /* not much choice of outputs */
-               if (*iarg != 0) {
+               if (*iarg != 0)
                        return -EINVAL;
-               }
-       }
                break;
+       }
 
        case DECODER_ENABLE_OUTPUT:
        {
                int *iarg = arg;
                int enable = (*iarg != 0);
 
-               dprintk(1, KERN_INFO "%s: enable output %x\n",
-                       I2C_NAME(client), *iarg);
+               v4l_dbg(1, debug, client, "enable output %x\n", *iarg);
 
                if (decoder->enable != enable) {
                        decoder->enable = enable;
-
-                       if (decoder->enable) {
-                               bt819_setbit(client, 0x16, 7, 0);
-                       } else {
-                               bt819_setbit(client, 0x16, 7, 1);
-                       }
+                       bt819_setbit(client, 0x16, 7, !enable);
                }
-       }
                break;
+       }
 
        case DECODER_SET_PICTURE:
        {
                struct video_picture *pic = arg;
 
-               dprintk(1,
-                       KERN_INFO
-                       "%s: set picture brightness %d contrast %d colour %d\n",
-                       I2C_NAME(client), pic->brightness, pic->contrast,
-                       pic->colour);
+               v4l_dbg(1, debug, client,
+                       "set picture brightness %d contrast %d colour %d\n",
+                       pic->brightness, pic->contrast, pic->colour);
 
 
                if (decoder->bright != pic->brightness) {
@@ -474,8 +412,8 @@ bt819_command (struct i2c_client *client,
                        bt819_write(client, 0x0f,
                                    128 - (decoder->hue >> 8));
                }
-       }
                break;
+       }
 
        default:
                return -EINVAL;
@@ -486,55 +424,44 @@ bt819_command (struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = {
-       I2C_BT819 >> 1,
-       I2C_CLIENT_END,
-};
-
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
+static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END };
 
-static struct i2c_driver i2c_driver_bt819;
+I2C_CLIENT_INSMOD;
 
-static int
-bt819_detect_client (struct i2c_adapter *adapter,
-                    int                 address,
-                    int                 kind)
+static int bt819_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       int i, id;
+       int i, ver;
        struct bt819 *decoder;
-       struct i2c_client *client;
-
-       dprintk(1,
-               KERN_INFO
-               "bt819: detecting bt819 client on address 0x%x\n",
-               address << 1);
+       const char *name;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_bt819;
+       ver = bt819_read(client, 0x17);
+       switch (ver & 0xf0) {
+       case 0x70:
+               name = "bt819a";
+               break;
+       case 0x60:
+               name = "bt817a";
+               break;
+       case 0x20:
+               name = "bt815a";
+               break;
+       default:
+               v4l_dbg(1, debug, client,
+                       "unknown chip version 0x%02x\n", ver);
+               return -ENODEV;
+       }
+
+       v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+                       client->addr << 1, client->adapter->name);
 
        decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
-       if (decoder == NULL) {
-               kfree(client);
+       if (decoder == NULL)
                return -ENOMEM;
-       }
        decoder->norm = VIDEO_MODE_NTSC;
        decoder->input = 0;
        decoder->enable = 1;
@@ -545,97 +472,33 @@ bt819_detect_client (struct i2c_adapter *adapter,
        decoder->initialized = 0;
        i2c_set_clientdata(client, decoder);
 
-       id = bt819_read(client, 0x17);
-       switch (id & 0xf0) {
-       case 0x70:
-               strlcpy(I2C_NAME(client), "bt819a", sizeof(I2C_NAME(client)));
-               break;
-       case 0x60:
-               strlcpy(I2C_NAME(client), "bt817a", sizeof(I2C_NAME(client)));
-               break;
-       case 0x20:
-               strlcpy(I2C_NAME(client), "bt815a", sizeof(I2C_NAME(client)));
-               break;
-       default:
-               dprintk(1,
-                       KERN_ERR
-                       "bt819: unknown chip version 0x%x (ver 0x%x)\n",
-                       id & 0xf0, id & 0x0f);
-               kfree(decoder);
-               kfree(client);
-               return 0;
-       }
-
-       i = i2c_attach_client(client);
-       if (i) {
-               kfree(client);
-               kfree(decoder);
-               return i;
-       }
-
        i = bt819_init(client);
-       if (i < 0) {
-               dprintk(1, KERN_ERR "%s_attach: init status %d\n",
-                       I2C_NAME(client), i);
-       } else {
-               dprintk(1,
-                       KERN_INFO
-                       "%s_attach: chip version 0x%x at address 0x%x\n",
-                       I2C_NAME(client), id & 0x0f,
-                       client->addr << 1);
-       }
-
+       if (i < 0)
+               v4l_dbg(1, debug, client, "init status %d\n", i);
        return 0;
 }
 
-static int
-bt819_attach_adapter (struct i2c_adapter *adapter)
-{
-       return i2c_probe(adapter, &addr_data, &bt819_detect_client);
-}
-
-static int
-bt819_detach_client (struct i2c_client *client)
+static int bt819_remove(struct i2c_client *client)
 {
-       struct bt819 *decoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(decoder);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_bt819 = {
-       .driver = {
-               .name = "bt819",
-       },
-
-       .id = I2C_DRIVERID_BT819,
+static const struct i2c_device_id bt819_id[] = {
+       { "bt819a", 0 },
+       { "bt817a", 0 },
+       { "bt815a", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, bt819_id);
 
-       .attach_adapter = bt819_attach_adapter,
-       .detach_client = bt819_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "bt819",
+       .driverid = I2C_DRIVERID_BT819,
        .command = bt819_command,
+       .probe = bt819_probe,
+       .remove = bt819_remove,
+       .id_table = bt819_id,
 };
-
-static int __init
-bt819_init_module (void)
-{
-       return i2c_add_driver(&i2c_driver_bt819);
-}
-
-static void __exit
-bt819_exit (void)
-{
-       i2c_del_driver(&i2c_driver_bt819);
-}
-
-module_init(bt819_init_module);
-module_exit(bt819_exit);
index ab2ce4d7b5de0dc3d822dd9b97d23f1bd358d807..4213867507f8d0f8c45579466adf120091f8c17e 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/video_encoder.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
 #include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
+#include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-
-#define I2C_NAME(s) (s)->name
-
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* ----------------------------------------------------------------------- */
 
 #define BT856_REG_OFFSET       0xDA
@@ -78,14 +59,9 @@ struct bt856 {
        int enable;
 };
 
-#define   I2C_BT856        0x88
-
 /* ----------------------------------------------------------------------- */
 
-static inline int
-bt856_write (struct i2c_client *client,
-            u8                 reg,
-            u8                 value)
+static inline int bt856_write(struct i2c_client *client, u8 reg, u8 value)
 {
        struct bt856 *encoder = i2c_get_clientdata(client);
 
@@ -93,46 +69,36 @@ bt856_write (struct i2c_client *client,
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int
-bt856_setbit (struct i2c_client *client,
-             u8                 reg,
-             u8                 bit,
-             u8                 value)
+static inline int bt856_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
 {
        struct bt856 *encoder = i2c_get_clientdata(client);
 
        return bt856_write(client, reg,
-                          (encoder->
-                           reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
-                           (value ? (1 << bit) : 0));
+               (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
+                               (value ? (1 << bit) : 0));
 }
 
-static void
-bt856_dump (struct i2c_client *client)
+static void bt856_dump(struct i2c_client *client)
 {
        int i;
        struct bt856 *encoder = i2c_get_clientdata(client);
 
-       printk(KERN_INFO "%s: register dump:", I2C_NAME(client));
+       v4l_info(client, "register dump:\n");
        for (i = 0; i < BT856_NR_REG; i += 2)
-               printk(" %02x", encoder->reg[i]);
-       printk("\n");
+               printk(KERN_CONT " %02x", encoder->reg[i]);
+       printk(KERN_CONT "\n");
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int
-bt856_command (struct i2c_client *client,
-              unsigned int       cmd,
-              void              *arg)
+static int bt856_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct bt856 *encoder = i2c_get_clientdata(client);
 
        switch (cmd) {
-
        case 0:
                /* This is just for testing!!! */
-               dprintk(1, KERN_INFO "bt856: init\n");
+               v4l_dbg(1, debug, client, "init\n");
                bt856_write(client, 0xdc, 0x18);
                bt856_write(client, 0xda, 0);
                bt856_write(client, 0xde, 0);
@@ -142,7 +108,6 @@ bt856_command (struct i2c_client *client,
                bt856_setbit(client, 0xdc, 4, 1);
 
                switch (encoder->norm) {
-
                case VIDEO_MODE_NTSC:
                        bt856_setbit(client, 0xdc, 2, 0);
                        break;
@@ -163,26 +128,23 @@ bt856_command (struct i2c_client *client,
        {
                struct video_encoder_capability *cap = arg;
 
-               dprintk(1, KERN_INFO "%s: get capabilities\n",
-                       I2C_NAME(client));
+               v4l_dbg(1, debug, client, "get capabilities\n");
 
                cap->flags = VIDEO_ENCODER_PAL |
                             VIDEO_ENCODER_NTSC |
                             VIDEO_ENCODER_CCIR;
                cap->inputs = 2;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case ENCODER_SET_NORM:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_INFO "%s: set norm %d\n", I2C_NAME(client),
-                       *iarg);
+               v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
 
                switch (*iarg) {
-
                case VIDEO_MODE_NTSC:
                        bt856_setbit(client, 0xdc, 2, 0);
                        break;
@@ -195,27 +157,23 @@ bt856_command (struct i2c_client *client,
 
                default:
                        return -EINVAL;
-
                }
                encoder->norm = *iarg;
                if (debug != 0)
                        bt856_dump(client);
-       }
                break;
+       }
 
        case ENCODER_SET_INPUT:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_INFO "%s: set input %d\n", I2C_NAME(client),
-                       *iarg);
+               v4l_dbg(1, debug, client, "set input %d\n", *iarg);
 
                /* We only have video bus.
                 * iarg = 0: input is from bt819
                 * iarg = 1: input is from ZR36060 */
-
                switch (*iarg) {
-
                case 0:
                        bt856_setbit(client, 0xde, 4, 0);
                        bt856_setbit(client, 0xde, 3, 1);
@@ -234,27 +192,24 @@ bt856_command (struct i2c_client *client,
                        break;
                default:
                        return -EINVAL;
-
                }
 
                if (debug != 0)
                        bt856_dump(client);
-       }
                break;
+       }
 
        case ENCODER_SET_OUTPUT:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_INFO "%s: set output %d\n", I2C_NAME(client),
-                       *iarg);
+               v4l_dbg(1, debug, client, "set output %d\n", *iarg);
 
                /* not much choice of outputs */
-               if (*iarg != 0) {
+               if (*iarg != 0)
                        return -EINVAL;
-               }
-       }
                break;
+       }
 
        case ENCODER_ENABLE_OUTPUT:
        {
@@ -262,10 +217,9 @@ bt856_command (struct i2c_client *client,
 
                encoder->enable = !!*iarg;
 
-               dprintk(1, KERN_INFO "%s: enable output %d\n",
-                       I2C_NAME(client), encoder->enable);
-       }
+               v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
                break;
+       }
 
        default:
                return -EINVAL;
@@ -276,64 +230,29 @@ bt856_command (struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END };
-
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
-static struct i2c_driver i2c_driver_bt856;
+I2C_CLIENT_INSMOD;
 
-static int
-bt856_detect_client (struct i2c_adapter *adapter,
-                    int                 address,
-                    int                 kind)
+static int bt856_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       int i;
-       struct i2c_client *client;
        struct bt856 *encoder;
 
-       dprintk(1,
-               KERN_INFO
-               "bt856.c: detecting bt856 client on address 0x%x\n",
-               address << 1);
-
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_bt856;
-       strlcpy(I2C_NAME(client), "bt856", sizeof(I2C_NAME(client)));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
-       if (encoder == NULL) {
-               kfree(client);
+       if (encoder == NULL)
                return -ENOMEM;
-       }
        encoder->norm = VIDEO_MODE_NTSC;
        encoder->enable = 1;
        i2c_set_clientdata(client, encoder);
 
-       i = i2c_attach_client(client);
-       if (i) {
-               kfree(client);
-               kfree(encoder);
-               return i;
-       }
-
        bt856_write(client, 0xdc, 0x18);
        bt856_write(client, 0xda, 0);
        bt856_write(client, 0xde, 0);
@@ -359,65 +278,26 @@ bt856_detect_client (struct i2c_adapter *adapter,
 
        if (debug != 0)
                bt856_dump(client);
-
-       dprintk(1, KERN_INFO "%s_attach: at address 0x%x\n", I2C_NAME(client),
-               client->addr << 1);
-
        return 0;
 }
 
-static int
-bt856_attach_adapter (struct i2c_adapter *adapter)
+static int bt856_remove(struct i2c_client *client)
 {
-       dprintk(1,
-               KERN_INFO
-               "bt856.c: starting probe for adapter %s (0x%x)\n",
-               I2C_NAME(adapter), adapter->id);
-       return i2c_probe(adapter, &addr_data, &bt856_detect_client);
-}
-
-static int
-bt856_detach_client (struct i2c_client *client)
-{
-       struct bt856 *encoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(encoder);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver i2c_driver_bt856 = {
-       .driver = {
-               .name = "bt856",
-       },
-
-       .id = I2C_DRIVERID_BT856,
+static const struct i2c_device_id bt856_id[] = {
+       { "bt856", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, bt856_id);
 
-       .attach_adapter = bt856_attach_adapter,
-       .detach_client = bt856_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "bt856",
+       .driverid = I2C_DRIVERID_BT856,
        .command = bt856_command,
+       .probe = bt856_probe,
+       .remove = bt856_remove,
+       .id_table = bt856_id,
 };
-
-static int __init
-bt856_init (void)
-{
-       return i2c_add_driver(&i2c_driver_bt856);
-}
-
-static void __exit
-bt856_exit (void)
-{
-       i2c_del_driver(&i2c_driver_bt856);
-}
-
-module_init(bt856_init);
-module_exit(bt856_exit);
index 96b415576f0deb8f5330eda6f758deb3cb76a73d..596f9e2376beccf140690bf92228ef973b32880f 100644 (file)
 */
 
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
 #include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
 #include <linux/i2c.h>
-
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
-
 #include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
+MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
+MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-#define        BT866_DEVNAME   "bt866"
-#define I2C_BT866      0x88
-
-MODULE_LICENSE("GPL");
-
-#define DEBUG(x)               /* Debug driver */
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /* ----------------------------------------------------------------------- */
 
 struct bt866 {
-       struct i2c_client *i2c;
-       int addr;
-       unsigned char reg[256];
+       u8 reg[256];
 
        int norm;
        int enable;
@@ -74,20 +60,45 @@ struct bt866 {
        int sat;
 };
 
-static int bt866_write(struct bt866 *dev,
-                       unsigned char subaddr, unsigned char data);
+static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
+{
+       struct bt866 *encoder = i2c_get_clientdata(client);
+       u8 buffer[2];
+       int err;
+
+       buffer[0] = subaddr;
+       buffer[1] = data;
+
+       encoder->reg[subaddr] = data;
+
+       v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
+
+       for (err = 0; err < 3;) {
+               if (i2c_master_send(client, buffer, 2) == 2)
+                       break;
+               err++;
+               v4l_warn(client, "error #%d writing to 0x%02x\n",
+                               err, subaddr);
+               schedule_timeout_interruptible(msecs_to_jiffies(100));
+       }
+       if (err == 3) {
+               v4l_warn(client, "giving up\n");
+               return -1;
+       }
+
+       return 0;
+}
 
-static int bt866_do_command(struct bt866 *encoder,
-                       unsigned int cmd, void *arg)
+static int bt866_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
+       struct bt866 *encoder = i2c_get_clientdata(client);
+
        switch (cmd) {
        case ENCODER_GET_CAPABILITIES:
        {
                struct video_encoder_capability *cap = arg;
 
-               DEBUG(printk
-                     (KERN_INFO "%s: get capabilities\n",
-                      encoder->i2c->name));
+               v4l_dbg(1, debug, client, "get capabilities\n");
 
                cap->flags
                        = VIDEO_ENCODER_PAL
@@ -95,18 +106,16 @@ static int bt866_do_command(struct bt866 *encoder,
                        | VIDEO_ENCODER_CCIR;
                cap->inputs = 2;
                cap->outputs = 1;
+               break;
        }
-       break;
 
        case ENCODER_SET_NORM:
        {
                int *iarg = arg;
 
-               DEBUG(printk(KERN_INFO "%s: set norm %d\n",
-                            encoder->i2c->name, *iarg));
+               v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
 
                switch (*iarg) {
-
                case VIDEO_MODE_NTSC:
                        break;
 
@@ -115,11 +124,10 @@ static int bt866_do_command(struct bt866 *encoder,
 
                default:
                        return -EINVAL;
-
                }
                encoder->norm = *iarg;
+               break;
        }
-       break;
 
        case ENCODER_SET_INPUT:
        {
@@ -155,7 +163,7 @@ static int bt866_do_command(struct bt866 *encoder,
                u8 val;
 
                for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
-                       bt866_write(encoder, init[i], init[i+1]);
+                       bt866_write(client, init[i], init[i+1]);
 
                val = encoder->reg[0xdc];
 
@@ -164,17 +172,16 @@ static int bt866_do_command(struct bt866 *encoder,
                else
                        val &= ~0x40; /* !CBSWAP */
 
-               bt866_write(encoder, 0xdc, val);
+               bt866_write(client, 0xdc, val);
 
                val = encoder->reg[0xcc];
                if (*iarg == 2)
                        val |= 0x01; /* OSDBAR */
                else
                        val &= ~0x01; /* !OSDBAR */
-               bt866_write(encoder, 0xcc, val);
+               bt866_write(client, 0xcc, val);
 
-               DEBUG(printk(KERN_INFO "%s: set input %d\n",
-                            encoder->i2c->name, *iarg));
+               v4l_dbg(1, debug, client, "set input %d\n", *iarg);
 
                switch (*iarg) {
                case 0:
@@ -183,48 +190,44 @@ static int bt866_do_command(struct bt866 *encoder,
                        break;
                default:
                        return -EINVAL;
-
                }
+               break;
        }
-       break;
 
        case ENCODER_SET_OUTPUT:
        {
                int *iarg = arg;
 
-               DEBUG(printk(KERN_INFO "%s: set output %d\n",
-                            encoder->i2c->name, *iarg));
+               v4l_dbg(1, debug, client, "set output %d\n", *iarg);
 
                /* not much choice of outputs */
                if (*iarg != 0)
                        return -EINVAL;
+               break;
        }
-       break;
 
        case ENCODER_ENABLE_OUTPUT:
        {
                int *iarg = arg;
                encoder->enable = !!*iarg;
 
-               DEBUG(printk
-                     (KERN_INFO "%s: enable output %d\n",
-                      encoder->i2c->name, encoder->enable));
+               v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
+               break;
        }
-       break;
 
        case 4711:
        {
                int *iarg = arg;
                __u8 val;
 
-               printk("bt866: square = %d\n", *iarg);
+               v4l_dbg(1, debug, client, "square %d\n", *iarg);
 
                val = encoder->reg[0xdc];
                if (*iarg)
                        val |= 1; /* SQUARE */
                else
                        val &= ~1; /* !SQUARE */
-               bt866_write(encoder, 0xdc, val);
+               bt866_write(client, 0xdc, val);
                break;
        }
 
@@ -235,141 +238,49 @@ static int bt866_do_command(struct bt866 *encoder,
        return 0;
 }
 
-static int bt866_write(struct bt866 *encoder,
-                       unsigned char subaddr, unsigned char data)
-{
-       unsigned char buffer[2];
-       int err;
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
-       buffer[0] = subaddr;
-       buffer[1] = data;
-
-       encoder->reg[subaddr] = data;
+I2C_CLIENT_INSMOD;
 
-       DEBUG(printk
-             ("%s: write 0x%02X = 0x%02X\n",
-              encoder->i2c->name, subaddr, data));
-
-       for (err = 0; err < 3;) {
-               if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
-                       break;
-               err++;
-               printk(KERN_WARNING "%s: I/O error #%d "
-                      "(write 0x%02x/0x%02x)\n",
-                      encoder->i2c->name, err, encoder->addr, subaddr);
-               schedule_timeout_interruptible(msecs_to_jiffies(100));
-       }
-       if (err == 3) {
-               printk(KERN_WARNING "%s: giving up\n",
-                      encoder->i2c->name);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int bt866_attach(struct i2c_adapter *adapter);
-static int bt866_detach(struct i2c_client *client);
-static int bt866_command(struct i2c_client *client,
-                        unsigned int cmd, void *arg);
-
-
-/* Addresses to scan */
-static unsigned short normal_i2c[]     = {I2C_BT866>>1, I2C_CLIENT_END};
-static unsigned short probe[2]         = {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short ignore[2]                = {I2C_CLIENT_END, I2C_CLIENT_END};
-
-static struct i2c_client_address_data addr_data = {
-       normal_i2c,
-       probe,
-       ignore,
-};
-
-static struct i2c_driver i2c_driver_bt866 = {
-       .driver.name = BT866_DEVNAME,
-       .id = I2C_DRIVERID_BT866,
-       .attach_adapter = bt866_attach,
-       .detach_client = bt866_detach,
-       .command = bt866_command
-};
-
-
-static struct i2c_client bt866_client_tmpl =
-{
-       .name = "(nil)",
-       .addr = 0,
-       .adapter = NULL,
-       .driver = &i2c_driver_bt866,
-};
-
-static int bt866_found_proc(struct i2c_adapter *adapter,
-                           int addr, int kind)
+static int bt866_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        struct bt866 *encoder;
-       struct i2c_client *client;
 
-       client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (client == NULL)
-               return -ENOMEM;
-       memcpy(client, &bt866_client_tmpl, sizeof(*client));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
-       if (encoder == NULL) {
-               kfree(client);
+       if (encoder == NULL)
                return -ENOMEM;
-       }
 
        i2c_set_clientdata(client, encoder);
-       client->adapter = adapter;
-       client->addr = addr;
-       sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
-
-       encoder->i2c = client;
-       encoder->addr = addr;
-       //encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
-
-       /* initialize */
-
-       i2c_attach_client(client);
-
-       return 0;
-}
-
-static int bt866_attach(struct i2c_adapter *adapter)
-{
-       if (adapter->id == I2C_HW_B_ZR36067)
-               return i2c_probe(adapter, &addr_data, bt866_found_proc);
-       return 0;
-}
-
-static int bt866_detach(struct i2c_client *client)
-{
-       struct bt866 *encoder = i2c_get_clientdata(client);
-
-       i2c_detach_client(client);
-       kfree(encoder);
-       kfree(client);
-
        return 0;
 }
 
-static int bt866_command(struct i2c_client *client,
-                        unsigned int cmd, void *arg)
+static int bt866_remove(struct i2c_client *client)
 {
-       struct bt866 *encoder = i2c_get_clientdata(client);
-       return bt866_do_command(encoder, cmd, arg);
-}
-
-static int __devinit bt866_init(void)
-{
-       i2c_add_driver(&i2c_driver_bt866);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static void __devexit bt866_exit(void)
+static int bt866_legacy_probe(struct i2c_adapter *adapter)
 {
-       i2c_del_driver(&i2c_driver_bt866);
+       return adapter->id == I2C_HW_B_ZR36067;
 }
 
-module_init(bt866_init);
-module_exit(bt866_exit);
+static const struct i2c_device_id bt866_id[] = {
+       { "bt866", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, bt866_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "bt866",
+       .driverid = I2C_DRIVERID_BT866,
+       .command = bt866_command,
+       .probe = bt866_probe,
+       .remove = bt866_remove,
+       .legacy_probe = bt866_legacy_probe,
+       .id_table = bt866_id,
+};
index 2cda15f829fdda6fb434b60f78e8b9e78cff22f7..dac5ccc9ba72a669de7a5558b722838f6ea914a3 100644 (file)
@@ -39,16 +39,16 @@ struct cx23885_board cx23885_boards[] = {
                .input          = {{
                        .type   = CX23885_VMUX_COMPOSITE1,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX23885_VMUX_COMPOSITE2,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX23885_VMUX_COMPOSITE3,
                        .vmux   = 2,
-               },{
+               }, {
                        .type   = CX23885_VMUX_COMPOSITE4,
                        .vmux   = 3,
-               }},
+               } },
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
                .name           = "Hauppauge WinTV-HVR1800lp",
@@ -57,19 +57,19 @@ struct cx23885_board cx23885_boards[] = {
                        .type   = CX23885_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xff00,
-               },{
+               }, {
                        .type   = CX23885_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0xff01,
-               },{
+               }, {
                        .type   = CX23885_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xff02,
-               },{
+               }, {
                        .type   = CX23885_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xff02,
-               }},
+               } },
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1800] = {
                .name           = "Hauppauge WinTV-HVR1800",
@@ -84,20 +84,20 @@ struct cx23885_board cx23885_boards[] = {
                                        CX25840_VIN5_CH2 |
                                        CX25840_VIN2_CH1,
                        .gpio0  = 0,
-               },{
+               }, {
                        .type   = CX23885_VMUX_COMPOSITE1,
                        .vmux   =       CX25840_VIN7_CH3 |
                                        CX25840_VIN4_CH2 |
                                        CX25840_VIN6_CH1,
                        .gpio0  = 0,
-               },{
+               }, {
                        .type   = CX23885_VMUX_SVIDEO,
                        .vmux   =       CX25840_VIN7_CH3 |
                                        CX25840_VIN4_CH2 |
                                        CX25840_VIN8_CH1 |
                                        CX25840_SVIDEO_ON,
                        .gpio0  = 0,
-               }},
+               } },
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1250] = {
                .name           = "Hauppauge WinTV-HVR1250",
@@ -106,19 +106,19 @@ struct cx23885_board cx23885_boards[] = {
                        .type   = CX23885_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xff00,
-               },{
+               }, {
                        .type   = CX23885_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0xff01,
-               },{
+               }, {
                        .type   = CX23885_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xff02,
-               },{
+               }, {
                        .type   = CX23885_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xff02,
-               }},
+               } },
        },
        [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
                .name           = "DViCO FusionHDTV5 Express",
@@ -169,43 +169,43 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x3400,
                .card      = CX23885_BOARD_UNKNOWN,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7600,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7800,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7801,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7809,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7911,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1250,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd500,
                .card      = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7790,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7797,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7710,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x7717,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
@@ -225,11 +225,11 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x8010,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1400,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd618,
                .card      = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb78,
                .card      = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
@@ -247,23 +247,25 @@ void cx23885_card_list(struct cx23885_dev *dev)
 
        if (0 == dev->pci->subsystem_vendor &&
            0 == dev->pci->subsystem_device) {
-               printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n"
-                      "%s: be autodetected.  Please pass card=<n> insmod option to\n"
-                      "%s: workaround that.  Redirect complaints to the vendor of\n"
-                      "%s: the TV card.  Best regards,\n"
+               printk(KERN_INFO
+                       "%s: Board has no valid PCIe Subsystem ID and can't\n"
+                      "%s: be autodetected. Pass card=<n> insmod option\n"
+                      "%s: to workaround that. Redirect complaints to the\n"
+                      "%s: vendor of the TV card.  Best regards,\n"
                       "%s:         -- tux\n",
                       dev->name, dev->name, dev->name, dev->name, dev->name);
        } else {
-               printk("%s: Your board isn't known (yet) to the driver.  You can\n"
-                      "%s: try to pick one of the existing card configs via\n"
+               printk(KERN_INFO
+                       "%s: Your board isn't known (yet) to the driver.\n"
+                      "%s: Try to pick one of the existing card configs via\n"
                       "%s: card=<n> insmod option.  Updating to the latest\n"
                       "%s: version might help as well.\n",
                       dev->name, dev->name, dev->name, dev->name);
        }
-       printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+       printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n",
               dev->name);
        for (i = 0; i < cx23885_bcount; i++)
-               printk("%s:    card=%d -> %s\n",
+               printk(KERN_INFO "%s:    card=%d -> %s\n",
                       dev->name, i, cx23885_boards[i].name);
 }
 
@@ -271,11 +273,11 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 {
        struct tveeprom tv;
 
-       tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data);
+       tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
+               eeprom_data);
 
        /* Make sure we support the board model */
-       switch (tv.model)
-       {
+       switch (tv.model) {
        case 71009:
                /* WinTV-HVR1200 (PCIe, Retail, full height)
                 * DVB-T and basic analog */
@@ -303,21 +305,51 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
        case 71999:
                /* WinTV-HVR1200 (PCIe, OEM, full height)
                 * DVB-T and basic analog */
-       case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
-       case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
-       case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
-       case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */
-       case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */
-       case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
-       case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
-       case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
-       case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
-       case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
-       case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */
-       case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */
-       case 79561: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
-       case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
-       case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
+       case 76601:
+               /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual
+                       channel ATSC and MPEG2 HW Encoder */
+       case 77001:
+               /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC
+                       and Basic analog */
+       case 77011:
+               /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC
+                       and Basic analog */
+       case 77041:
+               /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM
+                       and Basic analog */
+       case 77051:
+               /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM
+                       and Basic analog */
+       case 78011:
+               /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM,
+                       Dual channel ATSC and MPEG2 HW Encoder */
+       case 78501:
+               /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+                       Dual channel ATSC and MPEG2 HW Encoder */
+       case 78521:
+               /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+                       Dual channel ATSC and MPEG2 HW Encoder */
+       case 78531:
+               /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM,
+                       Dual channel ATSC and MPEG2 HW Encoder */
+       case 78631:
+               /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM,
+                       Dual channel ATSC and MPEG2 HW Encoder */
+       case 79001:
+               /* WinTV-HVR1250 (PCIe, Retail, IR, full height,
+                       ATSC and Basic analog */
+       case 79101:
+               /* WinTV-HVR1250 (PCIe, Retail, IR, half height,
+                       ATSC and Basic analog */
+       case 79561:
+               /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+                       ATSC and Basic analog */
+       case 79571:
+               /* WinTV-HVR1250 (PCIe, OEM, No IR, full height,
+                ATSC and Basic analog */
+       case 79671:
+               /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+                       ATSC and Basic analog */
        case 80019:
                /* WinTV-HVR1400 (Express Card, Retail, IR,
                 * DVB-T and Basic analog */
@@ -329,7 +361,8 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
                 * DVB-T and MPEG2 HW Encoder */
                break;
        default:
-               printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
+               printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n",
+                       dev->name, tv.model);
                break;
        }
 
@@ -352,7 +385,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
                return -EINVAL;
        }
 
-       switch(dev->board) {
+       switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -383,7 +416,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
 
 void cx23885_gpio_setup(struct cx23885_dev *dev)
 {
-       switch(dev->board) {
+       switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
                /* GPIO-0 cx24227 demodulator reset */
                cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
@@ -617,10 +650,3 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 }
 
 /* ------------------------------------------------------------------ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index beb3e61669a3373af706781717081aedf4dfa489..8f6fb2add7dea0c895c030597c0a5b9757c2155f 100644 (file)
@@ -37,12 +37,12 @@ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
 static unsigned int debug;
-module_param(debug,int,0644);
-MODULE_PARM_DESC(debug,"enable debug messages");
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
 
 static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
-MODULE_PARM_DESC(card,"card type");
+MODULE_PARM_DESC(card, "card type");
 
 #define dprintk(level, fmt, arg...)\
        do { if (debug >= level)\
@@ -364,13 +364,12 @@ void cx23885_wakeup(struct cx23885_tsport *port,
                list_del(&buf->vb.queue);
                wake_up(&buf->vb.done);
        }
-       if (list_empty(&q->active)) {
+       if (list_empty(&q->active))
                del_timer(&q->timeout);
-       } else {
+       else
                mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-       }
        if (bc != 1)
-               printk("%s: %d buffers handled (should be 1)\n",
+               printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
                       __func__, bc);
 }
 
@@ -381,8 +380,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
        unsigned int i, lines;
        u32 cdt;
 
-       if (ch->cmds_start == 0)
-       {
+       if (ch->cmds_start == 0) {
                dprintk(1, "%s() Erasing channel [%s]\n", __func__,
                        ch->name);
                cx_write(ch->ptr1_reg, 0);
@@ -418,15 +416,15 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
 
        /* write CMDS */
        if (ch->jumponly)
-               cx_write(ch->cmds_start +  0, 8);
+               cx_write(ch->cmds_start + 0, 8);
        else
-               cx_write(ch->cmds_start +  0, risc);
+               cx_write(ch->cmds_start + 0, risc);
        cx_write(ch->cmds_start +  4, 0); /* 64 bits 63-32 */
        cx_write(ch->cmds_start +  8, cdt);
        cx_write(ch->cmds_start + 12, (lines*16) >> 3);
        cx_write(ch->cmds_start + 16, ch->ctrl_start);
        if (ch->jumponly)
-               cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) );
+               cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
        else
                cx_write(ch->cmds_start + 20, 64 >> 2);
        for (i = 24; i < 80; i += 4)
@@ -436,9 +434,9 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
        cx_write(ch->ptr1_reg, ch->fifo_start);
        cx_write(ch->ptr2_reg, cdt);
        cx_write(ch->cnt2_reg, (lines*16) >> 3);
-       cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+       cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
 
-       dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n",
+       dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n",
                dev->bridge,
                ch->name,
                bpl,
@@ -469,43 +467,43 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
        u32 risc;
        unsigned int i, j, n;
 
-       printk("%s: %s - dma channel status dump\n",
+       printk(KERN_WARNING "%s: %s - dma channel status dump\n",
               dev->name, ch->name);
        for (i = 0; i < ARRAY_SIZE(name); i++)
-               printk("%s:   cmds: %-15s: 0x%08x\n",
+               printk(KERN_WARNING "%s:   cmds: %-15s: 0x%08x\n",
                       dev->name, name[i],
                       cx_read(ch->cmds_start + 4*i));
 
        for (i = 0; i < 4; i++) {
                risc = cx_read(ch->cmds_start + 4 * (i + 14));
-               printk("%s:   risc%d: ", dev->name, i);
+               printk(KERN_WARNING "%s:   risc%d: ", dev->name, i);
                cx23885_risc_decode(risc);
        }
        for (i = 0; i < (64 >> 2); i += n) {
                risc = cx_read(ch->ctrl_start + 4 * i);
                /* No consideration for bits 63-32 */
 
-               printk("%s:   (0x%08x) iq %x: ", dev->name,
+               printk(KERN_WARNING "%s:   (0x%08x) iq %x: ", dev->name,
                       ch->ctrl_start + 4 * i, i);
                n = cx23885_risc_decode(risc);
                for (j = 1; j < n; j++) {
                        risc = cx_read(ch->ctrl_start + 4 * (i + j));
-                       printk("%s:   iq %x: 0x%08x [ arg #%d ]\n",
+                       printk(KERN_WARNING "%s:   iq %x: 0x%08x [ arg #%d ]\n",
                               dev->name, i+j, risc, j);
                }
        }
 
-       printk("%s: fifo: 0x%08x -> 0x%x\n",
+       printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n",
               dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
-       printk("%s: ctrl: 0x%08x -> 0x%x\n",
+       printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n",
               dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
-       printk("%s:   ptr1_reg: 0x%08x\n",
+       printk(KERN_WARNING "%s:   ptr1_reg: 0x%08x\n",
               dev->name, cx_read(ch->ptr1_reg));
-       printk("%s:   ptr2_reg: 0x%08x\n",
+       printk(KERN_WARNING "%s:   ptr2_reg: 0x%08x\n",
               dev->name, cx_read(ch->ptr2_reg));
-       printk("%s:   cnt1_reg: 0x%08x\n",
+       printk(KERN_WARNING "%s:   cnt1_reg: 0x%08x\n",
               dev->name, cx_read(ch->cnt1_reg));
-       printk("%s:   cnt2_reg: 0x%08x\n",
+       printk(KERN_WARNING "%s:   cnt2_reg: 0x%08x\n",
               dev->name, cx_read(ch->cnt2_reg));
 }
 
@@ -515,13 +513,13 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
        struct cx23885_dev *dev = port->dev;
        unsigned int i, j, n;
 
-       printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+       printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n",
               dev->name, risc->cpu, (unsigned long)risc->dma);
        for (i = 0; i < (risc->size >> 2); i += n) {
-               printk("%s:   %04d: ", dev->name, i);
+               printk(KERN_INFO "%s:   %04d: ", dev->name, i);
                n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
                for (j = 1; j < n; j++)
-                       printk("%s:   %04d: 0x%08x [ arg #%d ]\n",
+                       printk(KERN_INFO "%s:   %04d: 0x%08x [ arg #%d ]\n",
                               dev->name, i + j, risc->cpu[i + j], j);
                if (risc->cpu[i] == cpu_to_le32(RISC_JUMP))
                        break;
@@ -600,7 +598,7 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev)
         * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
         * occur on the cx23887 bridge.
         */
-       if(dev->bridge == CX23885_BRIDGE_885)
+       if (dev->bridge == CX23885_BRIDGE_885)
                cx_clear(RDR_TLCTL0, 1 << 4);
 
        return 0;
@@ -608,13 +606,13 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev)
 
 static int get_resources(struct cx23885_dev *dev)
 {
-       if (request_mem_region(pci_resource_start(dev->pci,0),
-                              pci_resource_len(dev->pci,0),
+       if (request_mem_region(pci_resource_start(dev->pci, 0),
+                              pci_resource_len(dev->pci, 0),
                               dev->name))
                return 0;
 
        printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
-               dev->name, (unsigned long long)pci_resource_start(dev->pci,0));
+               dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
 
        return -EBUSY;
 }
@@ -623,7 +621,8 @@ static void cx23885_timeout(unsigned long data);
 int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
                                u32 reg, u32 mask, u32 value);
 
-static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
+static int cx23885_init_tsport(struct cx23885_dev *dev,
+       struct cx23885_tsport *port, int portno)
 {
        dprintk(1, "%s(portno=%d)\n", __func__, portno);
 
@@ -643,7 +642,18 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
        port->mpegq.timeout.data = (unsigned long)port;
        init_timer(&port->mpegq.timeout);
 
-       switch(portno) {
+       mutex_init(&port->frontends.lock);
+       INIT_LIST_HEAD(&port->frontends.felist);
+       port->frontends.active_fe_id = 0;
+
+       /* This should be hardcoded allow a single frontend
+        * attachment to this tsport, keeping the -dvb.c
+        * code clean and safe.
+        */
+       if (!port->num_frontends)
+               port->num_frontends = 1;
+
+       switch (portno) {
        case 1:
                port->reg_gpcnt          = VID_B_GPCNT;
                port->reg_gpcnt_ctl      = VID_B_GPCNT_CTL;
@@ -744,13 +754,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        mutex_unlock(&devlist);
 
        /* Configure the internal memory */
-       if(dev->pci->device == 0x8880) {
+       if (dev->pci->device == 0x8880) {
                dev->bridge = CX23885_BRIDGE_887;
                /* Apply a sensible clock frequency for the PCIe bridge */
                dev->clk_freq = 25000000;
                dev->sram_channels = cx23887_sram_channels;
        } else
-       if(dev->pci->device == 0x8852) {
+       if (dev->pci->device == 0x8852) {
                dev->bridge = CX23885_BRIDGE_885;
                /* Apply a sensible clock frequency for the PCIe bridge */
                dev->clk_freq = 28000000;
@@ -831,8 +841,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        }
 
        /* PCIe stuff */
-       dev->lmmio = ioremap(pci_resource_start(dev->pci,0),
-                            pci_resource_len(dev->pci,0));
+       dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
+                            pci_resource_len(dev->pci, 0));
 
        dev->bmmio = (u8 __iomem *)dev->lmmio;
 
@@ -862,7 +872,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        cx23885_i2c_register(&dev->i2c_bus[1]);
        cx23885_i2c_register(&dev->i2c_bus[2]);
        cx23885_card_setup(dev);
-       cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
+       cx23885_call_i2c_clients(&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
        cx23885_ir_init(dev);
 
        if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
@@ -908,8 +918,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 
 static void cx23885_dev_unregister(struct cx23885_dev *dev)
 {
-       release_mem_region(pci_resource_start(dev->pci,0),
-                          pci_resource_len(dev->pci,0));
+       release_mem_region(pci_resource_start(dev->pci, 0),
+                          pci_resource_len(dev->pci, 0));
 
        if (!atomic_dec_and_test(&dev->refcount))
                return;
@@ -936,7 +946,7 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
        iounmap(dev->lmmio);
 }
 
-static __le32cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
+static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
                               unsigned int offset, u32 sync_line,
                               unsigned int bpl, unsigned int padding,
                               unsigned int lines)
@@ -957,31 +967,31 @@ static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
                }
                if (bpl <= sg_dma_len(sg)-offset) {
                        /* fits into current chunk */
-                       *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
-                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                       *(rp++)=cpu_to_le32(0); /* bits 63-32 */
-                       offset+=bpl;
+                       *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+                       *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
+                       *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+                       offset += bpl;
                } else {
                        /* scanline needs to be split */
                        todo = bpl;
-                       *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+                       *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|
                                            (sg_dma_len(sg)-offset));
-                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                       *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+                       *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
+                       *(rp++) = cpu_to_le32(0); /* bits 63-32 */
                        todo -= (sg_dma_len(sg)-offset);
                        offset = 0;
                        sg++;
                        while (todo > sg_dma_len(sg)) {
-                               *(rp++)=cpu_to_le32(RISC_WRITE|
+                               *(rp++) = cpu_to_le32(RISC_WRITE|
                                                    sg_dma_len(sg));
-                               *(rp++)=cpu_to_le32(sg_dma_address(sg));
-                               *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+                               *(rp++) = cpu_to_le32(sg_dma_address(sg));
+                               *(rp++) = cpu_to_le32(0); /* bits 63-32 */
                                todo -= sg_dma_len(sg);
                                sg++;
                        }
-                       *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
-                       *(rp++)=cpu_to_le32(sg_dma_address(sg));
-                       *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+                       *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+                       *(rp++) = cpu_to_le32(sg_dma_address(sg));
+                       *(rp++) = cpu_to_le32(0); /* bits 63-32 */
                        offset += todo;
                }
                offset += padding;
@@ -1010,9 +1020,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
           can cause next bpl to start close to a page border.  First DMA
           region may be smaller than PAGE_SIZE */
        /* write and jump need and extra dword */
-       instructions  = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+       instructions  = fields * (1 + ((bpl + padding) * lines)
+               / PAGE_SIZE + lines);
        instructions += 2;
-       if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+       rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+       if (rc < 0)
                return rc;
 
        /* write risc instructions */
@@ -1026,7 +1038,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
        return 0;
 }
 
@@ -1048,7 +1060,8 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
        instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
        instructions += 1;
 
-       if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+       rc = btcx_riscmem_alloc(pci, risc, instructions*12);
+       if (rc < 0)
                return rc;
 
        /* write risc instructions */
@@ -1057,7 +1070,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
        return 0;
 }
 
@@ -1067,7 +1080,8 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
        __le32 *rp;
        int rc;
 
-       if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
+       rc = btcx_riscmem_alloc(pci, risc, 4*16);
+       if (rc < 0)
                return rc;
 
        /* write risc instructions */
@@ -1161,22 +1175,23 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
 
        /* setup fifo + format */
        cx23885_sram_channel_setup(dev,
-                                  &dev->sram_channels[ port->sram_chno ],
+                                  &dev->sram_channels[port->sram_chno],
                                   port->ts_packet_size, buf->risc.dma);
-       if(debug > 5) {
-               cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] );
+       if (debug > 5) {
+               cx23885_sram_channel_dump(dev,
+                       &dev->sram_channels[port->sram_chno]);
                cx23885_risc_disasm(port, &buf->risc);
        }
 
        /* write TS length to chip */
        cx_write(port->reg_lngth, buf->vb.width);
 
-       if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
-               (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
-               printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
+       if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
+               (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
+               printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n",
                        __func__,
                        cx23885_boards[dev->board].portb,
-                       cx23885_boards[dev->board].portc );
+                       cx23885_boards[dev->board].portc);
                return -EINVAL;
        }
 
@@ -1186,7 +1201,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        udelay(100);
 
        /* If the port supports SRC SELECT, configure it */
-       if(port->reg_src_sel)
+       if (port->reg_src_sel)
                cx_write(port->reg_src_sel, port->src_sel_val);
 
        cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
@@ -1195,7 +1210,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
        udelay(100);
 
-       // NOTE: this is 2 (reserved) for portb, does it matter?
+       /* NOTE: this is 2 (reserved) for portb, does it matter? */
        /* reset counter to zero */
        cx_write(port->reg_gpcnt_ctl, 3);
        q->count = 1;
@@ -1229,11 +1244,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
                cx_write(ALT_PIN_OUT_SEL, 0x10100045);
        }
 
-       switch(dev->bridge) {
+       switch (dev->bridge) {
        case CX23885_BRIDGE_885:
        case CX23885_BRIDGE_887:
                /* enable irqs */
-               dprintk(1, "%s() enabling TS int's and DMA\n", __func__ );
+               dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
                cx_set(port->reg_ts_int_msk,  port->ts_int_msk_val);
                cx_set(port->reg_dma_ctl, port->dma_ctl_val);
                cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
@@ -1292,8 +1307,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
        struct cx23885_buffer *buf;
 
        dprintk(5, "%s()\n", __func__);
-       if (list_empty(&q->active))
-       {
+       if (list_empty(&q->active)) {
                struct cx23885_buffer *prev;
                prev = NULL;
 
@@ -1311,7 +1325,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
                                buf->vb.state = VIDEOBUF_ACTIVE;
                                buf->count    = q->count++;
                                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-                               dprintk(5, "[%p/%d] restart_queue - first active\n",
+                               dprintk(5, "[%p/%d] restart_queue - f/active\n",
                                        buf, buf->vb.i);
 
                        } else if (prev->vb.width  == buf->vb.width  &&
@@ -1322,8 +1336,9 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
                                buf->vb.state = VIDEOBUF_ACTIVE;
                                buf->count    = q->count++;
                                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-                               prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
-                               dprintk(5,"[%p/%d] restart_queue - move to active\n",
+                               /* 64 bit bits 63-32 */
+                               prev->risc.jmp[2] = cpu_to_le32(0);
+                               dprintk(5, "[%p/%d] restart_queue - m/active\n",
                                        buf, buf->vb.i);
                        } else {
                                return 0;
@@ -1362,7 +1377,8 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
                buf->vb.size   = size;
                buf->vb.field  = field /*V4L2_FIELD_TOP*/;
 
-               if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+               rc = videobuf_iolock(q, &buf->vb, NULL);
+               if (0 != rc)
                        goto fail;
                cx23885_risc_databuffer(dev->pci, &buf->risc,
                                        videobuf_to_dma(&buf->vb)->sglist,
@@ -1388,7 +1404,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
        if (list_empty(&cx88q->active)) {
-               dprintk( 1, "queue is empty - first active\n" );
+               dprintk(1, "queue is empty - first active\n");
                list_add_tail(&buf->vb.queue, &cx88q->active);
                cx23885_start_dma(port, cx88q, buf);
                buf->vb.state = VIDEOBUF_ACTIVE;
@@ -1397,7 +1413,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
                dprintk(1, "[%p/%d] %s - first active\n",
                        buf, buf->vb.i, __func__);
        } else {
-               dprintk( 1, "queue is not empty - append to active\n" );
+               dprintk(1, "queue is not empty - append to active\n");
                prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
                                  vb.queue);
                list_add_tail(&buf->vb.queue, &cx88q->active);
@@ -1405,7 +1421,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
                buf->count    = cx88q->count++;
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
-               dprintk( 1, "[%p/%d] %s - append to active\n",
+               dprintk(1, "[%p/%d] %s - append to active\n",
                         buf, buf->vb.i, __func__);
        }
 }
@@ -1431,7 +1447,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
                        buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
        }
        if (restart) {
-               dprintk(1, "restarting queue\n" );
+               dprintk(1, "restarting queue\n");
                cx23885_restart_queue(port, q);
        }
        spin_unlock_irqrestore(&port->slock, flags);
@@ -1453,10 +1469,11 @@ static void cx23885_timeout(unsigned long data)
        struct cx23885_tsport *port = (struct cx23885_tsport *)data;
        struct cx23885_dev *dev = port->dev;
 
-       dprintk(1, "%s()\n",__func__);
+       dprintk(1, "%s()\n", __func__);
 
        if (debug > 5)
-               cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+               cx23885_sram_channel_dump(dev,
+                       &dev->sram_channels[port->sram_chno]);
 
        cx23885_stop_dma(port);
        do_cancel_buffers(port, "timeout", 1);
@@ -1532,16 +1549,23 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
        if ((status & VID_BC_MSK_OPC_ERR) ||
                (status & VID_BC_MSK_BAD_PKT) ||
                (status & VID_BC_MSK_SYNC) ||
-               (status & VID_BC_MSK_OF))
-       {
+               (status & VID_BC_MSK_OF)) {
+
                if (status & VID_BC_MSK_OPC_ERR)
-                       dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
+                       dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n",
+                               VID_BC_MSK_OPC_ERR);
+
                if (status & VID_BC_MSK_BAD_PKT)
-                       dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT);
+                       dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n",
+                               VID_BC_MSK_BAD_PKT);
+
                if (status & VID_BC_MSK_SYNC)
-                       dprintk(7, " (VID_BC_MSK_SYNC    0x%08x)\n", VID_BC_MSK_SYNC);
+                       dprintk(7, " (VID_BC_MSK_SYNC    0x%08x)\n",
+                               VID_BC_MSK_SYNC);
+
                if (status & VID_BC_MSK_OF)
-                       dprintk(7, " (VID_BC_MSK_OF      0x%08x)\n", VID_BC_MSK_OF);
+                       dprintk(7, " (VID_BC_MSK_OF      0x%08x)\n",
+                               VID_BC_MSK_OF);
 
                printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
 
@@ -1595,7 +1619,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        ts2_status = cx_read(VID_C_INT_STAT);
        ts2_mask = cx_read(VID_C_INT_MSK);
 
-       if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
+       if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0))
                goto out;
 
        vida_count = cx_read(VID_A_GPCNT);
@@ -1610,38 +1634,56 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
                ts2_status, ts2_mask, ts2_count);
 
-       if ( (pci_status & PCI_MSK_RISC_RD) ||
-            (pci_status & PCI_MSK_RISC_WR) ||
-            (pci_status & PCI_MSK_AL_RD) ||
-            (pci_status & PCI_MSK_AL_WR) ||
-            (pci_status & PCI_MSK_APB_DMA) ||
-            (pci_status & PCI_MSK_VID_C) ||
-            (pci_status & PCI_MSK_VID_B) ||
-            (pci_status & PCI_MSK_VID_A) ||
-            (pci_status & PCI_MSK_AUD_INT) ||
-            (pci_status & PCI_MSK_AUD_EXT) )
-       {
+       if ((pci_status & PCI_MSK_RISC_RD) ||
+           (pci_status & PCI_MSK_RISC_WR) ||
+           (pci_status & PCI_MSK_AL_RD) ||
+           (pci_status & PCI_MSK_AL_WR) ||
+           (pci_status & PCI_MSK_APB_DMA) ||
+           (pci_status & PCI_MSK_VID_C) ||
+           (pci_status & PCI_MSK_VID_B) ||
+           (pci_status & PCI_MSK_VID_A) ||
+           (pci_status & PCI_MSK_AUD_INT) ||
+           (pci_status & PCI_MSK_AUD_EXT)) {
 
                if (pci_status & PCI_MSK_RISC_RD)
-                       dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n", PCI_MSK_RISC_RD);
+                       dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
+                               PCI_MSK_RISC_RD);
+
                if (pci_status & PCI_MSK_RISC_WR)
-                       dprintk(7, " (PCI_MSK_RISC_WR   0x%08x)\n", PCI_MSK_RISC_WR);
+                       dprintk(7, " (PCI_MSK_RISC_WR   0x%08x)\n",
+                               PCI_MSK_RISC_WR);
+
                if (pci_status & PCI_MSK_AL_RD)
-                       dprintk(7, " (PCI_MSK_AL_RD     0x%08x)\n", PCI_MSK_AL_RD);
+                       dprintk(7, " (PCI_MSK_AL_RD     0x%08x)\n",
+                               PCI_MSK_AL_RD);
+
                if (pci_status & PCI_MSK_AL_WR)
-                       dprintk(7, " (PCI_MSK_AL_WR     0x%08x)\n", PCI_MSK_AL_WR);
+                       dprintk(7, " (PCI_MSK_AL_WR     0x%08x)\n",
+                               PCI_MSK_AL_WR);
+
                if (pci_status & PCI_MSK_APB_DMA)
-                       dprintk(7, " (PCI_MSK_APB_DMA   0x%08x)\n", PCI_MSK_APB_DMA);
+                       dprintk(7, " (PCI_MSK_APB_DMA   0x%08x)\n",
+                               PCI_MSK_APB_DMA);
+
                if (pci_status & PCI_MSK_VID_C)
-                       dprintk(7, " (PCI_MSK_VID_C     0x%08x)\n", PCI_MSK_VID_C);
+                       dprintk(7, " (PCI_MSK_VID_C     0x%08x)\n",
+                               PCI_MSK_VID_C);
+
                if (pci_status & PCI_MSK_VID_B)
-                       dprintk(7, " (PCI_MSK_VID_B     0x%08x)\n", PCI_MSK_VID_B);
+                       dprintk(7, " (PCI_MSK_VID_B     0x%08x)\n",
+                               PCI_MSK_VID_B);
+
                if (pci_status & PCI_MSK_VID_A)
-                       dprintk(7, " (PCI_MSK_VID_A     0x%08x)\n", PCI_MSK_VID_A);
+                       dprintk(7, " (PCI_MSK_VID_A     0x%08x)\n",
+                               PCI_MSK_VID_A);
+
                if (pci_status & PCI_MSK_AUD_INT)
-                       dprintk(7, " (PCI_MSK_AUD_INT   0x%08x)\n", PCI_MSK_AUD_INT);
+                       dprintk(7, " (PCI_MSK_AUD_INT   0x%08x)\n",
+                               PCI_MSK_AUD_INT);
+
                if (pci_status & PCI_MSK_AUD_EXT)
-                       dprintk(7, " (PCI_MSK_AUD_EXT   0x%08x)\n", PCI_MSK_AUD_EXT);
+                       dprintk(7, " (PCI_MSK_AUD_EXT   0x%08x)\n",
+                               PCI_MSK_AUD_EXT);
 
        }
 
@@ -1753,13 +1795,13 @@ static struct pci_device_id cx23885_pci_tbl[] = {
                .device       = 0x8852,
                .subvendor    = PCI_ANY_ID,
                .subdevice    = PCI_ANY_ID,
-       },{
+       }, {
                /* CX23887 Rev 2 */
                .vendor       = 0x14f1,
                .device       = 0x8880,
                .subvendor    = PCI_ANY_ID,
                .subdevice    = PCI_ANY_ID,
-       },{
+       }, {
                /* --- end of list --- */
        }
 };
@@ -1797,9 +1839,3 @@ module_init(cx23885_init);
 module_exit(cx23885_fini);
 
 /* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index 24bd18327aa0f50b924bdf69527a5e373937c7fb..e1aac07b3158a42bd32210f1d3d0a123b09cb940 100644 (file)
@@ -78,19 +78,19 @@ static int dvb_buf_prepare(struct videobuf_queue *q,
                           struct videobuf_buffer *vb, enum v4l2_field field)
 {
        struct cx23885_tsport *port = q->priv_data;
-       return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field);
+       return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
 }
 
 static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        struct cx23885_tsport *port = q->priv_data;
-       cx23885_buf_queue(port, (struct cx23885_buffer*)vb);
+       cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
 }
 
 static void dvb_buf_release(struct videobuf_queue *q,
                            struct videobuf_buffer *vb)
 {
-       cx23885_free_buffer(q, (struct cx23885_buffer*)vb);
+       cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
 }
 
 static struct videobuf_queue_ops dvb_qops = {
@@ -312,19 +312,25 @@ static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_i2c *i2c_bus = NULL;
+       struct videobuf_dvb_frontend *fe0;
+
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+       if (!fe0)
+               return -EINVAL;
 
        /* init struct videobuf_dvb */
-       port->dvb.name = dev->name;
+       fe0->dvb.name = dev->name;
 
        /* init frontend */
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
                i2c_bus = &dev->i2c_bus[0];
-               port->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &hauppauge_generic_config,
                                                &i2c_bus->i2c_adap);
-               if (port->dvb.frontend != NULL) {
-                       dvb_attach(mt2131_attach, port->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(mt2131_attach, fe0->dvb.frontend,
                                   &i2c_bus->i2c_adap,
                                   &hauppauge_generic_tunerconfig, 0);
                }
@@ -333,27 +339,27 @@ static int dvb_register(struct cx23885_tsport *port)
                i2c_bus = &dev->i2c_bus[0];
                switch (alt_tuner) {
                case 1:
-                       port->dvb.frontend =
+                       fe0->dvb.frontend =
                                dvb_attach(s5h1409_attach,
                                           &hauppauge_ezqam_config,
                                           &i2c_bus->i2c_adap);
-                       if (port->dvb.frontend != NULL) {
-                               dvb_attach(tda829x_attach, port->dvb.frontend,
+                       if (fe0->dvb.frontend != NULL) {
+                               dvb_attach(tda829x_attach, fe0->dvb.frontend,
                                           &dev->i2c_bus[1].i2c_adap, 0x42,
                                           &tda829x_no_probe);
-                               dvb_attach(tda18271_attach, port->dvb.frontend,
+                               dvb_attach(tda18271_attach, fe0->dvb.frontend,
                                           0x60, &dev->i2c_bus[1].i2c_adap,
                                           &hauppauge_tda18271_config);
                        }
                        break;
                case 0:
                default:
-                       port->dvb.frontend =
+                       fe0->dvb.frontend =
                                dvb_attach(s5h1409_attach,
                                           &hauppauge_generic_config,
                                           &i2c_bus->i2c_adap);
-                       if (port->dvb.frontend != NULL)
-                               dvb_attach(mt2131_attach, port->dvb.frontend,
+                       if (fe0->dvb.frontend != NULL)
+                               dvb_attach(mt2131_attach, fe0->dvb.frontend,
                                           &i2c_bus->i2c_adap,
                                           &hauppauge_generic_tunerconfig, 0);
                        break;
@@ -361,42 +367,42 @@ static int dvb_register(struct cx23885_tsport *port)
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
                i2c_bus = &dev->i2c_bus[0];
-               port->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &hauppauge_hvr1800lp_config,
                                                &i2c_bus->i2c_adap);
-               if (port->dvb.frontend != NULL) {
-                       dvb_attach(mt2131_attach, port->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(mt2131_attach, fe0->dvb.frontend,
                                   &i2c_bus->i2c_adap,
                                   &hauppauge_generic_tunerconfig, 0);
                }
                break;
        case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
                i2c_bus = &dev->i2c_bus[0];
-               port->dvb.frontend = dvb_attach(lgdt330x_attach,
+               fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
                                                &fusionhdtv_5_express,
                                                &i2c_bus->i2c_adap);
-               if (port->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, port->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &i2c_bus->i2c_adap, 0x61,
                                   TUNER_LG_TDVS_H06XF);
                }
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
                i2c_bus = &dev->i2c_bus[1];
-               port->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &hauppauge_hvr1500q_config,
                                                &dev->i2c_bus[0].i2c_adap);
-               if (port->dvb.frontend != NULL)
-                       dvb_attach(xc5000_attach, port->dvb.frontend,
+               if (fe0->dvb.frontend != NULL)
+                       dvb_attach(xc5000_attach, fe0->dvb.frontend,
                                   &i2c_bus->i2c_adap,
                                   &hauppauge_hvr1500q_tunerconfig);
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
                i2c_bus = &dev->i2c_bus[1];
-               port->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &hauppauge_hvr1500_config,
                                                &dev->i2c_bus[0].i2c_adap);
-               if (port->dvb.frontend != NULL) {
+               if (fe0->dvb.frontend != NULL) {
                        struct dvb_frontend *fe;
                        struct xc2028_config cfg = {
                                .i2c_adap  = &i2c_bus->i2c_adap,
@@ -409,7 +415,7 @@ static int dvb_register(struct cx23885_tsport *port)
                        };
 
                        fe = dvb_attach(xc2028_attach,
-                                       port->dvb.frontend, &cfg);
+                                       fe0->dvb.frontend, &cfg);
                        if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
                }
@@ -417,24 +423,24 @@ static int dvb_register(struct cx23885_tsport *port)
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
                i2c_bus = &dev->i2c_bus[0];
-               port->dvb.frontend = dvb_attach(tda10048_attach,
+               fe0->dvb.frontend = dvb_attach(tda10048_attach,
                        &hauppauge_hvr1200_config,
                        &i2c_bus->i2c_adap);
-               if (port->dvb.frontend != NULL) {
-                       dvb_attach(tda829x_attach, port->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda829x_attach, fe0->dvb.frontend,
                                &dev->i2c_bus[1].i2c_adap, 0x42,
                                &tda829x_no_probe);
-                       dvb_attach(tda18271_attach, port->dvb.frontend,
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
                                0x60, &dev->i2c_bus[1].i2c_adap,
                                &hauppauge_hvr1200_tuner_config);
                }
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
                i2c_bus = &dev->i2c_bus[0];
-               port->dvb.frontend = dvb_attach(dib7000p_attach,
+               fe0->dvb.frontend = dvb_attach(dib7000p_attach,
                        &i2c_bus->i2c_adap,
                        0x12, &hauppauge_hvr1400_dib7000_config);
-               if (port->dvb.frontend != NULL) {
+               if (fe0->dvb.frontend != NULL) {
                        struct dvb_frontend *fe;
                        struct xc2028_config cfg = {
                                .i2c_adap  = &dev->i2c_bus[1].i2c_adap,
@@ -444,12 +450,13 @@ static int dvb_register(struct cx23885_tsport *port)
                                .fname   = XC3028L_DEFAULT_FIRMWARE,
                                .max_len = 64,
                                .demod   = 5000,
-                               /* This is true for all demods with v36 firmware? */
+                               /* This is true for all demods with
+                                       v36 firmware? */
                                .type    = XC2028_D2633,
                        };
 
                        fe = dvb_attach(xc2028_attach,
-                                       port->dvb.frontend, &cfg);
+                                       fe0->dvb.frontend, &cfg);
                        if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
                }
@@ -457,25 +464,25 @@ static int dvb_register(struct cx23885_tsport *port)
        case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
                i2c_bus = &dev->i2c_bus[port->nr - 1];
 
-               port->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &dvico_s5h1409_config,
                                                &i2c_bus->i2c_adap);
-               if (port->dvb.frontend == NULL)
-                       port->dvb.frontend = dvb_attach(s5h1411_attach,
+               if (fe0->dvb.frontend == NULL)
+                       fe0->dvb.frontend = dvb_attach(s5h1411_attach,
                                                        &dvico_s5h1411_config,
                                                        &i2c_bus->i2c_adap);
-               if (port->dvb.frontend != NULL)
-                       dvb_attach(xc5000_attach, port->dvb.frontend,
+               if (fe0->dvb.frontend != NULL)
+                       dvb_attach(xc5000_attach, fe0->dvb.frontend,
                                   &i2c_bus->i2c_adap,
                                   &dvico_xc5000_tunerconfig);
                break;
        case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
                i2c_bus = &dev->i2c_bus[port->nr - 1];
 
-               port->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_xc3028,
                                               &i2c_bus->i2c_adap);
-               if (port->dvb.frontend != NULL) {
+               if (fe0->dvb.frontend != NULL) {
                        struct dvb_frontend      *fe;
                        struct xc2028_config      cfg = {
                                .i2c_adap  = &i2c_bus->i2c_adap,
@@ -487,7 +494,7 @@ static int dvb_register(struct cx23885_tsport *port)
                                .demod       = XC3028_FE_ZARLINK456,
                        };
 
-                       fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+                       fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
                                        &cfg);
                        if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
@@ -497,10 +504,10 @@ static int dvb_register(struct cx23885_tsport *port)
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
                i2c_bus = &dev->i2c_bus[0];
 
-               port->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                        &dvico_fusionhdtv_xc3028,
                        &i2c_bus->i2c_adap);
-               if (port->dvb.frontend != NULL) {
+               if (fe0->dvb.frontend != NULL) {
                        struct dvb_frontend      *fe;
                        struct xc2028_config      cfg = {
                                .i2c_adap  = &dev->i2c_bus[1].i2c_adap,
@@ -512,73 +519,108 @@ static int dvb_register(struct cx23885_tsport *port)
                                .demod       = XC3028_FE_ZARLINK456,
                        };
 
-                       fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+                       fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
                                &cfg);
                        if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
                }
                break;
        default:
-               printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+               printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
+                       " isn't supported yet\n",
                       dev->name);
                break;
        }
-       if (NULL == port->dvb.frontend) {
-               printk("%s: frontend initialization failed\n", dev->name);
+       if (NULL == fe0->dvb.frontend) {
+               printk(KERN_ERR "%s: frontend initialization failed\n",
+                       dev->name);
                return -1;
        }
        /* define general-purpose callback pointer */
-       port->dvb.frontend->callback = cx23885_tuner_callback;
+       fe0->dvb.frontend->callback = cx23885_tuner_callback;
 
        /* Put the analog decoder in standby to keep it quiet */
        cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
 
-       if (port->dvb.frontend->ops.analog_ops.standby)
-               port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
+       if (fe0->dvb.frontend->ops.analog_ops.standby)
+               fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
 
        /* register everything */
-       return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
-                                    &dev->pci->dev, adapter_nr);
+       return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+               &dev->pci->dev, adapter_nr, 0);
+
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
 {
+
+       struct videobuf_dvb_frontend *fe0;
        struct cx23885_dev *dev = port->dev;
-       int err;
+       int err, i;
+
+       /* Here we need to allocate the correct number of frontends,
+        * as reflected in the cards struct. The reality is that currrently
+        * no cx23885 boards support this - yet. But, if we don't modify this
+        * code then the second frontend would never be allocated (later)
+        * and fail with error before the attach in dvb_register().
+        * Without these changes we risk an OOPS later. The changes here
+        * are for safety, and should provide a good foundation for the
+        * future addition of any multi-frontend cx23885 based boards.
+        */
+       printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
+               port->num_frontends);
+
+       for (i = 1; i <= port->num_frontends; i++) {
+               if (videobuf_dvb_alloc_frontend(
+                       &port->frontends, i) == NULL) {
+                       printk(KERN_ERR "%s() failed to alloc\n", __func__);
+                       return -ENOMEM;
+               }
 
-       dprintk(1, "%s\n", __func__);
-       dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
-               dev->board,
-               dev->name,
-               dev->pci_bus,
-               dev->pci_slot);
+               fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+               if (!fe0)
+                       err = -EINVAL;
 
-       err = -ENODEV;
+               dprintk(1, "%s\n", __func__);
+               dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
+                       dev->board,
+                       dev->name,
+                       dev->pci_bus,
+                       dev->pci_slot);
 
-       /* dvb stuff */
-       printk("%s: cx23885 based dvb card\n", dev->name);
-       videobuf_queue_sg_init(&port->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock,
+               err = -ENODEV;
+
+               /* dvb stuff */
+               /* We have to init the queue for each frontend on a port. */
+               printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
+               videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
+                           &dev->pci->dev, &port->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
                            sizeof(struct cx23885_buffer), port);
+       }
        err = dvb_register(port);
        if (err != 0)
-               printk("%s() dvb_register failed err = %d\n", __func__, err);
+               printk(KERN_ERR "%s() dvb_register failed err = %d\n",
+                       __func__, err);
 
        return err;
 }
 
 int cx23885_dvb_unregister(struct cx23885_tsport *port)
 {
-       /* dvb */
-       if(port->dvb.frontend)
-               videobuf_dvb_unregister(&port->dvb);
+       struct videobuf_dvb_frontend *fe0;
+
+       /* FIXME: in an error condition where the we have
+        * an expected number of frontends (attach problem)
+        * then this might not clean up correctly, if 1
+        * is invalid.
+        * This comment only applies to future boards IF they
+        * implement MFE support.
+        */
+       fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+       if (fe0->dvb.frontend)
+               videobuf_dvb_unregister_bus(&port->frontends);
 
        return 0;
 }
 
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
-*/
index f98e476e96172c9aa8b3865e437b07d98d7fa548..bb7f71a1fcbe7b30a997d50592fb98e138410915 100644 (file)
@@ -131,7 +131,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
                        printk(" >\n");
        }
 
-       for (cnt = 1; cnt < msg->len; cnt++ ) {
+       for (cnt = 1; cnt < msg->len; cnt++) {
                /* following bytes */
                wdata = msg->buf[cnt];
                ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
@@ -151,9 +151,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
                if (retval == 0)
                        goto eio;
                if (i2c_debug) {
-                       printk(" %02x", msg->buf[cnt]);
+                       dprintk(1, " %02x", msg->buf[cnt]);
                        if (!(ctrl & I2C_NOSTOP))
-                               printk(" >\n");
+                               dprintk(1, " >\n");
                }
        }
        return msg->len;
@@ -162,7 +162,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
        retval = -EIO;
  err:
        if (i2c_debug)
-               printk(" ERR: %d\n", retval);
+               printk(KERN_ERR " ERR: %d\n", retval);
        return retval;
 }
 
@@ -194,12 +194,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
 
        if (i2c_debug) {
                if (joined)
-                       printk(" R");
+                       dprintk(1, " R");
                else
-                       printk(" <R %02x", (msg->addr << 1) + 1);
+                       dprintk(1, " <R %02x", (msg->addr << 1) + 1);
        }
 
-       for(cnt = 0; cnt < msg->len; cnt++) {
+       for (cnt = 0; cnt < msg->len; cnt++) {
 
                ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
 
@@ -216,9 +216,9 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
                        goto eio;
                msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
                if (i2c_debug) {
-                       printk(" %02x", msg->buf[cnt]);
+                       dprintk(1, " %02x", msg->buf[cnt]);
                        if (!(ctrl & I2C_NOSTOP))
-                               printk(" >\n");
+                               dprintk(1, " >\n");
                }
        }
        return msg->len;
@@ -227,7 +227,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
        retval = -EIO;
  err:
        if (i2c_debug)
-               printk(" ERR: %d\n", retval);
+               printk(KERN_ERR " ERR: %d\n", retval);
        return retval;
 }
 
@@ -353,17 +353,17 @@ static struct i2c_client cx23885_i2c_client_template = {
 };
 
 static char *i2c_devs[128] = {
-       [0x10 >> 1]   = "tda10048",
-       [0x12 >> 1]   = "dib7000pc",
-       [ 0x1c >> 1 ] = "lgdt3303",
-       [ 0x86 >> 1 ] = "tda9887",
-       [ 0x32 >> 1 ] = "cx24227",
-       [ 0x88 >> 1 ] = "cx25837",
-       [ 0x84 >> 1 ] = "tda8295",
-       [ 0xa0 >> 1 ] = "eeprom",
-       [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
+       [0x10 >> 1] = "tda10048",
+       [0x12 >> 1] = "dib7000pc",
+       [0x1c >> 1] = "lgdt3303",
+       [0x86 >> 1] = "tda9887",
+       [0x32 >> 1] = "cx24227",
+       [0x88 >> 1] = "cx25837",
+       [0x84 >> 1] = "tda8295",
+       [0xa0 >> 1] = "eeprom",
+       [0xc0 >> 1] = "tuner/mt2131/tda8275",
        [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",
-       [0xc8 >> 1]   = "tuner/xc3028L",
+       [0xc8 >> 1] = "tuner/xc3028L",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
@@ -376,7 +376,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
                rc = i2c_master_recv(c, &buf, 0);
                if (rc < 0)
                        continue;
-               printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
+               printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
                       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
        }
 }
@@ -408,11 +408,12 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
        bus->i2c_client.adapter = &bus->i2c_adap;
 
        if (0 == bus->i2c_rc) {
-               printk("%s: i2c bus %d registered\n", dev->name, bus->nr);
+               dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr);
                if (i2c_scan)
                        do_i2c_scan(dev->name, &bus->i2c_client);
        } else
-               printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr);
+               printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
+                       dev->name, bus->nr);
 
        return bus->i2c_rc;
 }
index f75ed1c9b71a28ec3f5791d80139f00c2605e2b0..ab3110d6046ca08ac7fd2488da02fcaa19396bd2 100644 (file)
@@ -285,11 +285,10 @@ static void cx23885_video_wakeup(struct cx23885_dev *dev,
                list_del(&buf->vb.queue);
                wake_up(&buf->vb.done);
        }
-       if (list_empty(&q->active)) {
+       if (list_empty(&q->active))
                del_timer(&q->timeout);
-       } else {
+       else
                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-       }
        if (bc != 1)
                printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
                        __func__, bc);
@@ -379,12 +378,12 @@ static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
 
 static int res_check(struct cx23885_fh *fh, unsigned int bit)
 {
-       return (fh->resources & bit);
+       return fh->resources & bit;
 }
 
 static int res_locked(struct cx23885_dev *dev, unsigned int bit)
 {
-       return (dev->resources & bit);
+       return dev->resources & bit;
 }
 
 static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
@@ -887,14 +886,16 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma)
 /* ------------------------------------------------------------------ */
 /* VIDEO CTRL IOCTLS                                                  */
 
-static int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_get_control(struct cx23885_dev *dev,
+       struct v4l2_control *ctl)
 {
        dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
        cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
        return 0;
 }
 
-static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_set_control(struct cx23885_dev *dev,
+       struct v4l2_control *ctl)
 {
        dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
                " (disabled - no action)\n", __func__);
@@ -1073,29 +1074,29 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        struct v4l2_requestbuffers *p)
 {
        struct cx23885_fh *fh = priv;
-       return (videobuf_reqbufs(get_queue(fh), p));
+       return videobuf_reqbufs(get_queue(fh), p);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
        struct v4l2_buffer *p)
 {
        struct cx23885_fh *fh = priv;
-       return (videobuf_querybuf(get_queue(fh), p));
+       return videobuf_querybuf(get_queue(fh), p);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv,
        struct v4l2_buffer *p)
 {
        struct cx23885_fh *fh = priv;
-       return (videobuf_qbuf(get_queue(fh), p));
+       return videobuf_qbuf(get_queue(fh), p);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv,
        struct v4l2_buffer *p)
 {
        struct cx23885_fh *fh = priv;
-       return (videobuf_dqbuf(get_queue(fh), p,
-                               file->f_flags & O_NONBLOCK));
+       return videobuf_dqbuf(get_queue(fh), p,
+                               file->f_flags & O_NONBLOCK);
 }
 
 static int vidioc_streamon(struct file *file, void *priv,
index ba4e0aaed4633985dabe58919afef9dddfb9b228..1d53f54cd943efc593f2f755328064642cc627aa 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/version.h>
 #include <linux/mutex.h>
 
-#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1)
+#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 1)
 
 #define UNSET (-1U)
 
@@ -225,7 +225,7 @@ struct cx23885_tsport {
        int                        nr;
        int                        sram_chno;
 
-       struct videobuf_dvb        dvb;
+       struct videobuf_dvb_frontends frontends;
 
        /* dma queues */
        struct cx23885_dmaqueue    mpegq;
@@ -262,6 +262,9 @@ struct cx23885_tsport {
        u32                        src_sel_val;
        u32                        vld_misc_val;
        u32                        hw_sop_ctrl_val;
+
+       /* Allow a single tsport to have multiple frontends */
+       u32                        num_frontends;
 };
 
 struct cx23885_dev {
@@ -367,14 +370,14 @@ struct sram_channel {
 /* ----------------------------------------------------------- */
 
 #define cx_read(reg)             readl(dev->lmmio + ((reg)>>2))
-#define cx_write(reg,value)      writel((value), dev->lmmio + ((reg)>>2))
+#define cx_write(reg, value)     writel((value), dev->lmmio + ((reg)>>2))
 
-#define cx_andor(reg,mask,value) \
+#define cx_andor(reg, mask, value) \
   writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
   ((value) & (mask)), dev->lmmio+((reg)>>2))
 
-#define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
-#define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
+#define cx_set(reg, bit)          cx_andor((reg), (bit), (bit))
+#define cx_clear(reg, bit)        cx_andor((reg), (bit), 0)
 
 /* ----------------------------------------------------------- */
 /* cx23885-core.c                                              */
@@ -411,7 +414,8 @@ extern const unsigned int cx23885_bcount;
 extern struct cx23885_subid cx23885_subids[];
 extern const unsigned int cx23885_idcount;
 
-extern int cx23885_tuner_callback(void *priv, int component, int command, int arg);
+extern int cx23885_tuner_callback(void *priv, int component,
+       int command, int arg);
 extern void cx23885_card_list(struct cx23885_dev *dev);
 extern int  cx23885_ir_init(struct cx23885_dev *dev);
 extern void cx23885_gpio_setup(struct cx23885_dev *dev);
@@ -479,11 +483,3 @@ static inline unsigned int norm_swidth(v4l2_std_id norm)
 {
        return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
 }
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index 5da04e811ca20b3941b086e73566c91d081d27e6..fbc224f46e0eb15ea596e7759cc05a39390f71b9 100644 (file)
@@ -1270,27 +1270,40 @@ static const struct cx88_board cx88_boards[] = {
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_HVR3000] = {
-               /* FIXME: Add dvb & radio support */
                .name           = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
                .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
+               .audio_chip     = V4L2_IDENT_WM8775,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x84bf,
+                       /* 1: TV Audio / FM Mono */
+                       .audioroute = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x84bf,
+                       /* 2: Line-In */
+                       .audioroute = 2,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x84bf,
+                       /* 2: Line-In */
+                       .audioroute = 2,
                }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x84bf,
+                       /* 4: FM Stereo (untested) */
+                       .audioroute = 8,
+               },
                .mpeg           = CX88_MPEG_DVB,
+               .num_frontends  = 2,
        },
        [CX88_BOARD_NORWOOD_MICRO] = {
                .name           = "Norwood Micro TV Tuner",
@@ -1356,23 +1369,27 @@ static const struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xef88,
+                       /* 1: TV Audio / FM Mono */
                        .audioroute = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xef88,
+                       /* 2: Line-In */
                        .audioroute = 2,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xef88,
+                       /* 2: Line-In */
                        .audioroute = 2,
                }},
-               /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0xef88,
+                       /* 4: FM Stereo (untested) */
+                       .audioroute = 8,
                },
        },
        [CX88_BOARD_ADSTECH_PTV_390] = {
@@ -1716,6 +1733,7 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
+               .audio_chip     = V4L2_IDENT_WM8775,
                /*
                 * GPIO0 (WINTV2000)
                 *
@@ -1729,7 +1747,7 @@ static const struct cx88_board cx88_boards[] = {
                 * BIT  VALUE   FUNCTION GP{x}_IO
                 * 0    1       I:?
                 * 1    1       I:?
-                * 2    1       O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH
+                * 2    1       O:MPEG PORT 0=DVB-T 1=DVB-S
                 * 3    1       I:?
                 * 4    1       I:?
                 * 5    1       I:?
@@ -1745,22 +1763,41 @@ static const struct cx88_board cx88_boards[] = {
                 * d    0       I
                 * e    1       O
                 * f    1       O
+                *
+                * WM8775 ADC
+                *
+                * 1: TV Audio / FM Mono
+                * 2: Line-In
+                * 3: Line-In Expansion
+                * 4: FM Stereo
                 */
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xc4bf,
+                       /* 1: TV Audio / FM Mono */
+                       .audioroute = 1,
                }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xc4bf,
+                       /* 2: Line-In */
+                       .audioroute = 2,
                }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xc4bf,
+                       /* 2: Line-In */
+                       .audioroute = 2,
                } },
-               /* fixme: Add radio support */
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0xc4bf,
+                       /* 4: FM Stereo */
+                       .audioroute = 8,
+               },
                .mpeg           = CX88_MPEG_DVB,
+               .num_frontends  = 2,
        },
        [CX88_BOARD_HAUPPAUGE_HVR4000LITE] = {
                .name           = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2",
@@ -2662,10 +2699,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
 
        case CX88_BOARD_HAUPPAUGE_HVR3000:
        case CX88_BOARD_HAUPPAUGE_HVR4000:
-       case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
                /* Init GPIO */
                cx_write(MO_GP0_IO, core->board.input[0].gpio0);
                udelay(1000);
+               cx_clear(MO_GP0_IO, 0x00000080);
+               udelay(50);
+               cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
+               udelay(1000);
                break;
        }
 }
@@ -3004,10 +3044,14 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
 
        memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
 
-       info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+       if (!core->board.num_frontends)
+               core->board.num_frontends=1;
+
+       info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n",
                pci->subsystem_vendor, pci->subsystem_device, core->board.name,
                core->boardnr, card[core->nr] == core->boardnr ?
-               "insmod option" : "autodetected");
+               "insmod option" : "autodetected",
+               core->board.num_frontends);
 
        if (tuner[core->nr] != UNSET)
                core->board.tuner_type = tuner[core->nr];
index d656fec5901086469fb750eeced37588b7702ccc..60705b08bfe899e5c39a17ef6dd83b8436f9ff30 100644 (file)
@@ -549,7 +549,8 @@ void cx88_wakeup(struct cx88_core *core,
                mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
        }
        if (bc != 1)
-               printk("%s: %d buffers handled (should be 1)\n",__func__,bc);
+               dprintk(2, "%s: %d buffers handled (should be 1)\n",
+                       __func__, bc);
 }
 
 void cx88_shutdown(struct cx88_core *core)
index 344ed2626e597e3a47c0e0307ee1f5001bae92da..6968ab0181aa6a6ee96672c7e856829c3135b697 100644 (file)
@@ -116,13 +116,23 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
        struct cx8802_dev *dev= fe->dvb->priv;
        struct cx8802_driver *drv = NULL;
        int ret = 0;
+       int fe_id;
+
+       fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
+       if (!fe_id) {
+               printk(KERN_ERR "%s() No frontend found\n", __func__);
+               return -EINVAL;
+       }
 
        drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
        if (drv) {
-               if (acquire)
+               if (acquire){
+                       dev->frontends.active_fe_id = fe_id;
                        ret = drv->request_acquire(drv);
-               else
+               } else {
                        ret = drv->request_release(drv);
+                       dev->frontends.active_fe_id = 0;
+               }
        }
 
        return ret;
@@ -396,7 +406,7 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
                        cx_write(MO_GP0_IO, 0x00006060);
                        break;
                case SEC_VOLTAGE_OFF:
-                       printk("LNB Voltage SEC_VOLTAGE_off\n");
+                       printk("LNB Voltage SEC_VOLTAGE_off\n");
                        break;
        }
 
@@ -483,6 +493,7 @@ static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
 static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
 {
        struct dvb_frontend *fe;
+       struct videobuf_dvb_frontend *fe0 = NULL;
        struct xc2028_ctrl ctl;
        struct xc2028_config cfg = {
                .i2c_adap  = &dev->core->i2c_adap,
@@ -490,7 +501,12 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
                .ctrl      = &ctl,
        };
 
-       if (!dev->dvb.frontend) {
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+       if (!fe0)
+               return -EINVAL;
+
+       if (!fe0->dvb.frontend) {
                printk(KERN_ERR "%s/2: dvb frontend not attached. "
                                "Can't attach xc3028\n",
                       dev->core->name);
@@ -504,10 +520,13 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
         */
        cx88_setup_xc3028(dev->core, &ctl);
 
-       fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+       fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
        if (!fe) {
                printk(KERN_ERR "%s/2: xc3028 attach failed\n",
                       dev->core->name);
+               dvb_frontend_detach(fe0->dvb.frontend);
+               dvb_unregister_frontend(fe0->dvb.frontend);
+               fe0->dvb.frontend = NULL;
                return -EINVAL;
        }
 
@@ -532,8 +551,10 @@ static int cx24116_reset_device(struct dvb_frontend *fe)
        struct cx88_core *core = dev->core;
 
        /* Reset the part */
+       /* Put the cx24116 into reset */
        cx_write(MO_SRST_IO, 0);
        msleep(10);
+       /* Take the cx24116 out of reset */
        cx_write(MO_SRST_IO, 1);
        msleep(10);
 
@@ -554,14 +575,14 @@ static struct cx24116_config tevii_s460_config = {
 
 static struct stv0299_config tevii_tuner_sharp_config = {
        .demod_address = 0x68,
-       .inittab = sharp_z0194a__inittab,
+       .inittab = sharp_z0194a_inittab,
        .mclk = 88000000UL,
        .invert = 1,
        .skip_reinit = 0,
        .lock_output = 1,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
        .min_delay_ms = 100,
-       .set_symbol_rate = sharp_z0194a__set_symbol_rate,
+       .set_symbol_rate = sharp_z0194a_set_symbol_rate,
        .set_ts_params = cx24116_set_ts_param,
 };
 
@@ -574,19 +595,25 @@ static struct stv0288_config tevii_tuner_earda_config = {
 static int dvb_register(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
+       struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+       int mfe_shared = 0; /* bus not shared by default */
 
-       /* init struct videobuf_dvb */
-       dev->dvb.name = core->name;
-       dev->ts_gen_cntrl = 0x0c;
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+       if (!fe0)
+               return -EINVAL;
 
-       /* init frontend */
+       /* multi-frontend gate control is undefined or defaults to fe0 */
+       dev->frontends.gate = 0;
+
+       /* init frontend(s) */
        switch (core->boardnr) {
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
-               dev->dvb.frontend = dvb_attach(cx22702_attach,
+               fe0->dvb.frontend = dvb_attach(cx22702_attach,
                                               &connexant_refboard_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x61, &core->i2c_adap,
                                        DVB_PLL_THOMSON_DTT759X))
                                goto frontend_detach;
@@ -596,11 +623,11 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_CONEXANT_DVB_T1:
        case CX88_BOARD_KWORLD_DVB_T_CX22702:
        case CX88_BOARD_WINFAST_DTV1000:
-               dev->dvb.frontend = dvb_attach(cx22702_attach,
+               fe0->dvb.frontend = dvb_attach(cx22702_attach,
                                               &connexant_refboard_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x60, &core->i2c_adap,
                                        DVB_PLL_THOMSON_DTT7579))
                                goto frontend_detach;
@@ -610,33 +637,67 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR1100LP:
        case CX88_BOARD_HAUPPAUGE_HVR1300:
-       case CX88_BOARD_HAUPPAUGE_HVR3000:
-               dev->dvb.frontend = dvb_attach(cx22702_attach,
+               fe0->dvb.frontend = dvb_attach(cx22702_attach,
                                               &hauppauge_hvr_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &core->i2c_adap, 0x61,
                                   TUNER_PHILIPS_FMD1216ME_MK3))
                                goto frontend_detach;
                }
                break;
+       case CX88_BOARD_HAUPPAUGE_HVR3000:
+               /* DVB-S init */
+               fe0->dvb.frontend = dvb_attach(cx24123_attach,
+                              &hauppauge_novas_config,
+                              &dev->core->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
+                       &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
+                               dprintk( 1, "%s(): HVR3000 - DVB-S LNB Init: failed\n", __func__);
+                       }
+               } else {
+                       dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __func__);
+               }
+               /* DVB-T init */
+               fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+               if (fe1) {
+                       dev->frontends.gate = 2;
+                       mfe_shared = 1;
+                       fe1->dvb.frontend = dvb_attach(cx22702_attach,
+                               &hauppauge_hvr_config,
+                               &dev->core->i2c_adap);
+                       if (fe1->dvb.frontend) {
+                               fe1->dvb.frontend->id = 1;
+                               if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
+                                               &dev->core->i2c_adap, 0x61,
+                                               TUNER_PHILIPS_FMD1216ME_MK3)) {
+                                       dprintk( 1, "%s(): HVR3000 - DVB-T misc Init: failed\n", __func__);
+                               }
+                       } else {
+                               dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __func__);
+                       }
+               } else {
+                       dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __func__);
+               }
+               break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-               dev->dvb.frontend = dvb_attach(mt352_attach,
+               fe0->dvb.frontend = dvb_attach(mt352_attach,
                                               &dvico_fusionhdtv,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x60, NULL, DVB_PLL_THOMSON_DTT7579))
                                goto frontend_detach;
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
-               dev->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_plus_v1_1,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x60, NULL, DVB_PLL_THOMSON_DTT7579))
                                goto frontend_detach;
                }
@@ -644,31 +705,31 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
                /* The tin box says DEE1601, but it seems to be DTT7579
                 * compatible, with a slightly different MT352 AGC gain. */
-               dev->dvb.frontend = dvb_attach(mt352_attach,
+               fe0->dvb.frontend = dvb_attach(mt352_attach,
                                               &dvico_fusionhdtv_dual,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x61, NULL, DVB_PLL_THOMSON_DTT7579))
                                goto frontend_detach;
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
-               dev->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_plus_v1_1,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x61, NULL, DVB_PLL_THOMSON_DTT7579))
                                goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-               dev->dvb.frontend = dvb_attach(mt352_attach,
+               fe0->dvb.frontend = dvb_attach(mt352_attach,
                                               &dvico_fusionhdtv,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x61, NULL, DVB_PLL_LG_Z201))
                                goto frontend_detach;
                }
@@ -676,11 +737,11 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_KWORLD_DVB_T:
        case CX88_BOARD_DNTV_LIVE_DVB_T:
        case CX88_BOARD_ADSTECH_DVB_T_PCI:
-               dev->dvb.frontend = dvb_attach(mt352_attach,
+               fe0->dvb.frontend = dvb_attach(mt352_attach,
                                               &dntv_live_dvbt_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
                                        0x61, NULL, DVB_PLL_UNKNOWN_1))
                                goto frontend_detach;
                }
@@ -688,10 +749,10 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
 #if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
                /* MT352 is on a secondary I2C bus made from some GPIO lines */
-               dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
+               fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
                                               &dev->vp3054->adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x61,
                                        TUNER_PHILIPS_FMD1216ME_MK3))
                                goto frontend_detach;
@@ -702,22 +763,22 @@ static int dvb_register(struct cx8802_dev *dev)
 #endif
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
-               dev->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_hybrid,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &core->i2c_adap, 0x61,
                                   TUNER_THOMSON_FE6600))
                                goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
-               dev->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_xc3028,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend == NULL)
-                       dev->dvb.frontend = dvb_attach(mt352_attach,
+               if (fe0->dvb.frontend == NULL)
+                       fe0->dvb.frontend = dvb_attach(mt352_attach,
                                                &dvico_fusionhdtv_mt352_xc3028,
                                                &core->i2c_adap);
                /*
@@ -725,16 +786,16 @@ static int dvb_register(struct cx8802_dev *dev)
                 * We must not permit gate_ctrl to be performed, or
                 * the xc3028 cannot communicate on the bus.
                 */
-               if (dev->dvb.frontend)
-                       dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+               if (fe0->dvb.frontend)
+                       fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
                if (attach_xc3028(0x61, dev) < 0)
                        return -EINVAL;
                break;
        case CX88_BOARD_PCHDTV_HD3000:
-               dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
+               fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x61,
                                        TUNER_THOMSON_DTT761X))
                                goto frontend_detach;
@@ -751,11 +812,11 @@ static int dvb_register(struct cx8802_dev *dev)
 
                /* Select RF connector callback */
                fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
-               dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+               fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_3_gold,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x61,
                                        TUNER_MICROTUNE_4042FI5))
                                goto frontend_detach;
@@ -769,11 +830,11 @@ static int dvb_register(struct cx8802_dev *dev)
                mdelay(100);
                cx_set(MO_GP0_IO, 9);
                mdelay(200);
-               dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+               fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_3_gold,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x61,
                                        TUNER_THOMSON_DTT761X))
                                goto frontend_detach;
@@ -787,15 +848,15 @@ static int dvb_register(struct cx8802_dev *dev)
                mdelay(100);
                cx_set(MO_GP0_IO, 1);
                mdelay(200);
-               dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+               fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_5_gold,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x61,
                                        TUNER_LG_TDVS_H06XF))
                                goto frontend_detach;
-                       if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+                       if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
                                   &core->i2c_adap, 0x43))
                                goto frontend_detach;
                }
@@ -808,25 +869,25 @@ static int dvb_register(struct cx8802_dev *dev)
                mdelay(100);
                cx_set(MO_GP0_IO, 1);
                mdelay(200);
-               dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+               fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &pchdtv_hd5500,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x61,
                                        TUNER_LG_TDVS_H06XF))
                                goto frontend_detach;
-                       if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+                       if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
                                   &core->i2c_adap, 0x43))
                                goto frontend_detach;
                }
                break;
        case CX88_BOARD_ATI_HDTVWONDER:
-               dev->dvb.frontend = dvb_attach(nxt200x_attach,
+               fe0->dvb.frontend = dvb_attach(nxt200x_attach,
                                               &ati_hdtvwonder,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x61,
                                        TUNER_PHILIPS_TUV1236D))
                                goto frontend_detach;
@@ -834,49 +895,49 @@ static int dvb_register(struct cx8802_dev *dev)
                break;
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
-               dev->dvb.frontend = dvb_attach(cx24123_attach,
+               fe0->dvb.frontend = dvb_attach(cx24123_attach,
                                               &hauppauge_novas_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend) {
-                       if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend) {
+                       if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
                                        &core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
                                goto frontend_detach;
                }
                break;
        case CX88_BOARD_KWORLD_DVBS_100:
-               dev->dvb.frontend = dvb_attach(cx24123_attach,
+               fe0->dvb.frontend = dvb_attach(cx24123_attach,
                                               &kworld_dvbs_100_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend) {
-                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
-                       dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+               if (fe0->dvb.frontend) {
+                       core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
                }
                break;
        case CX88_BOARD_GENIATECH_DVBS:
-               dev->dvb.frontend = dvb_attach(cx24123_attach,
+               fe0->dvb.frontend = dvb_attach(cx24123_attach,
                                               &geniatech_dvbs_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend) {
-                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
-                       dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+               if (fe0->dvb.frontend) {
+                       core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
                }
                break;
        case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-               dev->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                               &pinnacle_pctv_hd_800i_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
                                        &core->i2c_adap,
                                        &pinnacle_pctv_hd_800i_tuner_config))
                                goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
-               dev->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &dvico_hdtv5_pci_nano_config,
                                                &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
+               if (fe0->dvb.frontend != NULL) {
                        struct dvb_frontend *fe;
                        struct xc2028_config cfg = {
                                .i2c_adap  = &core->i2c_adap,
@@ -889,17 +950,17 @@ static int dvb_register(struct cx8802_dev *dev)
                        };
 
                        fe = dvb_attach(xc2028_attach,
-                                       dev->dvb.frontend, &cfg);
+                                       fe0->dvb.frontend, &cfg);
                        if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
                }
                break;
         case CX88_BOARD_PINNACLE_HYBRID_PCTV:
-               dev->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &cx88_pinnacle_hybrid_pctv,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+               if (fe0->dvb.frontend) {
+                       fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
                        if (attach_xc3028(0x61, dev) < 0)
                                goto frontend_detach;
                }
@@ -907,85 +968,118 @@ static int dvb_register(struct cx8802_dev *dev)
         case CX88_BOARD_GENIATECH_X8000_MT:
                dev->ts_gen_cntrl = 0x00;
 
-               dev->dvb.frontend = dvb_attach(zl10353_attach,
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &cx88_geniatech_x8000_mt,
                                               &core->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0)
                        goto frontend_detach;
                break;
         case CX88_BOARD_KWORLD_ATSC_120:
-               dev->dvb.frontend = dvb_attach(s5h1409_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1409_attach,
                                               &kworld_atsc_120_config,
                                               &core->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0)
                        goto frontend_detach;
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
-               dev->dvb.frontend = dvb_attach(s5h1411_attach,
+               fe0->dvb.frontend = dvb_attach(s5h1411_attach,
                                               &dvico_fusionhdtv7_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
                                        &core->i2c_adap,
                                        &dvico_fusionhdtv7_tuner_config))
                                goto frontend_detach;
                }
                break;
        case CX88_BOARD_HAUPPAUGE_HVR4000:
+               /* DVB-S/S2 Init */
+               fe0->dvb.frontend = dvb_attach(cx24116_attach,
+                       &hauppauge_hvr4000_config,
+                       &dev->core->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       if(!dvb_attach(isl6421_attach, fe0->dvb.frontend,
+                               &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
+                               dprintk( 1, "%s(): HVR4000 - DVB-S LNB Init: failed\n", __func__);
+                       }
+               } else {
+                       dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __func__);
+               }
+               /* DVB-T Init */
+               fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+               if (fe1) {
+                       dev->frontends.gate = 2;
+                       mfe_shared = 1;
+                       fe1->dvb.frontend = dvb_attach(cx22702_attach,
+                               &hauppauge_hvr_config,
+                               &dev->core->i2c_adap);
+                       if (fe1->dvb.frontend) {
+                               fe1->dvb.frontend->id = 1;
+                               if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
+                                       &dev->core->i2c_adap, 0x61,
+                                       TUNER_PHILIPS_FMD1216ME_MK3)) {
+                                       dprintk( 1, "%s(): HVR4000 - DVB-T misc Init: failed\n", __func__);
+                               }
+                       } else {
+                               dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __func__);
+                       }
+               } else {
+                       dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __func__);
+               }
+               break;
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
-               /* Support for DVB-S only, not DVB-T support */
-               dev->dvb.frontend = dvb_attach(cx24116_attach,
+               fe0->dvb.frontend = dvb_attach(cx24116_attach,
                        &hauppauge_hvr4000_config,
                        &dev->core->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dvb_attach(isl6421_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend) {
+                       dvb_attach(isl6421_attach, fe0->dvb.frontend,
                                &dev->core->i2c_adap,
                                0x08, ISL6421_DCL, 0x00);
                }
                break;
        case CX88_BOARD_TEVII_S420:
-               dev->dvb.frontend = dvb_attach(stv0299_attach,
+               fe0->dvb.frontend = dvb_attach(stv0299_attach,
                                                &tevii_tuner_sharp_config,
                                                &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
                                        &core->i2c_adap, DVB_PLL_OPERA1))
                                goto frontend_detach;
-                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
-                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+                       core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
 
                } else {
-                       dev->dvb.frontend = dvb_attach(stv0288_attach,
+                       fe0->dvb.frontend = dvb_attach(stv0288_attach,
                                                            &tevii_tuner_earda_config,
                                                            &core->i2c_adap);
-                               if (dev->dvb.frontend != NULL) {
-                                       if (!dvb_attach(stb6000_attach, dev->dvb.frontend, 0x61,
+                               if (fe0->dvb.frontend != NULL) {
+                                       if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
                                                &core->i2c_adap))
                                        goto frontend_detach;
-                               core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
-                               dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+                               core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+                               fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
 
                        }
                }
                break;
        case CX88_BOARD_TEVII_S460:
-               dev->dvb.frontend = dvb_attach(cx24116_attach,
+               fe0->dvb.frontend = dvb_attach(cx24116_attach,
                                               &tevii_s460_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
-                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+               if (fe0->dvb.frontend != NULL) {
+                       core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
                }
                break;
        case CX88_BOARD_OMICOM_SS4_PCI:
        case CX88_BOARD_TBS_8920:
        case CX88_BOARD_PROF_7300:
-               dev->dvb.frontend = dvb_attach(cx24116_attach,
+               fe0->dvb.frontend = dvb_attach(cx24116_attach,
                                               &hauppauge_hvr4000_config,
                                               &core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
-                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+               if (fe0->dvb.frontend != NULL) {
+                       core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
                }
                break;
        default:
@@ -993,29 +1087,32 @@ static int dvb_register(struct cx8802_dev *dev)
                       core->name);
                break;
        }
-       if (NULL == dev->dvb.frontend) {
+
+        if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
                printk(KERN_ERR
                       "%s/2: frontend initialization failed\n",
                       core->name);
                return -EINVAL;
        }
        /* define general-purpose callback pointer */
-       dev->dvb.frontend->callback = cx88_tuner_callback;
+       fe0->dvb.frontend->callback = cx88_tuner_callback;
 
        /* Ensure all frontends negotiate bus access */
-       dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+       fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+       if (fe1)
+               fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
        /* Put the analog decoder in standby to keep it quiet */
        cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
 
        /* register everything */
-       return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
-                                    &dev->pci->dev, adapter_nr);
+       return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+               &dev->pci->dev, adapter_nr, mfe_shared);
 
 frontend_detach:
-       if (dev->dvb.frontend) {
-               dvb_frontend_detach(dev->dvb.frontend);
-               dev->dvb.frontend = NULL;
+       if (fe0->dvb.frontend) {
+               dvb_frontend_detach(fe0->dvb.frontend);
+               fe0->dvb.frontend = NULL;
        }
        return -EINVAL;
 }
@@ -1039,6 +1136,38 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
                cx_clear(MO_GP0_IO, 0x00000004);
                udelay(1000);
                break;
+
+       case CX88_BOARD_HAUPPAUGE_HVR3000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+               if(core->dvbdev->frontends.active_fe_id == 1) {
+                       /* DVB-S/S2 Enabled */
+
+                       /* Toggle reset on cx22702 leaving i2c active */
+                       cx_write(MO_GP0_IO, (core->board.input[0].gpio0 & 0x0000ff00) | 0x00000080);
+                       udelay(1000);
+                       cx_clear(MO_GP0_IO, 0x00000080);
+                       udelay(50);
+                       cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */
+                       cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */
+                       udelay(1000);
+
+                       cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */
+                       core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
+               } else
+               if (core->dvbdev->frontends.active_fe_id == 2) {
+                       /* DVB-T Enabled */
+
+                       /* Put the cx24116/cx24123 into reset */
+                       cx_write(MO_SRST_IO, 0);
+
+                       /* cx22702 out of reset and enable it */
+                       cx_set(MO_GP0_IO,   0x00000080);
+                       cx_clear(MO_GP0_IO, 0x00000004);
+                       core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
+                       udelay(1000);
+               }
+               break;
+
        default:
                err = -ENODEV;
        }
@@ -1056,6 +1185,9 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
        case CX88_BOARD_HAUPPAUGE_HVR1300:
                /* Do Nothing, leave the cx22702 on the bus. */
                break;
+       case CX88_BOARD_HAUPPAUGE_HVR3000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+               break;
        default:
                err = -ENODEV;
        }
@@ -1066,7 +1198,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
 {
        struct cx88_core *core = drv->core;
        struct cx8802_dev *dev = drv->core->dvbdev;
-       int err;
+       int err, i;
+       struct videobuf_dvb_frontend *fe;
 
        dprintk( 1, "%s\n", __func__);
        dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
@@ -1086,18 +1219,28 @@ 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_sg_init(&dev->dvb.dvbq, &dvb_qops,
+       dev->ts_gen_cntrl = 0x0c;
+
+       for (i = 1; i <= core->board.num_frontends; i++) {
+               fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
+               if (!fe) {
+                       printk(KERN_ERR "%s() failed to get frontend(%d)\n", __func__, i);
+                       continue;
+               }
+               videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
                            &dev->pci->dev, &dev->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_TOP,
                            sizeof(struct cx88_buffer),
                            dev);
+               /* init struct videobuf_dvb */
+               fe->dvb.name = dev->core->name;
+       }
        err = dvb_register(dev);
        if (err != 0)
                printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
                       core->name, err);
-
- fail_core:
+fail_core:
        return err;
 }
 
@@ -1105,9 +1248,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
 {
        struct cx8802_dev *dev = drv->core->dvbdev;
 
-       /* dvb */
-       if (dev->dvb.frontend)
-               videobuf_dvb_unregister(&dev->dvb);
+       videobuf_dvb_unregister_bus(&dev->frontends);
 
        vp3054_i2c_remove(dev);
 
index 8e74d64fdcd2e5324e38af6db7002341154e3d8d..01de23007095f5d7d1de4b8371df34f26b9d0795 100644 (file)
@@ -116,18 +116,25 @@ static int detach_inform(struct i2c_client *client)
 
 void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
 {
+       struct videobuf_dvb_frontends *f = &core->dvbdev->frontends;
+       struct videobuf_dvb_frontend *fe = NULL;
        if (0 != core->i2c_rc)
                return;
 
 #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
-       if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
-               if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
-                       core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+       if (core->dvbdev && f) {
+               if(f->gate <= 1) /* undefined or fe0 */
+                       fe = videobuf_dvb_get_frontend(f, 1);
+               else
+                       fe = videobuf_dvb_get_frontend(f, f->gate);
+
+               if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
+                       fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 1);
 
                i2c_clients_command(&core->i2c_adap, cmd, arg);
 
-               if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
-                       core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+               if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
+                       fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 0);
        } else
 #endif
                i2c_clients_command(&core->i2c_adap, cmd, arg);
index a6b061c2644a7d72446a0a79713180c64e3d6c8d..6df5cf31418627025e16752fdecbab998040a7ed 100644 (file)
@@ -768,7 +768,8 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
 {
        struct cx8802_dev *dev;
        struct cx88_core  *core;
-       int err;
+       struct videobuf_dvb_frontend *demod;
+       int err,i;
 
        /* general setup */
        core = cx88_core_get(pci_dev);
@@ -781,6 +782,11 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
        if (!core->board.mpeg)
                goto fail_core;
 
+       if (!core->board.num_frontends) {
+               printk(KERN_ERR "%s() .num_frontends should be non-zero, err = %d\n", __func__, err);
+               goto fail_core;
+       }
+
        err = -ENOMEM;
        dev = kzalloc(sizeof(*dev),GFP_KERNEL);
        if (NULL == dev)
@@ -795,6 +801,20 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
        INIT_LIST_HEAD(&dev->drvlist);
        list_add_tail(&dev->devlist,&cx8802_devlist);
 
+       mutex_init(&dev->frontends.lock);
+       INIT_LIST_HEAD(&dev->frontends.felist);
+
+       printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, core->board.num_frontends);
+
+       for (i = 1; i <= core->board.num_frontends; i++) {
+               demod = videobuf_dvb_alloc_frontend(&dev->frontends, i);
+               if(demod == NULL) {
+                       printk(KERN_ERR "%s() failed to alloc\n", __func__);
+                       err = -ENOMEM;
+                       goto fail_free;
+               }
+       }
+
        /* Maintain a reference so cx88-video can query the 8802 device. */
        core->dvbdev = dev;
 
index 3a1977f41e277ddd681694398ae8de01335cdf5a..7dd506b987fe76d06be6788104f67ce88cd72bc2 100644 (file)
@@ -767,6 +767,14 @@ void cx88_set_tvaudio(struct cx88_core *core)
        case WW_FM:
                set_audio_standard_FM(core, radio_deemphasis);
                break;
+       case WW_I2SADC:
+               set_audio_start(core, 0x01);
+               /* Slave/Philips/Autobaud */
+               cx_write(AUD_I2SINPUTCNTL, 0);
+               /* Switch to "I2S ADC mode" */
+               cx_write(AUD_I2SCNTL, 0x1);
+               set_audio_finish(core, EN_I2SIN_ENABLE);
+               break;
        case WW_NONE:
        default:
                printk("%s/0: unknown tv audio mode [%d]\n",
@@ -895,6 +903,9 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                        break;
                }
                break;
+       case WW_I2SADC:
+               /* DO NOTHING */
+               break;
        }
 
        if (UNSET != ctl) {
index be45955dff686ebb38d598c8fb7e86d62ef6ca2f..3904b73f52ee2879ebc6058770d8692a80a57700 100644 (file)
@@ -426,24 +426,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
 
        /* if there are audioroutes defined, we have an external
           ADC to deal with audio */
-
        if (INPUT(input).audioroute) {
-
-               /* cx2388's C-ADC is connected to the tuner only.
-                  When used with S-Video, that ADC is busy dealing with
-                  chroma, so an external must be used for baseband audio */
-
-               if (INPUT(input).type != CX88_VMUX_TELEVISION &&
-                       INPUT(input).type != CX88_RADIO) {
-                       /* "ADC mode" */
-                       cx_write(AUD_I2SCNTL, 0x1);
-                       cx_set(AUD_CTL, EN_I2SIN_ENABLE);
-               } else {
-                       /* Normal mode */
-                       cx_write(AUD_I2SCNTL, 0x0);
-                       cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
-               }
-
                /* The wm8775 module has the "2" route hardwired into
                   the initialization. Some boards may use different
                   routes for different inputs. HVR-1300 surely does */
@@ -454,9 +437,19 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
                        route.input = INPUT(input).audioroute;
                        cx88_call_i2c_clients(core,
                                VIDIOC_INT_S_AUDIO_ROUTING, &route);
-
                }
-
+               /* cx2388's C-ADC is connected to the tuner only.
+                  When used with S-Video, that ADC is busy dealing with
+                  chroma, so an external must be used for baseband audio */
+               if (INPUT(input).type != CX88_VMUX_TELEVISION ) {
+                       /* "I2S ADC mode" */
+                       core->tvaudio = WW_I2SADC;
+                       cx88_set_tvaudio(core);
+               } else {
+                       /* Normal mode */
+                       cx_write(AUD_I2SCNTL, 0x0);
+                       cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+               }
        }
 
        return 0;
@@ -832,9 +825,24 @@ static int video_open(struct inode *inode, struct file *file)
                cx_write(MO_GP0_IO, core->board.radio.gpio0);
                cx_write(MO_GP1_IO, core->board.radio.gpio1);
                cx_write(MO_GP2_IO, core->board.radio.gpio2);
-               core->tvaudio = WW_FM;
-               cx88_set_tvaudio(core);
-               cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
+               if (core->board.radio.audioroute) {
+                       if(core->board.audio_chip &&
+                               core->board.audio_chip == V4L2_IDENT_WM8775) {
+                               struct v4l2_routing route;
+
+                               route.input = core->board.radio.audioroute;
+                               cx88_call_i2c_clients(core,
+                                       VIDIOC_INT_S_AUDIO_ROUTING, &route);
+                       }
+                       /* "I2S ADC mode" */
+                       core->tvaudio = WW_I2SADC;
+                       cx88_set_tvaudio(core);
+               } else {
+                       /* FM Mode */
+                       core->tvaudio = WW_FM;
+                       cx88_set_tvaudio(core);
+                       cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
+               }
                cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
        }
        unlock_kernel();
index dbf01b8b57a52876b0cfe7ae67f4e3665f6c0a1d..76207c2856b7d45b70f0c1048749e47bbe134430 100644 (file)
@@ -247,7 +247,7 @@ struct cx88_input {
        enum cx88_itype type;
        u32             gpio0, gpio1, gpio2, gpio3;
        unsigned int    vmux:2;
-       unsigned int    audioroute:2;
+       unsigned int    audioroute:4;
 };
 
 struct cx88_board {
@@ -261,6 +261,7 @@ struct cx88_board {
        struct cx88_input       radio;
        enum cx88_board_type    mpeg;
        unsigned int            audio_chip;
+       int                     num_frontends;
 };
 
 struct cx88_subid {
@@ -356,6 +357,7 @@ struct cx88_core {
        struct cx8802_dev          *dvbdev;
        enum cx88_board_type       active_type_id;
        int                        active_ref;
+       int                        active_fe_id;
 };
 
 struct cx8800_dev;
@@ -490,7 +492,7 @@ struct cx8802_dev {
 
 #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
        /* for dvb only */
-       struct videobuf_dvb        dvb;
+       struct videobuf_dvb_frontends frontends;
 #endif
 
 #if defined(CONFIG_VIDEO_CX88_VP3054) || \
@@ -628,6 +630,7 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
 #define WW_EIAJ                 7
 #define WW_I2SPT        8
 #define WW_FM           9
+#define WW_I2SADC       10
 
 void cx88_set_tvaudio(struct cx88_core *core);
 void cx88_newstation(struct cx88_core *core);
index c21af312ee7c496782a792fd1f29a33946a6277c..e48fbfc8ad05d72c4065fdf0ae42aa41b298f88d 100644 (file)
@@ -21,6 +21,7 @@
 #define MODULE_NAME "gspca"
 
 #include <linux/init.h>
+#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
@@ -403,7 +404,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
        unsigned int i;
 
        PDEBUG(D_STREAM, "kill transfer");
-       for (i = 0; i < MAX_NURBS; ++i) {
+       for (i = 0; i < MAX_NURBS; i++) {
                urb = gspca_dev->urb[i];
                if (urb == NULL)
                        break;
index 4779dd0b06da0145eeee191f4e0e2d3fe198446a..1d9dc90b479137d87c878fc84a3ee9e022a61e45 100644 (file)
@@ -2,7 +2,6 @@
 #define GSPCAV2_H
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/usb.h>
 #include <linux/videodev2.h>
index c786d7d3d44aaf11e4aae6a3bf537886b57ac87d..1a37ae4bc82dad9dbe4589cfb7aeb3966e347dc6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * USB Driver for ALi m5602 based webcams
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
 
 /*****************************************************************************/
 
-#undef PDEBUG
-#undef info
-#undef err
-
-#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
-       format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
-       format "\n" , ## arg)
-
-/* Debug parameters */
-#define DBG_INIT 0x1
-#define DBG_PROBE 0x2
-#define DBG_V4L2 0x4
-#define DBG_TRACE 0x8
-#define DBG_DATA 0x10
-#define DBG_V4L2_CID 0x20
-#define DBG_GSPCA 0x40
-
-#define PDEBUG(level, fmt, args...) \
-       do { \
-               if (m5602_debug & level)     \
-                       info("[%s:%d] " fmt, __func__, __LINE__ , \
-                       ## args); \
-       } while (0)
-
-/*****************************************************************************/
-
 #define M5602_XB_SENSOR_TYPE 0x00
 #define M5602_XB_SENSOR_CTRL 0x01
 #define M5602_XB_LINE_OF_FRAME_H 0x02
index 19d5e351ccc18d24a36be72bac3a88374b596eb1..fd6ce384b487a224b586415502086c38a44f3c0e 100644 (file)
@@ -1,7 +1,7 @@
-/*
+ /*
  * USB Driver for ALi m5602 based webcams
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -26,7 +26,6 @@
 int force_sensor;
 int dump_bridge;
 int dump_sensor;
-unsigned int m5602_debug;
 
 static const __devinitdata struct usb_device_id m5602_table[] = {
        {USB_DEVICE(0x0402, 0x5602)},
@@ -48,7 +47,7 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
                              1, M5602_URB_MSG_TIMEOUT);
        *i2c_data = buf[0];
 
-       PDEBUG(DBG_TRACE, "Reading bridge register 0x%x containing 0x%x",
+       PDEBUG(D_CONF, "Reading bridge register 0x%x containing 0x%x",
               address, *i2c_data);
 
        /* usb_control_msg(...) returns the number of bytes sent upon success,
@@ -63,7 +62,7 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
        struct usb_device *udev = sd->gspca_dev.dev;
        __u8 *buf = sd->gspca_dev.usb_buf;
 
-       PDEBUG(DBG_TRACE, "Writing bridge register 0x%x with 0x%x",
+       PDEBUG(D_CONF, "Writing bridge register 0x%x with 0x%x",
               address, i2c_data);
 
        memcpy(buf, bridge_urb_skeleton,
@@ -91,7 +90,8 @@ static void m5602_dump_bridge(struct sd *sd)
                m5602_read_bridge(sd, i, &val);
                info("ALi m5602 address 0x%x contains 0x%x", i, val);
        }
-       info("Warning: The camera probably won't work until it's power cycled");
+       info("Warning: The ALi m5602 webcam probably won't work "
+               "until it's power cycled");
 }
 
 static int m5602_probe_sensor(struct sd *sd)
@@ -135,7 +135,7 @@ static int m5602_init(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int err;
 
-       PDEBUG(DBG_TRACE, "Initializing ALi m5602 webcam");
+       PDEBUG(D_CONF, "Initializing ALi m5602 webcam");
        /* Run the init sequence */
        err = sd->sensor->init(sd);
 
@@ -146,16 +146,18 @@ static int m5602_start_transfer(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 *buf = sd->gspca_dev.usb_buf;
+       int err;
 
        /* Send start command to the camera */
        const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
        memcpy(buf, buffer, sizeof(buffer));
-       usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
-                       0x04, 0x40, 0x19, 0x0000, buf,
-                       4, M5602_URB_MSG_TIMEOUT);
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             0x04, 0x40, 0x19, 0x0000, buf,
+                             4, M5602_URB_MSG_TIMEOUT);
 
-       PDEBUG(DBG_V4L2, "Transfer started");
-       return 0;
+       PDEBUG(D_STREAM, "Transfer started");
+       return (err < 0) ? err : 0;
 }
 
 static void m5602_urb_complete(struct gspca_dev *gspca_dev,
@@ -165,14 +167,14 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
 
        if (len < 6) {
-               PDEBUG(DBG_DATA, "Packet is less than 6 bytes");
+               PDEBUG(D_PACK, "Packet is less than 6 bytes");
                return;
        }
 
        /* Frame delimiter: ff xx xx xx ff ff */
        if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
            data[2] != sd->frame_id) {
-               PDEBUG(DBG_DATA, "Frame delimiter detected");
+               PDEBUG(D_FRAM, "Frame delimiter detected");
                sd->frame_id = data[2];
 
                /* Remove the extra fluff appended on each header */
@@ -187,7 +189,7 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
                /* Create a new frame */
                gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
 
-               PDEBUG(DBG_V4L2, "Starting new frame %d",
+               PDEBUG(D_FRAM, "Starting new frame %d",
                       sd->frame_count);
 
        } else {
@@ -198,7 +200,7 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
                len -= 4;
 
                if (cur_frame_len + len <= frame->v4l2_buf.length) {
-                       PDEBUG(DBG_DATA, "Continuing frame %d copying %d bytes",
+                       PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
                               sd->frame_count, len);
 
                        gspca_frame_add(gspca_dev, INTER_PACKET, frame,
@@ -234,8 +236,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
        struct cam *cam;
        int err;
 
-       PDEBUG(DBG_GSPCA, "m5602_configure start");
-
        cam = &gspca_dev->cam;
        cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
        sd->desc = &sd_desc;
@@ -248,11 +248,10 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
        if (err)
                goto fail;
 
-       PDEBUG(DBG_GSPCA, "m5602_configure end");
        return 0;
 
 fail:
-       PDEBUG(DBG_GSPCA, "m5602_configure failed");
+       PDEBUG(D_ERR, "ALi m5602 webcam failed");
        cam->cam_mode = NULL;
        cam->nmodes = 0;
 
@@ -282,13 +281,13 @@ static int __init mod_m5602_init(void)
 {
        if (usb_register(&sd_driver) < 0)
                return -1;
-       PDEBUG(D_PROBE, "m5602 module registered");
+       PDEBUG(D_PROBE, "registered");
        return 0;
 }
 static void __exit mod_m5602_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "m5602 module deregistered");
+       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(mod_m5602_init);
@@ -297,9 +296,6 @@ module_exit(mod_m5602_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-module_param_named(debug, m5602_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "toggles debug on/off");
-
 module_param(force_sensor, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(force_sensor,
                "force detection of sensor, "
index 566d4925a0e8a4af6a41494719539bde976ce56e..fb700c2d055acf4775cd00c5ccb889a08170f7e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the mt9m111 sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -107,7 +107,7 @@ int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                  data, 2);
        *val = data[0] & MT9M111_RMB_MIRROR_ROWS;
-       PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -118,7 +118,7 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
 
        /* Set the correct page map */
        err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -145,7 +145,7 @@ int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                  data, 2);
        *val = data[0] & MT9M111_RMB_MIRROR_COLS;
-       PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -156,7 +156,7 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 
        /* Set the correct page map */
        err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -188,7 +188,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
              ((tmp & (1 <<  8)) * 2) |
               (tmp & 0x7f);
 
-       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+       PDEBUG(D_V4L2, "Read gain %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -222,7 +222,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 
        data[1] = (tmp & 0xff00) >> 8;
        data[0] = (tmp & 0xff);
-       PDEBUG(DBG_V4L2_CID, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
+       PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
               data[1], data[0]);
 
        err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
@@ -257,7 +257,7 @@ int mt9m111_read_sensor(struct sd *sd, const u8 address,
        for (i = 0; i < len && !err; i++) {
                err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
 
-               PDEBUG(DBG_TRACE, "Reading sensor register "
+               PDEBUG(D_CONF, "Reading sensor register "
                       "0x%x contains 0x%x ", address, *i2c_data);
        }
 out:
@@ -290,7 +290,7 @@ int mt9m111_write_sensor(struct sd *sd, const u8 address,
                memcpy(p, sensor_urb_skeleton + 16, 4);
                p[3] = i2c_data[i];
                p += 4;
-               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
                       address, i2c_data[i]);
        }
 
index 79a5d88781902b2b5fd1952b7de609cad5c02c4f..315209d5aeefdc679f482e34ebbeb05a807e3dac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the mt9m111 sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -82,7 +82,6 @@
 /* Kernel module parameters */
 extern int force_sensor;
 extern int dump_sensor;
-extern unsigned int m5602_debug;
 
 int mt9m111_probe(struct sd *sd);
 int mt9m111_init(struct sd *sd);
@@ -152,8 +151,8 @@ static struct m5602_sensor mt9m111 = {
                        .default_value  = DEFAULT_GAIN,
                        .flags          = V4L2_CTRL_FLAG_SLIDER
                },
-               .set = mt9m111_set_hflip,
-               .get = mt9m111_get_hflip
+               .set = mt9m111_set_gain,
+               .get = mt9m111_get_gain
        }
        },
 
index 31c5896250e7cd16aafe004e2fa19e04652c340d..837c7e47661c044aa13aad1426901e25f6fd2e36 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the ov9650 sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -40,7 +40,7 @@ int ov9650_read_sensor(struct sd *sd, const u8 address,
        for (i = 0; i < len; i++) {
                err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
 
-               PDEBUG(DBG_TRACE, "Reading sensor register "
+               PDEBUG(D_CONF, "Reading sensor register "
                                "0x%x containing 0x%x ", address, *i2c_data);
        }
        return (err < 0) ? err : 0;
@@ -72,7 +72,7 @@ int ov9650_write_sensor(struct sd *sd, const u8 address,
                memcpy(p, sensor_urb_skeleton + 16, 4);
                p[3] = i2c_data[i];
                p += 4;
-               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
                       address, i2c_data[i]);
        }
 
@@ -199,7 +199,7 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
                goto out;
        *val |= (i2c_data & 0x3f) << 10;
 
-       PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+       PDEBUG(D_V4L2, "Read exposure %d", *val);
 out:
        return (err < 0) ? err : 0;
 }
@@ -210,7 +210,7 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        int err;
 
-       PDEBUG(DBG_V4L2_CID, "Set exposure to %d",
+       PDEBUG(D_V4L2, "Set exposure to %d",
               val & 0xffff);
 
        /* The 6 MSBs */
@@ -246,7 +246,7 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 
        err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
        *val |= i2c_data;
-       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+       PDEBUG(D_V4L2, "Read gain %d", *val);
        return (err < 0) ? err : 0;
 }
 
@@ -280,7 +280,7 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
        err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1);
        *val = i2c_data;
 
-       PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+       PDEBUG(D_V4L2, "Read red gain %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -291,7 +291,7 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set red gain to %d",
+       PDEBUG(D_V4L2, "Set red gain to %d",
                             val & 0xff);
 
        i2c_data = val & 0xff;
@@ -309,7 +309,7 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
        err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
        *val = i2c_data;
 
-       PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+       PDEBUG(D_V4L2, "Read blue gain %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -320,7 +320,7 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set blue gain to %d",
+       PDEBUG(D_V4L2, "Set blue gain to %d",
               val & 0xff);
 
        i2c_data = val & 0xff;
@@ -340,7 +340,7 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
                *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
        else
                *val = (i2c_data & OV9650_HFLIP) >> 5;
-       PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -351,7 +351,7 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
        err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (err < 0)
                goto out;
@@ -379,7 +379,7 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
                *val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
        else
                *val = (i2c_data & 0x10) >> 4;
-       PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -390,7 +390,7 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
        err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (err < 0)
                goto out;
@@ -420,7 +420,7 @@ int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
 
        err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
        *val |= i2c_data;
-       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+       PDEBUG(D_V4L2, "Read gain %d", *val);
 out:
        return (err < 0) ? err : 0;
 }
@@ -431,7 +431,7 @@ int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set gain to %d", val & 0x3ff);
+       PDEBUG(D_V4L2, "Set gain to %d", val & 0x3ff);
 
        /* Read the OV9650_VREF register first to avoid
                corrupting the VREF high and low bits */
@@ -461,7 +461,7 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
 
        err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        *val = (i2c_data & OV9650_AWB_EN) >> 1;
-       PDEBUG(DBG_V4L2_CID, "Read auto white balance %d", *val);
+       PDEBUG(D_V4L2, "Read auto white balance %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -472,7 +472,7 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set auto white balance to %d", val);
+       PDEBUG(D_V4L2, "Set auto white balance to %d", val);
        err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                goto out;
@@ -491,7 +491,7 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
 
        err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        *val = (i2c_data & OV9650_AGC_EN) >> 2;
-       PDEBUG(DBG_V4L2_CID, "Read auto gain control %d", *val);
+       PDEBUG(D_V4L2, "Read auto gain control %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -502,7 +502,7 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       PDEBUG(DBG_V4L2_CID, "Set auto gain control to %d", val);
+       PDEBUG(D_V4L2, "Set auto gain control to %d", val);
        err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                goto out;
index 2f29cb056f30094f5fc84cd5b8971e4d0da20bc0..065632f0378ebd04bdd2a01d0470293d4d186cfc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the ov9650 sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
 /* Kernel module parameters */
 extern int force_sensor;
 extern int dump_sensor;
-extern unsigned int m5602_debug;
 
 int ov9650_probe(struct sd *sd);
 int ov9650_init(struct sd *sd);
index 08c015bde115b5e1a6f51d4fa5cec1546416e0e9..d17ac52566e68c00eb5a791bc3e29afa271510f6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the po1030 sensor
  *
- * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2008 Erik Andrén
  * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -82,7 +82,7 @@ int po1030_read_sensor(struct sd *sd, const u8 address,
        for (i = 0; i < len; i++) {
                err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
 
-               PDEBUG(DBG_TRACE, "Reading sensor register "
+               PDEBUG(D_CONF, "Reading sensor register "
                                "0x%x containing 0x%x ", address, *i2c_data);
        }
        return (err < 0) ? err : 0;
@@ -112,7 +112,7 @@ int po1030_write_sensor(struct sd *sd, const u8 address,
                memcpy(p, sensor_urb_skeleton + 16, 4);
                p[3] = i2c_data[i];
                p += 4;
-               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
                       address, i2c_data[i]);
        }
 
@@ -185,7 +185,7 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
                                 &i2c_data, 1);
        *val |= i2c_data;
 
-       PDEBUG(DBG_V4L2_CID, "Exposure read as %d", *val);
+       PDEBUG(D_V4L2, "Exposure read as %d", *val);
 out:
        return (err < 0) ? err : 0;
 }
@@ -196,10 +196,10 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        int err;
 
-       PDEBUG(DBG_V4L2, "Set exposure to %d", val & 0xffff);
+       PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
 
        i2c_data = ((val & 0xff00) >> 8);
-       PDEBUG(DBG_V4L2, "Set exposure to high byte to 0x%x",
+       PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
               i2c_data);
 
        err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H,
@@ -208,7 +208,7 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
                goto out;
 
        i2c_data = (val & 0xff);
-       PDEBUG(DBG_V4L2, "Set exposure to low byte to 0x%x",
+       PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
               i2c_data);
        err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M,
                                  &i2c_data, 1);
@@ -226,7 +226,71 @@ int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
                                 &i2c_data, 1);
        *val = i2c_data;
-       PDEBUG(DBG_V4L2_CID, "Read global gain %d", *val);
+       PDEBUG(D_V4L2, "Read global gain %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       err = po1030_read_sensor(sd, PO1030_REG_CONTROL2,
+                                &i2c_data, 1);
+
+       *val = (i2c_data >> 7) & 0x01 ;
+
+       PDEBUG(D_V4L2, "Read hflip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       PDEBUG(D_V4L2, "Set hflip %d", val);
+
+       i2c_data = (val & 0x01) << 7;
+
+       err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
+                                 &i2c_data, 1);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+                                &i2c_data, 1);
+
+       *val = (i2c_data >> 6) & 0x01;
+
+       PDEBUG(D_V4L2, "Read vflip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       PDEBUG(D_V4L2, "Set vflip %d", val);
+
+       i2c_data = (val & 0x01) << 6;
+
+       err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
+                                 &i2c_data, 1);
 
        return (err < 0) ? err : 0;
 }
@@ -238,7 +302,7 @@ int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        int err;
 
        i2c_data = val & 0xff;
-       PDEBUG(DBG_V4L2, "Set global gain to %d", i2c_data);
+       PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
        err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN,
                                  &i2c_data, 1);
        return (err < 0) ? err : 0;
@@ -253,7 +317,7 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
        err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN,
                                 &i2c_data, 1);
        *val = i2c_data;
-       PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+       PDEBUG(D_V4L2, "Read red gain %d", *val);
        return (err < 0) ? err : 0;
 }
 
@@ -264,7 +328,7 @@ int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
        int err;
 
        i2c_data = val & 0xff;
-       PDEBUG(DBG_V4L2, "Set red gain to %d", i2c_data);
+       PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
        err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN,
                                  &i2c_data, 1);
        return (err < 0) ? err : 0;
@@ -279,7 +343,7 @@ int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
        err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN,
                                 &i2c_data, 1);
        *val = i2c_data;
-       PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+       PDEBUG(D_V4L2, "Read blue gain %d", *val);
 
        return (err < 0) ? err : 0;
 }
@@ -290,7 +354,7 @@ int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
        u8 i2c_data;
        int err;
        i2c_data = val & 0xff;
-       PDEBUG(DBG_V4L2, "Set blue gain to %d", i2c_data);
+       PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
        err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN,
                                  &i2c_data, 1);
 
index 68f34c97bf44bdaf50f6d56bf9dcd88c9b0f21a6..a0b75ff61d797c966a1ee266f31c4e9896f8b046 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * Driver for the po1030 sensor.
- * This is probably a pixel plus sensor but we haven't identified it yet
  *
- * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2008 Erik Andrén
  * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
 #define PO1030_REG_YCONTRAST           0x74
 #define PO1030_REG_YSATURATION         0x75
 
+#define PO1030_HFLIP                   (1 << 7)
+#define PO1030_VFLIP                   (1 << 6)
+
 /*****************************************************************************/
 
 #define PO1030_GLOBAL_GAIN_DEFAULT     0x12
-#define PO1030_EXPOSURE_DEFAULT                0xf0ff
+#define PO1030_EXPOSURE_DEFAULT                0x0085
 #define PO1030_BLUE_GAIN_DEFAULT       0x40
 #define PO1030_RED_GAIN_DEFAULT        0x40
 
 /* Kernel module parameters */
 extern int force_sensor;
 extern int dump_sensor;
-extern unsigned int m5602_debug;
 
 int po1030_probe(struct sd *sd);
 int po1030_init(struct sd *sd);
@@ -142,6 +143,10 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
 int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
 int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
 int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
 
 static struct m5602_sensor po1030 = {
        .name = "PO1030",
@@ -152,7 +157,7 @@ static struct m5602_sensor po1030 = {
        .init = po1030_init,
        .power_down = po1030_power_down,
 
-       .nctrls = 4,
+       .nctrls = 6,
        .ctrls = {
        {
                {
@@ -160,7 +165,7 @@ static struct m5602_sensor po1030 = {
                        .type           = V4L2_CTRL_TYPE_INTEGER,
                        .name           = "gain",
                        .minimum        = 0x00,
-                       .maximum        = 0xff,
+                       .maximum        = 0x4f,
                        .step           = 0x1,
                        .default_value  = PO1030_GLOBAL_GAIN_DEFAULT,
                        .flags          = V4L2_CTRL_FLAG_SLIDER
@@ -173,7 +178,7 @@ static struct m5602_sensor po1030 = {
                        .type           = V4L2_CTRL_TYPE_INTEGER,
                        .name           = "exposure",
                        .minimum        = 0x00,
-                       .maximum        = 0xffff,
+                       .maximum        = 0x02ff,
                        .step           = 0x1,
                        .default_value  = PO1030_EXPOSURE_DEFAULT,
                        .flags          = V4L2_CTRL_FLAG_SLIDER
@@ -206,8 +211,33 @@ static struct m5602_sensor po1030 = {
                },
                .set = po1030_set_blue_balance,
                .get = po1030_get_blue_balance
+       }, {
+               {
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = po1030_set_hflip,
+               .get = po1030_get_hflip
+       }, {
+               {
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = po1030_set_vflip,
+               .get = po1030_get_vflip
        }
        },
+
        .nmodes = 1,
        .modes = {
        {
@@ -381,7 +411,7 @@ static const unsigned char init_po1030[][4] =
 
        /* Set the y window to 1 */
        {SENSOR, PO1030_REG_WINDOWY_H, 0x00},
-       {SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+       {SENSOR, PO1030_REG_WINDOWY_L, 0x01},
 
        {SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
        {SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
index 68202565325d675e4c2d0edc1662b59e4113ee7b..14b1eac5b812517723e79a9fa910cf061ee6c099 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the s5k4aa sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -117,7 +117,7 @@ int s5k4aa_read_sensor(struct sd *sd, const u8 address,
        for (i = 0; (i < len) & !err; i++) {
                err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
 
-               PDEBUG(DBG_TRACE, "Reading sensor register "
+               PDEBUG(D_CONF, "Reading sensor register "
                                  "0x%x containing 0x%x ", address, *i2c_data);
        }
 out:
@@ -150,7 +150,7 @@ int s5k4aa_write_sensor(struct sd *sd, const u8 address,
                memcpy(p, sensor_urb_skeleton + 16, 4);
                p[3] = i2c_data[i];
                p += 4;
-               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
                       address, i2c_data[i]);
        }
 
@@ -248,7 +248,7 @@ int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
        *val = data << 8;
        err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
        *val |= data;
-       PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+       PDEBUG(D_V4L2, "Read exposure %d", *val);
 out:
        return (err < 0) ? err : 0;
 }
@@ -259,7 +259,7 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(DBG_V4L2_CID, "Set exposure to %d", val);
+       PDEBUG(D_V4L2, "Set exposure to %d", val);
        err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
@@ -285,7 +285,7 @@ int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 
        err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        *val = (data & S5K4AA_RM_V_FLIP) >> 7;
-       PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
 out:
        return (err < 0) ? err : 0;
@@ -297,7 +297,7 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
        err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
@@ -341,7 +341,7 @@ int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 
        err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        *val = (data & S5K4AA_RM_H_FLIP) >> 6;
-       PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 out:
        return (err < 0) ? err : 0;
 }
@@ -352,7 +352,7 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d",
+       PDEBUG(D_V4L2, "Set horizontal flip to %d",
               val);
        err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -397,7 +397,7 @@ int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 
        err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
        *val = data;
-       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+       PDEBUG(D_V4L2, "Read gain %d", *val);
 
 out:
        return (err < 0) ? err : 0;
@@ -409,7 +409,7 @@ int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(DBG_V4L2_CID, "Set gain to %d", val);
+       PDEBUG(D_V4L2, "Set gain to %d", val);
        err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
index bb7f7e3e90af6fe460e7abc2a583dc0d9689a2c7..eaef67655afa9cd282d010b7645ac0ee2e0dd307 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the s5k4aa sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -63,7 +63,6 @@
 /* Kernel module parameters */
 extern int force_sensor;
 extern int dump_sensor;
-extern unsigned int m5602_debug;
 
 int s5k4aa_probe(struct sd *sd);
 int s5k4aa_init(struct sd *sd);
index b4b33c2d0499d61cff0c0cee8fbc1903e5a50442..8988a728e0b400dbeb395b2ac78a53d6869b1f4f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the s5k83a sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -101,7 +101,7 @@ int s5k83a_read_sensor(struct sd *sd, const u8 address,
        for (i = 0; i < len && !len; i++) {
                err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
 
-               PDEBUG(DBG_TRACE, "Reading sensor register "
+               PDEBUG(D_CONF, "Reading sensor register "
                                  "0x%x containing 0x%x ", address, *i2c_data);
        }
 
@@ -135,7 +135,7 @@ int s5k83a_write_sensor(struct sd *sd, const u8 address,
                memcpy(p, sensor_urb_skeleton + 16, 4);
                p[3] = i2c_data[i];
                p += 4;
-               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
                       address, i2c_data[i]);
        }
 
index 833708eb5a428ed957b9f307941e50bf10a98056..ee3ee9cfca1d96083283ba16a5723f2ce7c46349 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the s5k83a sensor
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
@@ -41,8 +41,6 @@
 /* Kernel module parameters */
 extern int force_sensor;
 extern int dump_sensor;
-extern unsigned int m5602_debug;
-
 
 int s5k83a_probe(struct sd *sd);
 int s5k83a_init(struct sd *sd);
index 930fcaab4416fc8afef5c9671501fd41e784d9fc..60c9a48e0c0291cb478c3d51d60e6608438fb6a1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * USB Driver for ALi m5602 based webcams
  *
- * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2008 Erik Andrén
  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  *
index b561f7c4f066632571d8b12265b1ed776dc49231..eac245d7a7561af56241fb806472eb00d877a9ad 100644 (file)
@@ -50,7 +50,7 @@ struct sd {
 
        __u8 sensor;
 #define SENSOR_TAS5130A 0
-#define SENSOR_OTHER 1
+#define SENSOR_OM6802 1
 };
 
 /* V4L2 controls supported by the driver */
@@ -188,7 +188,7 @@ static struct ctrl sd_ctrls[] = {
          .minimum = 0,
          .maximum = 1,
          .step = 1,
-         .default_value = 1,
+         .default_value = 0,
          },
         .set = sd_setwhitebalance,
         .get = sd_getwhitebalance
@@ -261,6 +261,59 @@ static struct v4l2_pix_format vga_mode_t16[] = {
                .priv = 0},
 };
 
+/* sensor specific data */
+struct additional_sensor_data {
+       const __u8 data1[20];
+       const __u8 data2[18];
+       const __u8 data3[18];
+       const __u8 data4[4];
+       const __u8 data5[6];
+       const __u8 stream[4];
+};
+
+const static struct additional_sensor_data sensor_data[] = {
+    {                          /* TAS5130A */
+       .data1 =
+               {0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10,
+                0xd4, 0xbb, 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+                0xd8, 0xc8, 0xd9, 0xfc},
+       .data2 =
+               {0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60,
+                0xe4, 0xa8, 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+                0xe8, 0xe0},
+       .data3 =
+               {0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60,
+                0xcb, 0xa8, 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+                0xcf, 0xe0},
+       .data4 =        /* Freq (50/60Hz). Splitted for test purpose */
+               {0x66, 0x00, 0xa8, 0xe8},
+       .data5 =
+               {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
+       .stream =
+               {0x0b, 0x04, 0x0a, 0x40},
+    },
+    {                          /* OM6802 */
+       .data1 =
+               {0xd0, 0xc2, 0xd1, 0x28, 0xd2, 0x0f, 0xd3, 0x22,
+                0xd4, 0xcd, 0xd5, 0x27, 0xd6, 0x2c, 0xd7, 0x06,
+                0xd8, 0xb3, 0xd9, 0xfc},
+       .data2 =
+               {0xe0, 0x80, 0xe1, 0xff, 0xe2, 0xff, 0xe3, 0x80,
+                0xe4, 0xff, 0xe5, 0xff, 0xe6, 0x80, 0xe7, 0xff,
+                0xe8, 0xff},
+       .data3 =
+               {0xc7, 0x80, 0xc8, 0xff, 0xc9, 0xff, 0xca, 0x80,
+                0xcb, 0xff, 0xcc, 0xff, 0xcd, 0x80, 0xce, 0xff,
+                0xcf, 0xff},
+       .data4 =        /*Freq (50/60Hz). Splitted for test purpose */
+               {0x66, 0xca, 0xa8, 0xf0 },
+       .data5 =        /* this could be removed later */
+               {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
+       .stream =
+               {0x0b, 0x04, 0x0a, 0x78},
+    }
+};
+
 #define MAX_EFFECTS 7
 /* easily done by soft, this table could be removed,
  * i keep it here just in case */
@@ -365,6 +418,8 @@ static const __u8 tas5130a_sensor_init[][8] = {
        {},
 };
 
+static __u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
+
 /* read 1 byte */
 static int reg_r(struct gspca_dev *gspca_dev,
                   __u16 index)
@@ -385,12 +440,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0,
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index,
                        NULL, 0, 500);
 }
 
-static void i2c_w(struct gspca_dev *gspca_dev,
+static void reg_w_buf(struct gspca_dev *gspca_dev,
                  const __u8 *buffer, __u16 len)
 {
        if (len <= USB_BUF_SZ) {
@@ -398,7 +453,7 @@ static void i2c_w(struct gspca_dev *gspca_dev,
                usb_control_msg(gspca_dev->dev,
                                usb_sndctrlpipe(gspca_dev->dev, 0),
                                0,
-                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                0x01, 0,
                                gspca_dev->usb_buf, len, 500);
        } else {
@@ -409,14 +464,15 @@ static void i2c_w(struct gspca_dev *gspca_dev,
                usb_control_msg(gspca_dev->dev,
                                usb_sndctrlpipe(gspca_dev->dev, 0),
                                0,
-                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                0x01, 0,
                                tmpbuf, len, 500);
                kfree(tmpbuf);
        }
 }
 
-static void other_sensor_init(struct gspca_dev *gspca_dev)
+/* Reported as OM6802*/
+static void om6802_sensor_init(struct gspca_dev *gspca_dev)
 {
        int i;
        const __u8 *p;
@@ -436,19 +492,32 @@ static void other_sensor_init(struct gspca_dev *gspca_dev)
                0x90, 0x24,
                0x91, 0xb2,
                0x82, 0x32,
-               0xfd, 0x00,
-               0xfd, 0x01,
                0xfd, 0x41,
                0x00                    /* table end */
        };
 
+       reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
+       msleep(5);
+       i = 4;
+       while (--i < 0) {
+               byte = reg_r(gspca_dev, 0x0060);
+               if (!(byte & 0x01))
+                       break;
+               msleep(100);
+       }
+       byte = reg_r(gspca_dev, 0x0063);
+       if (byte != 0x17) {
+               err("Bad sensor reset %02x", byte);
+               /* continue? */
+       }
+
        p = sensor_init;
        while (*p != 0) {
                val[1] = *p++;
                val[3] = *p++;
                if (*p == 0)
                        reg_w(gspca_dev, 0x3c80);
-               i2c_w(gspca_dev, val, sizeof val);
+               reg_w_buf(gspca_dev, val, sizeof val);
                i = 4;
                while (--i >= 0) {
                        msleep(15);
@@ -457,7 +526,8 @@ static void other_sensor_init(struct gspca_dev *gspca_dev)
                                break;
                }
        }
-                       reg_w(gspca_dev, 0x3c80);
+       msleep(15);
+       reg_w(gspca_dev, 0x3c80);
 }
 
 /* this function is called at probe time */
@@ -485,12 +555,75 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       unsigned int brightness;
+       __u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
+
+       brightness = sd->brightness;
+       if (brightness < 7) {
+               set6[1] = 0x26;
+               set6[3] = 0x70 - brightness * 0x10;
+       } else {
+               set6[3] = 0x00 + ((brightness - 7) * 0x10);
+       }
+
+       reg_w_buf(gspca_dev, set6, sizeof set6);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       unsigned int contrast = sd->contrast;
+       __u16 reg_to_write;
+
+       if (contrast < 7)
+               reg_to_write = 0x8ea9 - contrast * 0x200;
+       else
+               reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
+
+       reg_w(gspca_dev, reg_to_write);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u16 reg_to_write;
+
+       reg_to_write = 0x80bb + sd->colors * 0x100;     /* was 0xc0 */
+       reg_w(gspca_dev, reg_to_write);
+}
+
 static void setgamma(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
-       i2c_w(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+       reg_w_buf(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       __u8 white_balance[8] =
+               {0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38};
+
+       if (sd->whitebalance)
+               white_balance[7] = 0x3c;
+
+       reg_w_buf(gspca_dev, white_balance, sizeof white_balance);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u16 reg_to_write;
+
+       reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+       reg_w(gspca_dev, reg_to_write);
 }
 
 /* this function is called at probe and resume time */
@@ -511,8 +644,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
        static const __u8 n2[] =
                        {0x08, 0x00};
-       static const __u8 nset[] =
-                       { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
        static const __u8 n3[] =
                        {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
        static const __u8 n4[] =
@@ -525,51 +656,29 @@ static int sd_init(struct gspca_dev *gspca_dev)
                 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
                 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
                 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
-       static const __u8 nset4[] = {
-               0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
-               0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
-               0xe8, 0xe0
-       };
-       /* ojo puede ser 0xe6 en vez de 0xe9 */
-       static const __u8 nset2[] = {
-               0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
-               0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
-               0xd8, 0xc8, 0xd9, 0xfc
-       };
-       static const __u8 missing[] =
-               { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
-       static const __u8 nset3[] = {
-               0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
-               0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
-               0xcf, 0xe0
-       };
-       static const __u8 nset5[] =
-                       { 0x8f, 0x24, 0xc3, 0x00 };     /* bright */
-       static const __u8 nset7[4] =
-                       { 0x66, 0xca, 0xa8, 0xf8 };     /* 50/60 Hz */
        static const __u8 nset9[4] =
                        { 0x0b, 0x04, 0x0a, 0x78 };
        static const __u8 nset8[6] =
                        { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
-       static const __u8 nset10[6] =
-                       { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
 
        byte = reg_r(gspca_dev, 0x06);
        test_byte = reg_r(gspca_dev, 0x07);
        if (byte == 0x08 && test_byte == 0x07) {
-               PDEBUG(D_CONF, "other sensor");
-               sd->sensor = SENSOR_OTHER;
+               PDEBUG(D_CONF, "sensor om6802");
+               sd->sensor = SENSOR_OM6802;
+       } else if (byte == 0x08 && test_byte == 0x01) {
+               PDEBUG(D_CONF, "sensor tas5130a");
+               sd->sensor = SENSOR_TAS5130A;
        } else {
-               PDEBUG(D_CONF, "sensor %02x %02x", byte, test_byte);
+               PDEBUG(D_CONF, "unknown sensor %02x %02x", byte, test_byte);
                sd->sensor = SENSOR_TAS5130A;
        }
 
-       i2c_w(gspca_dev, n1, sizeof n1);
+       reg_w_buf(gspca_dev, n1, sizeof n1);
        test_byte = 0;
        i = 5;
        while (--i >= 0) {
-               i2c_w(gspca_dev, nset, sizeof nset);
-               msleep(5);
+               reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
                test_byte = reg_r(gspca_dev, 0x0063);
                msleep(100);
                if (test_byte == 0x17)
@@ -580,7 +689,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 /*             return -EIO; */
 /*fixme: test - continue */
        }
-       i2c_w(gspca_dev, n2, sizeof n2);
+       reg_w_buf(gspca_dev, n2, sizeof n2);
 
        i = 0;
        while (read_indexs[i] != 0x00) {
@@ -590,56 +699,50 @@ static int sd_init(struct gspca_dev *gspca_dev)
                i++;
        }
 
-       i2c_w(gspca_dev, n3, sizeof n3);
-       i2c_w(gspca_dev, n4, sizeof n4);
+       reg_w_buf(gspca_dev, n3, sizeof n3);
+       reg_w_buf(gspca_dev, n4, sizeof n4);
        reg_r(gspca_dev, 0x0080);
        reg_w(gspca_dev, 0x2c80);
-       i2c_w(gspca_dev, nset2, sizeof nset2);
-       i2c_w(gspca_dev, nset3, sizeof nset3);
-       i2c_w(gspca_dev, nset4, sizeof nset4);
+
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
+                       sizeof sensor_data[sd->sensor].data1);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
+                       sizeof sensor_data[sd->sensor].data3);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
+                       sizeof sensor_data[sd->sensor].data2);
+
        reg_w(gspca_dev, 0x3880);
        reg_w(gspca_dev, 0x3880);
        reg_w(gspca_dev, 0x338e);
-       i2c_w(gspca_dev, nset5, sizeof nset5);
-       reg_w(gspca_dev, 0x00a9);
-       setgamma(gspca_dev);
-       reg_w(gspca_dev, 0x86bb);
-       reg_w(gspca_dev, 0x4aa6);
 
-       i2c_w(gspca_dev, missing, sizeof missing);
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
+       setgamma(gspca_dev);
+       setcolors(gspca_dev);
+       setsharpness(gspca_dev);
+       setwhitebalance(gspca_dev);
 
-       reg_w(gspca_dev, 0x2087);
+       reg_w(gspca_dev, 0x2087);       /* tied to white balance? */
        reg_w(gspca_dev, 0x2088);
        reg_w(gspca_dev, 0x2089);
 
-       i2c_w(gspca_dev, nset7, sizeof nset7);
-       i2c_w(gspca_dev, nset10, sizeof nset10);
-       i2c_w(gspca_dev, nset8, sizeof nset8);
-       i2c_w(gspca_dev, nset9, sizeof nset9);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
+                       sizeof sensor_data[sd->sensor].data4);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
+                       sizeof sensor_data[sd->sensor].data5);
+       reg_w_buf(gspca_dev, nset8, sizeof nset8);
+       reg_w_buf(gspca_dev, nset9, sizeof nset9);
 
        reg_w(gspca_dev, 0x2880);
-       i2c_w(gspca_dev, nset2, sizeof nset2);
-       i2c_w(gspca_dev, nset3, sizeof nset3);
-       i2c_w(gspca_dev, nset4, sizeof nset4);
-
-       return 0;
-}
-
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       unsigned int brightness;
-       __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x00 };
 
-       brightness = sd->brightness;
-       if (brightness < 7) {
-               set6[3] = 0x70 - brightness * 0x10;
-       } else {
-               set6[1] = 0x24;
-               set6[3] = 0x00 + ((brightness - 7) * 0x10);
-       }
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
+                       sizeof sensor_data[sd->sensor].data1);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
+                       sizeof sensor_data[sd->sensor].data3);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
+                       sizeof sensor_data[sd->sensor].data2);
 
-       i2c_w(gspca_dev, set6, sizeof set6);
+       return 0;
 }
 
 static void setflip(struct gspca_dev *gspca_dev)
@@ -651,14 +754,15 @@ static void setflip(struct gspca_dev *gspca_dev)
        if (sd->mirror)
                flipcmd[3] = 0x01;
 
-       i2c_w(gspca_dev, flipcmd, sizeof flipcmd);
+       reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
 }
 
 static void seteffect(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       i2c_w(gspca_dev, effects_table[sd->effect], sizeof effects_table[0]);
+       reg_w_buf(gspca_dev, effects_table[sd->effect],
+                               sizeof effects_table[0]);
        if (sd->effect == 1 || sd->effect == 5) {
                PDEBUG(D_CONF,
                       "This effect have been disabled for webcam \"safety\"");
@@ -671,19 +775,6 @@ static void seteffect(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0xfaa6);
 }
 
-static void setwhitebalance(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       __u8 white_balance[8] =
-           { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
-
-       if (sd->whitebalance == 1)
-               white_balance[7] = 0x3c;
-
-       i2c_w(gspca_dev, white_balance, sizeof white_balance);
-}
-
 static void setlightfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -692,52 +783,46 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
        if (sd->freq == 2)      /* 60hz */
                freq[1] = 0x00;
 
-       i2c_w(gspca_dev, freq, sizeof freq);
+       reg_w_buf(gspca_dev, freq, sizeof freq);
 }
 
-static void setcontrast(struct gspca_dev *gspca_dev)
+/* Is this really needed?
+ * i added some module parameters for test with some users */
+static void poll_sensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       unsigned int contrast = sd->contrast;
-       __u16 reg_to_write;
-
-       if (contrast < 7)
-               reg_to_write = 0x8ea9 - (0x200 * contrast);
-       else
-               reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
-
-       reg_w(gspca_dev, reg_to_write);
-}
-
-static void setcolors(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u16 reg_to_write;
-
-       reg_to_write = 0xc0bb + sd->colors * 0x100;
-       reg_w(gspca_dev, reg_to_write);
-}
-
-static void setsharpness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u16 reg_to_write;
-
-       reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
-
-       reg_w(gspca_dev, reg_to_write);
+       static const __u8 poll1[] =
+               {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
+                0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
+                0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
+                0x60, 0x14};
+       static const __u8 poll2[] =
+               {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
+                0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
+       static const __u8 poll3[] =
+               {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
+       static const __u8 poll4[] =
+               {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
+                0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
+                0xc2, 0x80, 0xc3, 0x10};
+
+       if (sd->sensor != SENSOR_TAS5130A) {
+               PDEBUG(D_STREAM, "[Sensor requires polling]");
+               reg_w_buf(gspca_dev, poll1, sizeof poll1);
+               reg_w_buf(gspca_dev, poll2, sizeof poll2);
+               reg_w_buf(gspca_dev, poll3, sizeof poll3);
+               reg_w_buf(gspca_dev, poll4, sizeof poll4);
+       }
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i, mode;
-       static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
        __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
        static const __u8 t3[] =
                { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
                  0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
-       static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
 
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
        switch (mode) {
@@ -760,25 +845,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
        if (sd->sensor == SENSOR_TAS5130A) {
                i = 0;
                while (tas5130a_sensor_init[i][0] != 0) {
-                       i2c_w(gspca_dev, tas5130a_sensor_init[i],
+                       reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
                                         sizeof tas5130a_sensor_init[0]);
                        i++;
                }
                reg_w(gspca_dev, 0x3c80);
                /* just in case and to keep sync with logs (for mine) */
-               i2c_w(gspca_dev, tas5130a_sensor_init[3],
+               reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
                                 sizeof tas5130a_sensor_init[0]);
                reg_w(gspca_dev, 0x3c80);
        } else {
-               other_sensor_init(gspca_dev);
+               om6802_sensor_init(gspca_dev);
        }
-       /* just in case and to keep sync with logs  (for mine) */
-       i2c_w(gspca_dev, t1, sizeof t1);
-       i2c_w(gspca_dev, t2, sizeof t2);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
+                       sizeof sensor_data[sd->sensor].data4);
        reg_r(gspca_dev, 0x0012);
-       i2c_w(gspca_dev, t3, sizeof t3);
+       reg_w_buf(gspca_dev, t2, sizeof t2);
+       reg_w_buf(gspca_dev, t3, sizeof t3);
        reg_w(gspca_dev, 0x0013);
-       i2c_w(gspca_dev, t4, sizeof t4);
+       msleep(15);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+                       sizeof sensor_data[sd->sensor].stream);
+       poll_sensor(gspca_dev);
+
        /* restart on each start, just in case, sometimes regs goes wrong
         * when using controls from app */
        setbrightness(gspca_dev);
@@ -787,6 +876,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+                       sizeof sensor_data[sd->sensor].stream);
+       msleep(20);
+       reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+                       sizeof sensor_data[sd->sensor].stream);
+       msleep(20);
+       reg_w(gspca_dev, 0x0309);
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -1036,6 +1138,7 @@ static const struct sd_desc sd_desc = {
        .config = sd_config,
        .init = sd_init,
        .start = sd_start,
+       .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
 };
index b7457fc60ba5964c5131cc5282c1b2f29f831411..1c404e454a36f6c601550fd261e2cc65e42805ec 100644 (file)
@@ -600,13 +600,14 @@ retry:
        since we may get here before the stream has been fully set-up */
        if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
                while (count >= itv->dma_data_req_size) {
-                       if (!ivtv_yuv_udma_stream_frame (itv, (void __user *)user_buf)) {
-                               bytes_written += itv->dma_data_req_size;
-                               user_buf += itv->dma_data_req_size;
-                               count -= itv->dma_data_req_size;
-                       } else {
-                               break;
-                       }
+                       rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf);
+
+                       if (rc < 0)
+                               return rc;
+
+                       bytes_written += itv->dma_data_req_size;
+                       user_buf += itv->dma_data_req_size;
+                       count -= itv->dma_data_req_size;
                }
                if (count == 0) {
                        IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
index 8696527ab134bfb6daaee2e49eb7911a5c0cbf44..208fb54842f2f4a91f8527f280e5023cd8780215 100644 (file)
@@ -509,7 +509,6 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_
 static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
 {
        struct ivtv_open_id *id = fh;
-       struct ivtv *itv = id->itv;
        s32 w = fmt->fmt.pix.width;
        s32 h = fmt->fmt.pix.height;
        int field = fmt->fmt.pix.field;
@@ -517,7 +516,22 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format
 
        w = min(w, 720);
        w = max(w, 2);
-       h = min(h, itv->is_out_50hz ? 576 : 480);
+       /* Why can the height be 576 even when the output is NTSC?
+
+          Internally the buffers of the PVR350 are always set to 720x576. The
+          decoded video frame will always be placed in the top left corner of
+          this buffer. For any video which is not 720x576, the buffer will
+          then be cropped to remove the unused right and lower areas, with
+          the remaining image being scaled by the hardware to fit the display
+          area. The video can be scaled both up and down, so a 720x480 video
+          can be displayed full-screen on PAL and a 720x576 video can be
+          displayed without cropping on NTSC.
+
+          Note that the scaling only occurs on the video stream, the osd
+          resolution is locked to the broadcast standard and not scaled.
+
+          Thanks to Ian Armstrong for this explanation. */
+       h = min(h, 576);
        h = max(h, 2);
        if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
                fmt->fmt.pix.field = field;
index 2fd4b4a44aa92c44d5262302eda6e3e3e96d646c..bae2d2beb7093344f84b89ee7e0629701c14ca6c 100644 (file)
  * V1.1 Gerard v.d. Horst  Added some debugoutput, reset the video-standard
  */
 
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include "ks0127.h"
-
 #include <linux/i2c.h>
 #include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include "ks0127.h"
 
-#define dprintk     if (debug) printk
-
-/* i2c identification */
-#define I2C_KS0127_ADDON   0xD8
-#define I2C_KS0127_ONBOARD 0xDA
+MODULE_DESCRIPTION("KS0127 video decoder driver");
+MODULE_AUTHOR("Ryan Drake");
+MODULE_LICENSE("GPL");
 
 #define KS_TYPE_UNKNOWN        0
 #define KS_TYPE_0122S  1
@@ -204,8 +197,6 @@ struct adjust {
 };
 
 struct ks0127 {
-       struct i2c_client *client;
-       unsigned char   addr;
        int             format_width;
        int             format_height;
        int             cap_width;
@@ -220,16 +211,18 @@ static int debug; /* insmod parameter */
 
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug output");
-MODULE_LICENSE("GPL");
 
 static u8 reg_defaults[64];
 
-
-
 static void init_reg_defaults(void)
 {
+       static int initialized;
        u8 *table = reg_defaults;
 
+       if (initialized)
+               return;
+       initialized = 1;
+
        table[KS_CMDA]     = 0x2c;  /* VSE=0, CCIR 601, autodetect standard */
        table[KS_CMDB]     = 0x12;  /* VALIGN=0, AGC control and input */
        table[KS_CMDC]     = 0x00;  /* Test options */
@@ -308,50 +301,53 @@ static void init_reg_defaults(void)
  * An explanation from kayork@mail.utexas.edu:
  *
  * During I2C reads, the KS0127 only samples for a stop condition
- * during the place where the acknoledge bit should be. Any standard
+ * during the place where the acknowledge bit should be. Any standard
  * I2C implementation (correctly) throws in another clock transition
  * at the 9th bit, and the KS0127 will not recognize the stop condition
  * and will continue to clock out data.
  *
  * So we have to do the read ourself.  Big deal.
         workaround in i2c-algo-bit
*        workaround in i2c-algo-bit
  */
 
 
-static u8 ks0127_read(struct ks0127 *ks, u8 reg)
+static u8 ks0127_read(struct i2c_client *c, u8 reg)
 {
-       struct i2c_client *c = ks->client;
        char val = 0;
        struct i2c_msg msgs[] = {
-               {c->addr, 0, sizeof(reg), &reg},
-               {c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
+               { c->addr, 0, sizeof(reg), &reg },
+               { c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
+       };
        int ret;
 
        ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
        if (ret != ARRAY_SIZE(msgs))
-               dprintk("ks0127_write error\n");
+               v4l_dbg(1, debug, c, "read error\n");
 
        return val;
 }
 
 
-static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
+static void ks0127_write(struct i2c_client *c, u8 reg, u8 val)
 {
-       char msg[] = {reg, val};
+       struct ks0127 *ks = i2c_get_clientdata(c);
+       char msg[] = { reg, val };
 
-       if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
-               dprintk("ks0127_write error\n");
+       if (i2c_master_send(c, msg, sizeof(msg)) != sizeof(msg))
+               v4l_dbg(1, debug, c, "write error\n");
 
        ks->regs[reg] = val;
 }
 
 
 /* generic bit-twiddling */
-static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
+static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v)
 {
+       struct ks0127 *ks = i2c_get_clientdata(client);
+
        u8 val = ks->regs[reg];
        val = (val & and_v) | or_v;
-       ks0127_write(ks, reg, val);
+       ks0127_write(client, reg, val);
 }
 
 
@@ -359,73 +355,69 @@ static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
 /****************************************************************************
 * ks0127 private api
 ****************************************************************************/
-static void ks0127_reset(struct ks0127* ks)
+static void ks0127_reset(struct i2c_client *c)
 {
-       int i;
+       struct ks0127 *ks = i2c_get_clientdata(c);
        u8 *table = reg_defaults;
+       int i;
 
        ks->ks_type = KS_TYPE_UNKNOWN;
 
-       dprintk("ks0127: reset\n");
+       v4l_dbg(1, debug, c, "reset\n");
        msleep(1);
 
        /* initialize all registers to known values */
        /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
 
-       for(i = 1; i < 33; i++)
-               ks0127_write(ks, i, table[i]);
+       for (i = 1; i < 33; i++)
+               ks0127_write(c, i, table[i]);
 
-       for(i = 35; i < 40; i++)
-               ks0127_write(ks, i, table[i]);
+       for (i = 35; i < 40; i++)
+               ks0127_write(c, i, table[i]);
 
-       for(i = 41; i < 56; i++)
-               ks0127_write(ks, i, table[i]);
+       for (i = 41; i < 56; i++)
+               ks0127_write(c, i, table[i]);
 
-       for(i = 58; i < 64; i++)
-               ks0127_write(ks, i, table[i]);
+       for (i = 58; i < 64; i++)
+               ks0127_write(c, i, table[i]);
 
 
-       if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
+       if ((ks0127_read(c, KS_STAT) & 0x80) == 0) {
                ks->ks_type = KS_TYPE_0122S;
-               dprintk("ks0127: ks0122s Found\n");
+               v4l_dbg(1, debug, c, "ks0122s found\n");
                return;
        }
 
-       switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
-
+       switch (ks0127_read(c, KS_CMDE) & 0x0f) {
        case 0:
                ks->ks_type = KS_TYPE_0127;
-               dprintk("ks0127: ks0127 found\n");
+               v4l_dbg(1, debug, c, "ks0127 found\n");
                break;
 
        case 9:
                ks->ks_type = KS_TYPE_0127B;
-               dprintk("ks0127: ks0127B Revision A found\n");
+               v4l_dbg(1, debug, c, "ks0127B Revision A found\n");
                break;
 
        default:
-               dprintk("ks0127: unknown revision\n");
+               v4l_dbg(1, debug, c, "unknown revision\n");
                break;
        }
 }
 
-static int ks0127_command(struct i2c_client *client,
-                         unsigned int cmd, void *arg)
+static int ks0127_command(struct i2c_client *c, unsigned cmd, void *arg)
 {
-       struct ks0127 *ks = i2c_get_clientdata(client);
-
-       int             *iarg = (int*)arg;
-
+       struct ks0127 *ks = i2c_get_clientdata(c);
+       int             *iarg = (int *)arg;
        int             status;
 
        if (!ks)
                return -ENODEV;
 
        switch (cmd) {
-
        case DECODER_INIT:
-               dprintk("ks0127: command DECODER_INIT\n");
-               ks0127_reset(ks);
+               v4l_dbg(1, debug, c, "DECODER_INIT\n");
+               ks0127_reset(c);
                break;
 
        case DECODER_SET_INPUT:
@@ -436,161 +428,160 @@ static int ks0127_command(struct i2c_client *client,
                case KS_INPUT_COMPOSITE_4:
                case KS_INPUT_COMPOSITE_5:
                case KS_INPUT_COMPOSITE_6:
-                       dprintk("ks0127: command DECODER_SET_INPUT %d: "
-                               "Composite\n", *iarg);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_INPUT %d: Composite\n", *iarg);
                        /* autodetect 50/60 Hz */
-                       ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+                       ks0127_and_or(c, KS_CMDA,   0xfc, 0x00);
                        /* VSE=0 */
-                       ks0127_and_or(ks, KS_CMDA,   ~0x40, 0x00);
+                       ks0127_and_or(c, KS_CMDA,   ~0x40, 0x00);
                        /* set input line */
-                       ks0127_and_or(ks, KS_CMDB,   0xb0, *iarg);
+                       ks0127_and_or(c, KS_CMDB,   0xb0, *iarg);
                        /* non-freerunning mode */
-                       ks0127_and_or(ks, KS_CMDC,   0x70, 0x0a);
+                       ks0127_and_or(c, KS_CMDC,   0x70, 0x0a);
                        /* analog input */
-                       ks0127_and_or(ks, KS_CMDD,   0x03, 0x00);
+                       ks0127_and_or(c, KS_CMDD,   0x03, 0x00);
                        /* enable chroma demodulation */
-                       ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+                       ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
                        /* chroma trap, HYBWR=1 */
-                       ks0127_and_or(ks, KS_LUMA,   0x00,
+                       ks0127_and_or(c, KS_LUMA,   0x00,
                                       (reg_defaults[KS_LUMA])|0x0c);
                        /* scaler fullbw, luma comb off */
-                       ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+                       ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
                        /* manual chroma comb .25 .5 .25 */
-                       ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
+                       ks0127_and_or(c, KS_VERTIC, 0x0f, 0x90);
 
                        /* chroma path delay */
-                       ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
+                       ks0127_and_or(c, KS_CHROMB, 0x0f, 0x90);
 
-                       ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
-                       ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
-                       ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
-                       ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+                       ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
+                       ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
+                       ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+                       ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
                        break;
 
                case KS_INPUT_SVIDEO_1:
                case KS_INPUT_SVIDEO_2:
                case KS_INPUT_SVIDEO_3:
-                       dprintk("ks0127: command DECODER_SET_INPUT %d: "
-                               "S-Video\n", *iarg);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_INPUT %d: S-Video\n", *iarg);
                        /* autodetect 50/60 Hz */
-                       ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+                       ks0127_and_or(c, KS_CMDA,   0xfc, 0x00);
                        /* VSE=0 */
-                       ks0127_and_or(ks, KS_CMDA,   ~0x40, 0x00);
+                       ks0127_and_or(c, KS_CMDA,   ~0x40, 0x00);
                        /* set input line */
-                       ks0127_and_or(ks, KS_CMDB,   0xb0, *iarg);
+                       ks0127_and_or(c, KS_CMDB,   0xb0, *iarg);
                        /* non-freerunning mode */
-                       ks0127_and_or(ks, KS_CMDC,   0x70, 0x0a);
+                       ks0127_and_or(c, KS_CMDC,   0x70, 0x0a);
                        /* analog input */
-                       ks0127_and_or(ks, KS_CMDD,   0x03, 0x00);
+                       ks0127_and_or(c, KS_CMDD,   0x03, 0x00);
                        /* enable chroma demodulation */
-                       ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
-                       ks0127_and_or(ks, KS_LUMA, 0x00,
+                       ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
+                       ks0127_and_or(c, KS_LUMA, 0x00,
                                       reg_defaults[KS_LUMA]);
                        /* disable luma comb */
-                       ks0127_and_or(ks, KS_VERTIA, 0x08,
+                       ks0127_and_or(c, KS_VERTIA, 0x08,
                                       (reg_defaults[KS_VERTIA]&0xf0)|0x01);
-                       ks0127_and_or(ks, KS_VERTIC, 0x0f,
+                       ks0127_and_or(c, KS_VERTIC, 0x0f,
                                       reg_defaults[KS_VERTIC]&0xf0);
 
-                       ks0127_and_or(ks, KS_CHROMB, 0x0f,
+                       ks0127_and_or(c, KS_CHROMB, 0x0f,
                                       reg_defaults[KS_CHROMB]&0xf0);
 
-                       ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
-                       ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
-                       ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
-                       ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+                       ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
+                       ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
+                       ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+                       ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
                        break;
 
                case KS_INPUT_YUV656:
-                       dprintk("ks0127: command DECODER_SET_INPUT 15: "
-                               "YUV656\n");
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_INPUT 15: YUV656\n");
                        if (ks->norm == VIDEO_MODE_NTSC ||
                            ks->norm == KS_STD_PAL_M)
                                /* force 60 Hz */
-                               ks0127_and_or(ks, KS_CMDA,   0xfc, 0x03);
+                               ks0127_and_or(c, KS_CMDA,   0xfc, 0x03);
                        else
                                /* force 50 Hz */
-                               ks0127_and_or(ks, KS_CMDA,   0xfc, 0x02);
+                               ks0127_and_or(c, KS_CMDA,   0xfc, 0x02);
 
-                       ks0127_and_or(ks, KS_CMDA,   0xff, 0x40); /* VSE=1 */
+                       ks0127_and_or(c, KS_CMDA,   0xff, 0x40); /* VSE=1 */
                        /* set input line and VALIGN */
-                       ks0127_and_or(ks, KS_CMDB,   0xb0, (*iarg | 0x40));
+                       ks0127_and_or(c, KS_CMDB,   0xb0, (*iarg | 0x40));
                        /* freerunning mode, */
                        /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0  VMEM=1*/
-                       ks0127_and_or(ks, KS_CMDC,   0x70, 0x87);
+                       ks0127_and_or(c, KS_CMDC,   0x70, 0x87);
                        /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
-                       ks0127_and_or(ks, KS_CMDD,   0x03, 0x08);
+                       ks0127_and_or(c, KS_CMDD,   0x03, 0x08);
                        /* disable chroma demodulation */
-                       ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
+                       ks0127_and_or(c, KS_CTRACK, 0xcf, 0x30);
                        /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
-                       ks0127_and_or(ks, KS_LUMA,   0x00, 0x71);
-                       ks0127_and_or(ks, KS_VERTIC, 0x0f,
+                       ks0127_and_or(c, KS_LUMA,   0x00, 0x71);
+                       ks0127_and_or(c, KS_VERTIC, 0x0f,
                                       reg_defaults[KS_VERTIC]&0xf0);
 
                        /* scaler fullbw, luma comb off */
-                       ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+                       ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
 
-                       ks0127_and_or(ks, KS_CHROMB, 0x0f,
+                       ks0127_and_or(c, KS_CHROMB, 0x0f,
                                       reg_defaults[KS_CHROMB]&0xf0);
 
-                       ks0127_and_or(ks, KS_CON, 0x00, 0x00);
-                       ks0127_and_or(ks, KS_BRT, 0x00, 32);    /* spec: 34 */
+                       ks0127_and_or(c, KS_CON, 0x00, 0x00);
+                       ks0127_and_or(c, KS_BRT, 0x00, 32);     /* spec: 34 */
                                /* spec: 229 (e5) */
-                       ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
-                       ks0127_and_or(ks, KS_HUE, 0x00, 0);
+                       ks0127_and_or(c, KS_SAT, 0x00, 0xe8);
+                       ks0127_and_or(c, KS_HUE, 0x00, 0);
 
-                       ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
-                       ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
+                       ks0127_and_or(c, KS_UGAIN, 0x00, 238);
+                       ks0127_and_or(c, KS_VGAIN, 0x00, 0x00);
 
                        /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
-                       ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
-                       ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
+                       ks0127_and_or(c, KS_UVOFFH, 0x00, 0x4f);
+                       ks0127_and_or(c, KS_UVOFFL, 0x00, 0x00);
                        break;
 
                default:
-                       dprintk("ks0127: command DECODER_SET_INPUT: "
-                               "Unknown input %d\n", *iarg);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_INPUT: Unknown input %d\n", *iarg);
                        break;
                }
 
                /* hack: CDMLPF sometimes spontaneously switches on; */
                /* force back off */
-               ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
+               ks0127_write(c, KS_DEMOD, reg_defaults[KS_DEMOD]);
                break;
 
        case DECODER_SET_OUTPUT:
                switch(*iarg) {
                case KS_OUTPUT_YUV656E:
-                       dprintk("ks0127: command DECODER_SET_OUTPUT: "
-                               "OUTPUT_YUV656E (Missing)\n");
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_OUTPUT: OUTPUT_YUV656E (Missing)\n");
                        return -EINVAL;
-                       break;
 
                case KS_OUTPUT_EXV:
-                       dprintk("ks0127: command DECODER_SET_OUTPUT: "
-                               "OUTPUT_EXV\n");
-                       ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_OUTPUT: OUTPUT_EXV\n");
+                       ks0127_and_or(c, KS_OFMTA, 0xf0, 0x09);
                        break;
                }
                break;
 
-       case DECODER_SET_NORM: //sam This block mixes old and new norm names...
+       case DECODER_SET_NORM: /* sam This block mixes old and new norm names... */
                /* Set to automatic SECAM/Fsc mode */
-               ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+               ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
 
                ks->norm = *iarg;
-               switch(*iarg)
-               {
+               switch (*iarg) {
                /* this is untested !! */
                /* It just detects PAL_N/NTSC_M (no special frequencies) */
                /* And you have to set the standard a second time afterwards */
                case VIDEO_MODE_AUTO:
-                       dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_NORM: AUTO\n");
 
                        /* The chip determines the format */
                        /* based on the current field rate */
-                       ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
-                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+                       ks0127_and_or(c, KS_CMDA,   0xfc, 0x00);
+                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
                        /* This is wrong for PAL ! As I said, */
                        /* you need to set the standard once again !! */
                        ks->format_height = 240;
@@ -598,84 +589,86 @@ static int ks0127_command(struct i2c_client *client,
                        break;
 
                case VIDEO_MODE_NTSC:
-                       dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
-                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_NORM: NTSC_M\n");
+                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
                        ks->format_height = 240;
                        ks->format_width = 704;
                        break;
 
                case KS_STD_NTSC_N:
-                       dprintk("ks0127: command KS0127_SET_STANDARD: "
-                               "NTSC_N (fixme)\n");
-                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+                       v4l_dbg(1, debug, c,
+                               "KS0127_SET_NORM: NTSC_N (fixme)\n");
+                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
                        ks->format_height = 240;
                        ks->format_width = 704;
                        break;
 
                case VIDEO_MODE_PAL:
-                       dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
-                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_NORM: PAL_N\n");
+                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
                        ks->format_height = 290;
                        ks->format_width = 704;
                        break;
 
                case KS_STD_PAL_M:
-                       dprintk("ks0127: command KS0127_SET_STANDARD: "
-                               "PAL_M (fixme)\n");
-                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+                       v4l_dbg(1, debug, c,
+                               "KS0127_SET_NORM: PAL_M (fixme)\n");
+                       ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
                        ks->format_height = 290;
                        ks->format_width = 704;
                        break;
 
                case VIDEO_MODE_SECAM:
-                       dprintk("ks0127: command KS0127_SET_STANDARD: "
-                               "SECAM\n");
+                       v4l_dbg(1, debug, c,
+                               "KS0127_SET_NORM: SECAM\n");
                        ks->format_height = 290;
                        ks->format_width = 704;
 
                        /* set to secam autodetection */
-                       ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
-                       ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+                       ks0127_and_or(c, KS_CHROMA, 0xdf, 0x20);
+                       ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
                        schedule_timeout_interruptible(HZ/10+1);
 
                        /* did it autodetect? */
-                       if (ks0127_read(ks, KS_DEMOD) & 0x40)
+                       if (ks0127_read(c, KS_DEMOD) & 0x40)
                                break;
 
                        /* force to secam mode */
-                       ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
+                       ks0127_and_or(c, KS_DEMOD, 0xf0, 0x0f);
                        break;
 
                default:
-                       dprintk("ks0127: command DECODER_SET_NORM: "
-                               "Unknown norm %d\n", *iarg);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_SET_NORM: Unknown norm %d\n", *iarg);
                        break;
                }
                break;
 
        case DECODER_SET_PICTURE:
-               dprintk("ks0127: command DECODER_SET_PICTURE "
-                       "not yet supported (fixme)\n");
+               v4l_dbg(1, debug, c,
+                       "DECODER_SET_PICTURE: not yet supported\n");
                return -EINVAL;
 
-       //sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
-       //sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
-       //sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
-       //sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
-       //sam todo: KS0127_SET_AGC_MODE:
-       //sam todo: KS0127_SET_AGC:
-       //sam todo: KS0127_SET_CHROMA_MODE:
-       //sam todo: KS0127_SET_PIXCLK_MODE:
-       //sam todo: KS0127_SET_GAMMA_MODE:
-       //sam todo: KS0127_SET_UGAIN:
-       //sam todo: KS0127_SET_VGAIN:
-       //sam todo: KS0127_SET_INVALY:
-       //sam todo: KS0127_SET_INVALU:
-       //sam todo: KS0127_SET_INVALV:
-       //sam todo: KS0127_SET_UNUSEY:
-       //sam todo: KS0127_SET_UNUSEU:
-       //sam todo: KS0127_SET_UNUSEV:
-       //sam todo: KS0127_SET_VSALIGN_MODE:
+       /* sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE */
+       /* sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE */
+       /* sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE? */
+       /* sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE */
+       /* sam todo: KS0127_SET_AGC_MODE: */
+       /* sam todo: KS0127_SET_AGC: */
+       /* sam todo: KS0127_SET_CHROMA_MODE: */
+       /* sam todo: KS0127_SET_PIXCLK_MODE: */
+       /* sam todo: KS0127_SET_GAMMA_MODE: */
+       /* sam todo: KS0127_SET_UGAIN: */
+       /* sam todo: KS0127_SET_VGAIN: */
+       /* sam todo: KS0127_SET_INVALY: */
+       /* sam todo: KS0127_SET_INVALU: */
+       /* sam todo: KS0127_SET_INVALV: */
+       /* sam todo: KS0127_SET_UNUSEY: */
+       /* sam todo: KS0127_SET_UNUSEU: */
+       /* sam todo: KS0127_SET_UNUSEV: */
+       /* sam todo: KS0127_SET_VSALIGN_MODE: */
 
        case DECODER_ENABLE_OUTPUT:
        {
@@ -684,34 +677,32 @@ static int ks0127_command(struct i2c_client *client,
                iarg = arg;
                enable = (*iarg != 0);
                if (enable) {
-                       dprintk("ks0127: command "
-                                       "DECODER_ENABLE_OUTPUT on "
-                                       "(%d)\n", enable);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_ENABLE_OUTPUT on\n");
                        /* All output pins on */
-                       ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+                       ks0127_and_or(c, KS_OFMTA, 0xcf, 0x30);
                        /* Obey the OEN pin */
-                       ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+                       ks0127_and_or(c, KS_CDEM, 0x7f, 0x00);
                } else {
-                       dprintk("ks0127: command "
-                                       "DECODER_ENABLE_OUTPUT off "
-                                       "(%d)\n", enable);
+                       v4l_dbg(1, debug, c,
+                               "DECODER_ENABLE_OUTPUT off\n");
                        /* Video output pins off */
-                       ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+                       ks0127_and_or(c, KS_OFMTA, 0xcf, 0x00);
                        /* Ignore the OEN pin */
-                       ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+                       ks0127_and_or(c, KS_CDEM, 0x7f, 0x80);
                }
-       }
                break;
+       }
 
-       //sam todo: KS0127_SET_OUTPUT_MODE:
-       //sam todo: KS0127_SET_WIDTH:
-       //sam todo: KS0127_SET_HEIGHT:
-       //sam todo: KS0127_SET_HSCALE:
+       /* sam todo: KS0127_SET_OUTPUT_MODE: */
+       /* sam todo: KS0127_SET_WIDTH: */
+       /* sam todo: KS0127_SET_HEIGHT: */
+       /* sam todo: KS0127_SET_HSCALE: */
 
        case DECODER_GET_STATUS:
-               dprintk("ks0127: command DECODER_GET_STATUS\n");
+               v4l_dbg(1, debug, c, "DECODER_GET_STATUS\n");
                *iarg = 0;
-               status = ks0127_read(ks, KS_STAT);
+               status = ks0127_read(c, KS_STAT);
                if (!(status & 0x20))            /* NOVID not set */
                        *iarg = (*iarg | DECODER_STATUS_GOOD);
                if ((status & 0x01))                  /* CLOCK set */
@@ -722,124 +713,81 @@ static int ks0127_command(struct i2c_client *client,
                        *iarg = (*iarg | DECODER_STATUS_NTSC);
                break;
 
-       //Catch any unknown command
+       /* Catch any unknown command */
        default:
-               dprintk("ks0127: command unknown: %04X\n", cmd);
+               v4l_dbg(1, debug, c, "unknown: 0x%08x\n", cmd);
                return -EINVAL;
        }
        return 0;
 }
 
 
-
-
-static int ks0127_probe(struct i2c_adapter *adapter);
-static int ks0127_detach(struct i2c_client *client);
-static int ks0127_command(struct i2c_client *client,
-                         unsigned int cmd, void *arg);
-
-
-
 /* Addresses to scan */
-static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
-                                      I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
-static unsigned short probe[2] =       {I2C_CLIENT_END, I2C_CLIENT_END};
-static unsigned short ignore[2] =      {I2C_CLIENT_END, I2C_CLIENT_END};
-static struct i2c_client_address_data addr_data = {
-       normal_i2c,
-       probe,
-       ignore,
-};
+#define I2C_KS0127_ADDON   0xD8
+#define I2C_KS0127_ONBOARD 0xDA
 
-static struct i2c_driver i2c_driver_ks0127 = {
-       .driver.name = "ks0127",
-       .id             = I2C_DRIVERID_KS0127,
-       .attach_adapter = ks0127_probe,
-       .detach_client  = ks0127_detach,
-       .command        = ks0127_command
+static unsigned short normal_i2c[] = {
+       I2C_KS0127_ADDON >> 1,
+       I2C_KS0127_ONBOARD >> 1,
+       I2C_CLIENT_END
 };
 
-static struct i2c_client ks0127_client_tmpl =
-{
-       .name = "(ks0127 unset)",
-       .addr = 0,
-       .adapter = NULL,
-       .driver = &i2c_driver_ks0127,
-};
+I2C_CLIENT_INSMOD;
 
-static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+static int ks0127_probe(struct i2c_client *c, const struct i2c_device_id *id)
 {
        struct ks0127 *ks;
-       struct i2c_client *client;
 
-       client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (client == NULL)
-               return -ENOMEM;
-       memcpy(client, &ks0127_client_tmpl, sizeof(*client));
+       v4l_info(c, "%s chip found @ 0x%x (%s)\n",
+               c->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
+               c->addr << 1, c->adapter->name);
 
        ks = kzalloc(sizeof(*ks), GFP_KERNEL);
-       if (ks == NULL) {
-               kfree(client);
+       if (ks == NULL)
                return -ENOMEM;
-       }
 
-       i2c_set_clientdata(client, ks);
-       client->adapter = adapter;
-       client->addr = addr;
-       sprintf(client->name, "ks0127-%02x", adapter->id);
+       i2c_set_clientdata(c, ks);
 
-       ks->client = client;
-       ks->addr = addr;
        ks->ks_type = KS_TYPE_UNKNOWN;
 
        /* power up */
-       ks0127_write(ks, KS_CMDA, 0x2c);
+       init_reg_defaults();
+       ks0127_write(c, KS_CMDA, 0x2c);
        mdelay(10);
 
        /* reset the device */
-       ks0127_reset(ks);
-       printk(KERN_INFO "ks0127: attach: %s video decoder\n",
-              ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
-
-       i2c_attach_client(client);
+       ks0127_reset(c);
        return 0;
 }
 
-
-static int ks0127_probe(struct i2c_adapter *adapter)
+static int ks0127_remove(struct i2c_client *c)
 {
-       if (adapter->id == I2C_HW_B_ZR36067)
-               return i2c_probe(adapter, &addr_data, ks0127_found_proc);
-       return 0;
-}
-
-static int ks0127_detach(struct i2c_client *client)
-{
-       struct ks0127 *ks = i2c_get_clientdata(client);
+       struct ks0127 *ks = i2c_get_clientdata(c);
 
-       ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
-       ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
+       ks0127_write(c, KS_OFMTA, 0x20); /* tristate */
+       ks0127_write(c, KS_CMDA, 0x2c | 0x80); /* power down */
 
-       i2c_detach_client(client);
        kfree(ks);
-       kfree(client);
-
-       dprintk("ks0127: detach\n");
        return 0;
 }
 
-
-static int __devinit ks0127_init_module(void)
+static int ks0127_legacy_probe(struct i2c_adapter *adapter)
 {
-       init_reg_defaults();
-       return i2c_add_driver(&i2c_driver_ks0127);
+       return adapter->id == I2C_HW_B_ZR36067;
 }
 
-static void __devexit ks0127_cleanup_module(void)
-{
-       i2c_del_driver(&i2c_driver_ks0127);
-}
-
-
-module_init(ks0127_init_module);
-module_exit(ks0127_cleanup_module);
+static const struct i2c_device_id ks0127_id[] = {
+       { "ks0127", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ks0127_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "ks0127",
+       .driverid = I2C_DRIVERID_KS0127,
+       .command = ks0127_command,
+       .probe = ks0127_probe,
+       .remove = ks0127_remove,
+       .legacy_probe = ks0127_legacy_probe,
+       .id_table = ks0127_id,
+};
index 4aa82b310708c768140e50b698e81932d21e94a0..adf2ba79496a48e0d9705a74738fd03b5a1b807b 100644 (file)
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
-#include <asm/io.h>
 #include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
 MODULE_AUTHOR("Pauline Middelink");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
-
-#define I2C_NAME(s) (s)->name
-
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <linux/video_decoder.h>
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 #define SAA7110_MAX_INPUT      9       /* 6 CVBS, 3 SVHS */
 #define SAA7110_MAX_OUTPUT     0       /* its a decoder only */
 
-#define        I2C_SAA7110             0x9C    /* or 0x9E */
-
 #define SAA7110_NR_REG         0x35
 
 struct saa7110 {
@@ -81,10 +69,7 @@ struct saa7110 {
 /* I2C support functions                                                  */
 /* ----------------------------------------------------------------------- */
 
-static int
-saa7110_write (struct i2c_client *client,
-              u8                 reg,
-              u8                 value)
+static int saa7110_write(struct i2c_client *client, u8 reg, u8 value)
 {
        struct saa7110 *decoder = i2c_get_clientdata(client);
 
@@ -92,10 +77,7 @@ saa7110_write (struct i2c_client *client,
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static int
-saa7110_write_block (struct i2c_client *client,
-                    const u8          *data,
-                    unsigned int       len)
+static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
 {
        int ret = -1;
        u8 reg = *data;         /* first register to write to */
@@ -115,8 +97,8 @@ saa7110_write_block (struct i2c_client *client,
                memcpy(decoder->reg + reg, data + 1, len - 1);
        } else {
                for (++data, --len; len; len--) {
-                       if ((ret = saa7110_write(client, reg++,
-                                                *data++)) < 0)
+                       ret = saa7110_write(client, reg++, *data++);
+                       if (ret < 0)
                                break;
                }
        }
@@ -124,8 +106,7 @@ saa7110_write_block (struct i2c_client *client,
        return ret;
 }
 
-static inline int
-saa7110_read (struct i2c_client *client)
+static inline int saa7110_read(struct i2c_client *client)
 {
        return i2c_smbus_read_byte(client);
 }
@@ -138,9 +119,7 @@ saa7110_read (struct i2c_client *client)
 #define FRESP_06H_SVIDEO 0x83  //0xC0
 
 
-static int
-saa7110_selmux (struct i2c_client *client,
-               int                chan)
+static int saa7110_selmux(struct i2c_client *client, int chan)
 {
        static const unsigned char modes[9][8] = {
                /* mode 0 */
@@ -197,8 +176,7 @@ static const unsigned char initseq[1 + SAA7110_NR_REG] = {
        /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
 };
 
-static int
-determine_norm (struct i2c_client *client)
+static int determine_norm(struct i2c_client *client)
 {
        DEFINE_WAIT(wait);
        struct saa7110 *decoder = i2c_get_clientdata(client);
@@ -212,29 +190,23 @@ determine_norm (struct i2c_client *client)
        finish_wait(&decoder->wq, &wait);
        status = saa7110_read(client);
        if (status & 0x40) {
-               dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n",
-                       I2C_NAME(client), status);
+               v4l_dbg(1, debug, client, "status=0x%02x (no signal)\n", status);
                return decoder->norm;   // no change
        }
        if ((status & 3) == 0) {
                saa7110_write(client, 0x06, 0x83);
                if (status & 0x20) {
-                       dprintk(1,
-                               KERN_INFO
-                               "%s: status=0x%02x (NTSC/no color)\n",
-                               I2C_NAME(client), status);
+                       v4l_dbg(1, debug, client, "status=0x%02x (NTSC/no color)\n", status);
                        //saa7110_write(client,0x2E,0x81);
                        return VIDEO_MODE_NTSC;
                }
-               dprintk(1, KERN_INFO "%s: status=0x%02x (PAL/no color)\n",
-                       I2C_NAME(client), status);
+               v4l_dbg(1, debug, client, "status=0x%02x (PAL/no color)\n", status);
                //saa7110_write(client,0x2E,0x9A);
                return VIDEO_MODE_PAL;
        }
        //saa7110_write(client,0x06,0x03);
        if (status & 0x20) {    /* 60Hz */
-               dprintk(1, KERN_INFO "%s: status=0x%02x (NTSC)\n",
-                       I2C_NAME(client), status);
+               v4l_dbg(1, debug, client, "status=0x%02x (NTSC)\n", status);
                saa7110_write(client, 0x0D, 0x86);
                saa7110_write(client, 0x0F, 0x50);
                saa7110_write(client, 0x11, 0x2C);
@@ -254,13 +226,11 @@ determine_norm (struct i2c_client *client)
 
        status = saa7110_read(client);
        if ((status & 0x03) == 0x01) {
-               dprintk(1, KERN_INFO "%s: status=0x%02x (SECAM)\n",
-                       I2C_NAME(client), status);
+               v4l_dbg(1, debug, client, "status=0x%02x (SECAM)\n", status);
                saa7110_write(client, 0x0D, 0x87);
                return VIDEO_MODE_SECAM;
        }
-       dprintk(1, KERN_INFO "%s: status=0x%02x (PAL)\n", I2C_NAME(client),
-               status);
+       v4l_dbg(1, debug, client, "status=0x%02x (PAL)\n", status);
        return VIDEO_MODE_PAL;
 }
 
@@ -286,8 +256,8 @@ saa7110_command (struct i2c_client *client,
                    VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
                dc->inputs = SAA7110_MAX_INPUT;
                dc->outputs = SAA7110_MAX_OUTPUT;
-       }
                break;
+       }
 
        case DECODER_GET_STATUS:
        {
@@ -295,8 +265,8 @@ saa7110_command (struct i2c_client *client,
                int res = 0;
 
                status = saa7110_read(client);
-               dprintk(1, KERN_INFO "%s: status=0x%02x norm=%d\n",
-                       I2C_NAME(client), status, decoder->norm);
+               v4l_dbg(1, debug, client, "status=0x%02x norm=%d\n",
+                              status, decoder->norm);
                if (!(status & 0x40))
                        res |= DECODER_STATUS_GOOD;
                if (status & 0x03)
@@ -314,8 +284,8 @@ saa7110_command (struct i2c_client *client,
                        break;
                }
                *(int *) arg = res;
-       }
                break;
+       }
 
        case DECODER_SET_NORM:
                v = *(int *) arg;
@@ -328,34 +298,24 @@ saa7110_command (struct i2c_client *client,
                                saa7110_write(client, 0x0F, 0x50);
                                saa7110_write(client, 0x11, 0x2C);
                                //saa7110_write(client, 0x2E, 0x81);
-                               dprintk(1,
-                                       KERN_INFO "%s: switched to NTSC\n",
-                                       I2C_NAME(client));
+                               v4l_dbg(1, debug, client, "switched to NTSC\n");
                                break;
                        case VIDEO_MODE_PAL:
                                saa7110_write(client, 0x0D, 0x86);
                                saa7110_write(client, 0x0F, 0x10);
                                saa7110_write(client, 0x11, 0x59);
                                //saa7110_write(client, 0x2E, 0x9A);
-                               dprintk(1,
-                                       KERN_INFO "%s: switched to PAL\n",
-                                       I2C_NAME(client));
+                               v4l_dbg(1, debug, client, "switched to PAL\n");
                                break;
                        case VIDEO_MODE_SECAM:
                                saa7110_write(client, 0x0D, 0x87);
                                saa7110_write(client, 0x0F, 0x10);
                                saa7110_write(client, 0x11, 0x59);
                                //saa7110_write(client, 0x2E, 0x9A);
-                               dprintk(1,
-                                       KERN_INFO
-                                       "%s: switched to SECAM\n",
-                                       I2C_NAME(client));
+                               v4l_dbg(1, debug, client, "switched to SECAM\n");
                                break;
                        case VIDEO_MODE_AUTO:
-                               dprintk(1,
-                                       KERN_INFO
-                                       "%s: TV standard detection...\n",
-                                       I2C_NAME(client));
+                               v4l_dbg(1, debug, client, "switched to AUTO\n");
                                decoder->norm = determine_norm(client);
                                *(int *) arg = decoder->norm;
                                break;
@@ -368,15 +328,12 @@ saa7110_command (struct i2c_client *client,
        case DECODER_SET_INPUT:
                v = *(int *) arg;
                if (v < 0 || v > SAA7110_MAX_INPUT) {
-                       dprintk(1,
-                               KERN_INFO "%s: input=%d not available\n",
-                               I2C_NAME(client), v);
+                       v4l_dbg(1, debug, client, "input=%d not available\n", v);
                        return -EINVAL;
                }
                if (decoder->input != v) {
                        saa7110_selmux(client, v);
-                       dprintk(1, KERN_INFO "%s: switched to input=%d\n",
-                               I2C_NAME(client), v);
+                       v4l_dbg(1, debug, client, "switched to input=%d\n", v);
                }
                break;
 
@@ -392,8 +349,7 @@ saa7110_command (struct i2c_client *client,
                if (decoder->enable != v) {
                        decoder->enable = v;
                        saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
-                       dprintk(1, KERN_INFO "%s: YUV %s\n", I2C_NAME(client),
-                               v ? "on" : "off");
+                       v4l_dbg(1, debug, client, "YUV %s\n", v ? "on" : "off");
                }
                break;
 
@@ -423,23 +379,23 @@ saa7110_command (struct i2c_client *client,
                        saa7110_write(client, 0x07,
                                      (decoder->hue >> 8) - 128);
                }
-       }
                break;
+       }
 
        case DECODER_DUMP:
+               if (!debug)
+                       break;
                for (v = 0; v < SAA7110_NR_REG; v += 16) {
                        int j;
-                       dprintk(1, KERN_DEBUG "%s: %02x:", I2C_NAME(client),
-                               v);
+                       v4l_dbg(1, debug, client, "%02x:", v);
                        for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++)
-                               dprintk(1, " %02x", decoder->reg[v + j]);
-                       dprintk(1, "\n");
+                               printk(KERN_CONT " %02x", decoder->reg[v + j]);
+                       printk(KERN_CONT "\n");
                }
                break;
 
        default:
-               dprintk(1, KERN_INFO "unknown saa7110_command??(%d)\n",
-                       cmd);
+               v4l_dbg(1, debug, client, "unknown command %08x\n", cmd);
                return -EINVAL;
        }
        return 0;
@@ -451,55 +407,28 @@ saa7110_command (struct i2c_client *client,
  * Generic i2c probe
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
-static unsigned short normal_i2c[] = {
-       I2C_SAA7110 >> 1,
-       (I2C_SAA7110 >> 1) + 1,
-       I2C_CLIENT_END
-};
-
-static unsigned short ignore = I2C_CLIENT_END;
 
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
+static unsigned short normal_i2c[] = { 0x9c >> 1, 0x9e >> 1, I2C_CLIENT_END };
 
-static struct i2c_driver i2c_driver_saa7110;
+I2C_CLIENT_INSMOD;
 
-static int
-saa7110_detect_client (struct i2c_adapter *adapter,
-                      int                 address,
-                      int                 kind)
+static int saa7110_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       struct i2c_client *client;
        struct saa7110 *decoder;
        int rv;
 
-       dprintk(1,
-               KERN_INFO
-               "saa7110.c: detecting saa7110 client on address 0x%x\n",
-               address << 1);
-
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality
-           (adapter,
-            I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter,
+               I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_saa7110;
-       strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
-       if (!decoder) {
-               kfree(client);
+       if (!decoder)
                return -ENOMEM;
-       }
        decoder->norm = VIDEO_MODE_PAL;
        decoder->input = 0;
        decoder->enable = 1;
@@ -510,18 +439,10 @@ saa7110_detect_client (struct i2c_adapter *adapter,
        init_waitqueue_head(&decoder->wq);
        i2c_set_clientdata(client, decoder);
 
-       rv = i2c_attach_client(client);
-       if (rv) {
-               kfree(client);
-               kfree(decoder);
-               return rv;
-       }
-
        rv = saa7110_write_block(client, initseq, sizeof(initseq));
-       if (rv < 0)
-               dprintk(1, KERN_ERR "%s_attach: init status %d\n",
-                       I2C_NAME(client), rv);
-       else {
+       if (rv < 0) {
+               v4l_dbg(1, debug, client, "init status %d\n", rv);
+       } else {
                int ver, status;
                saa7110_write(client, 0x21, 0x10);
                saa7110_write(client, 0x0e, 0x18);
@@ -530,10 +451,8 @@ saa7110_detect_client (struct i2c_adapter *adapter,
                saa7110_write(client, 0x0D, 0x06);
                //mdelay(150);
                status = saa7110_read(client);
-               dprintk(1,
-                       KERN_INFO
-                       "%s_attach: SAA7110A version %x at 0x%02x, status=0x%02x\n",
-                       I2C_NAME(client), ver, client->addr << 1, status);
+               v4l_dbg(1, debug, client, "version %x, status=0x%02x\n",
+                              ver, status);
                saa7110_write(client, 0x0D, 0x86);
                saa7110_write(client, 0x0F, 0x10);
                saa7110_write(client, 0x11, 0x59);
@@ -547,58 +466,25 @@ saa7110_detect_client (struct i2c_adapter *adapter,
        return 0;
 }
 
-static int
-saa7110_attach_adapter (struct i2c_adapter *adapter)
-{
-       dprintk(1,
-               KERN_INFO
-               "saa7110.c: starting probe for adapter %s (0x%x)\n",
-               I2C_NAME(adapter), adapter->id);
-       return i2c_probe(adapter, &addr_data, &saa7110_detect_client);
-}
-
-static int
-saa7110_detach_client (struct i2c_client *client)
+static int saa7110_remove(struct i2c_client *client)
 {
-       struct saa7110 *decoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(decoder);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7110 = {
-       .driver = {
-               .name = "saa7110",
-       },
-
-       .id = I2C_DRIVERID_SAA7110,
+static const struct i2c_device_id saa7110_id[] = {
+       { "saa7110", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7110_id);
 
-       .attach_adapter = saa7110_attach_adapter,
-       .detach_client = saa7110_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa7110",
+       .driverid = I2C_DRIVERID_SAA7110,
        .command = saa7110_command,
+       .probe = saa7110_probe,
+       .remove = saa7110_remove,
+       .id_table = saa7110_id,
 };
-
-static int __init
-saa7110_init (void)
-{
-       return i2c_add_driver(&i2c_driver_saa7110);
-}
-
-static void __exit
-saa7110_exit (void)
-{
-       i2c_del_driver(&i2c_driver_saa7110);
-}
-
-module_init(saa7110_init);
-module_exit(saa7110_exit);
index 96c3d4357722fb32d279a8f63aae8a7318c6b7d5..a4738a2fb4d32753498b0091fdcf97d716cbd94f 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
 #include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-
-#define I2C_NAME(s) (s)->name
-
-
 static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* ----------------------------------------------------------------------- */
 
 #define SAA7111_NR_REG         0x18
@@ -77,14 +58,9 @@ struct saa7111 {
        int enable;
 };
 
-#define   I2C_SAA7111        0x48
-
 /* ----------------------------------------------------------------------- */
 
-static inline int
-saa7111_write (struct i2c_client *client,
-              u8                 reg,
-              u8                 value)
+static inline int saa7111_write(struct i2c_client *client, u8 reg, u8 value)
 {
        struct saa7111 *decoder = i2c_get_clientdata(client);
 
@@ -92,8 +68,7 @@ saa7111_write (struct i2c_client *client,
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline void
-saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
+static inline void saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
 {
        struct saa7111 *decoder = i2c_get_clientdata(client);
 
@@ -103,10 +78,7 @@ saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
        }
 }
 
-static int
-saa7111_write_block (struct i2c_client *client,
-                    const u8          *data,
-                    unsigned int       len)
+static int saa7111_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
 {
        int ret = -1;
        u8 reg;
@@ -127,18 +99,17 @@ saa7111_write_block (struct i2c_client *client,
                                    decoder->reg[reg++] = data[1];
                                len -= 2;
                                data += 2;
-                       } while (len >= 2 && data[0] == reg &&
-                                block_len < 32);
-                       if ((ret = i2c_master_send(client, block_data,
-                                                  block_len)) < 0)
+                       } while (len >= 2 && data[0] == reg && block_len < 32);
+                       ret = i2c_master_send(client, block_data, block_len);
+                       if (ret < 0)
                                break;
                }
        } else {
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       if ((ret = saa7111_write(client, reg,
-                                                *data++)) < 0)
+                       ret = saa7111_write(client, reg, *data++);
+                       if (ret < 0)
                                break;
                        len -= 2;
                }
@@ -147,16 +118,13 @@ saa7111_write_block (struct i2c_client *client,
        return ret;
 }
 
-static int
-saa7111_init_decoder (struct i2c_client *client,
-             struct video_decoder_init *init)
+static int saa7111_init_decoder(struct i2c_client *client,
+               struct video_decoder_init *init)
 {
        return saa7111_write_block(client, init->data, init->len);
 }
 
-static inline int
-saa7111_read (struct i2c_client *client,
-             u8                 reg)
+static inline int saa7111_read(struct i2c_client *client, u8 reg)
 {
        return i2c_smbus_read_byte_data(client, reg);
 }
@@ -203,28 +171,23 @@ static const unsigned char saa7111_i2c_init[] = {
        0x17, 0x00,             /* 17 - VBI */
 };
 
-static int
-saa7111_command (struct i2c_client *client,
-                unsigned int       cmd,
-                void              *arg)
+static int saa7111_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct saa7111 *decoder = i2c_get_clientdata(client);
 
        switch (cmd) {
-
        case 0:
                break;
        case DECODER_INIT:
        {
                struct video_decoder_init *init = arg;
+               struct video_decoder_init vdi;
+
                if (NULL != init)
                        return saa7111_init_decoder(client, init);
-               else {
-                       struct video_decoder_init vdi;
-                       vdi.data = saa7111_i2c_init;
-                       vdi.len = sizeof(saa7111_i2c_init);
-                       return saa7111_init_decoder(client, &vdi);
-               }
+               vdi.data = saa7111_i2c_init;
+               vdi.len = sizeof(saa7111_i2c_init);
+               return saa7111_init_decoder(client, &vdi);
        }
 
        case DECODER_DUMP:
@@ -234,15 +197,15 @@ saa7111_command (struct i2c_client *client,
                for (i = 0; i < SAA7111_NR_REG; i += 16) {
                        int j;
 
-                       printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+                       v4l_info(client, "%03x", i);
                        for (j = 0; j < 16 && i + j < SAA7111_NR_REG; ++j) {
-                               printk(" %02x",
+                               printk(KERN_CONT " %02x",
                                       saa7111_read(client, i + j));
                        }
-                       printk("\n");
+                       printk(KERN_CONT "\n");
                }
-       }
                break;
+       }
 
        case DECODER_GET_CAPABILITIES:
        {
@@ -255,8 +218,8 @@ saa7111_command (struct i2c_client *client,
                             VIDEO_DECODER_CCIR;
                cap->inputs = 8;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case DECODER_GET_STATUS:
        {
@@ -265,8 +228,7 @@ saa7111_command (struct i2c_client *client,
                int res;
 
                status = saa7111_read(client, 0x1f);
-               dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
-                       status);
+               v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
                res = 0;
                if ((status & (1 << 6)) == 0) {
                        res |= DECODER_STATUS_GOOD;
@@ -294,8 +256,8 @@ saa7111_command (struct i2c_client *client,
                        res |= DECODER_STATUS_COLOR;
                }
                *iarg = res;
-       }
                break;
+       }
 
        case DECODER_SET_GPIO:
        {
@@ -362,8 +324,8 @@ saa7111_command (struct i2c_client *client,
 
                }
                decoder->norm = *iarg;
-       }
                break;
+       }
 
        case DECODER_SET_INPUT:
        {
@@ -387,8 +349,8 @@ saa7111_command (struct i2c_client *client,
                                                             3) ? 0x80 :
                                                            0));
                }
-       }
                break;
+       }
 
        case DECODER_SET_OUTPUT:
        {
@@ -398,8 +360,8 @@ saa7111_command (struct i2c_client *client,
                if (*iarg != 0) {
                        return -EINVAL;
                }
-       }
                break;
+       }
 
        case DECODER_ENABLE_OUTPUT:
        {
@@ -439,8 +401,8 @@ saa7111_command (struct i2c_client *client,
                                              (decoder->reg[0x11] & 0xf3));
                        }
                }
-       }
                break;
+       }
 
        case DECODER_SET_PICTURE:
        {
@@ -454,8 +416,8 @@ saa7111_command (struct i2c_client *client,
                saa7111_write(client, 0x0c, pic->colour >> 9);
                /* We want -128 to 127 we get 0-65535 */
                saa7111_write(client, 0x0d, (pic->hue - 32768) >> 8);
-       }
                break;
+       }
 
        default:
                return -EINVAL;
@@ -466,48 +428,23 @@ saa7111_command (struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END };
-
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
+static unsigned short normal_i2c[] = { 0x48 >> 1, I2C_CLIENT_END };
 
-static struct i2c_driver i2c_driver_saa7111;
+I2C_CLIENT_INSMOD;
 
-static int
-saa7111_detect_client (struct i2c_adapter *adapter,
-                      int                 address,
-                      int                 kind)
+static int saa7111_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        int i;
-       struct i2c_client *client;
        struct saa7111 *decoder;
        struct video_decoder_init vdi;
 
-       dprintk(1,
-               KERN_INFO
-               "saa7111.c: detecting saa7111 client on address 0x%x\n",
-               address << 1);
-
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_saa7111;
-       strlcpy(I2C_NAME(client), "saa7111", sizeof(I2C_NAME(client)));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        decoder = kzalloc(sizeof(struct saa7111), GFP_KERNEL);
        if (decoder == NULL) {
@@ -519,82 +456,37 @@ saa7111_detect_client (struct i2c_adapter *adapter,
        decoder->enable = 1;
        i2c_set_clientdata(client, decoder);
 
-       i = i2c_attach_client(client);
-       if (i) {
-               kfree(client);
-               kfree(decoder);
-               return i;
-       }
-
        vdi.data = saa7111_i2c_init;
        vdi.len = sizeof(saa7111_i2c_init);
        i = saa7111_init_decoder(client, &vdi);
        if (i < 0) {
-               dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
-                       I2C_NAME(client), i);
+               v4l_dbg(1, debug, client, "init status %d\n", i);
        } else {
-               dprintk(1,
-                       KERN_INFO
-                       "%s_attach: chip version %x at address 0x%x\n",
-                       I2C_NAME(client), saa7111_read(client, 0x00) >> 4,
-                       client->addr << 1);
+               v4l_dbg(1, debug, client, "revision %x\n",
+                       saa7111_read(client, 0x00) >> 4);
        }
-
        return 0;
 }
 
-static int
-saa7111_attach_adapter (struct i2c_adapter *adapter)
+static int saa7111_remove(struct i2c_client *client)
 {
-       dprintk(1,
-               KERN_INFO
-               "saa7111.c: starting probe for adapter %s (0x%x)\n",
-               I2C_NAME(adapter), adapter->id);
-       return i2c_probe(adapter, &addr_data, &saa7111_detect_client);
-}
-
-static int
-saa7111_detach_client (struct i2c_client *client)
-{
-       struct saa7111 *decoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(decoder);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7111 = {
-       .driver = {
-               .name = "saa7111",
-       },
-
-       .id = I2C_DRIVERID_SAA7111A,
+static const struct i2c_device_id saa7111_id[] = {
+       { "saa7111_old", 0 },   /* "saa7111" maps to the saa7115 driver */
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7111_id);
 
-       .attach_adapter = saa7111_attach_adapter,
-       .detach_client = saa7111_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa7111",
+       .driverid = I2C_DRIVERID_SAA7111A,
        .command = saa7111_command,
+       .probe = saa7111_probe,
+       .remove = saa7111_remove,
+       .id_table = saa7111_id,
 };
-
-static int __init
-saa7111_init (void)
-{
-       return i2c_add_driver(&i2c_driver_saa7111);
-}
-
-static void __exit
-saa7111_exit (void)
-{
-       i2c_del_driver(&i2c_driver_saa7111);
-}
-
-module_init(saa7111_init);
-module_exit(saa7111_exit);
index e79075533beb2bcc9ffc90825d8777e5cf0c033f..7ca709fda5f4af38b9dc3b098279f29d217da7f8 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
 #include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-
-#define I2C_NAME(x) (x)->name
-
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* ----------------------------------------------------------------------- */
 
 struct saa7114 {
@@ -81,9 +62,6 @@ struct saa7114 {
        int playback;
 };
 
-#define   I2C_SAA7114        0x42
-#define   I2C_SAA7114A       0x40
-
 #define   I2C_DELAY   10
 
 
@@ -129,18 +107,12 @@ struct saa7114 {
 
 /* ----------------------------------------------------------------------- */
 
-static inline int
-saa7114_write (struct i2c_client *client,
-              u8                 reg,
-              u8                 value)
+static inline int saa7114_write(struct i2c_client *client, u8 reg, u8 value)
 {
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static int
-saa7114_write_block (struct i2c_client *client,
-                    const u8          *data,
-                    unsigned int       len)
+static int saa7114_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
 {
        int ret = -1;
        u8 reg;
@@ -160,18 +132,17 @@ saa7114_write_block (struct i2c_client *client,
                                reg++;
                                len -= 2;
                                data += 2;
-                       } while (len >= 2 && data[0] == reg &&
-                                block_len < 32);
-                       if ((ret = i2c_master_send(client, block_data,
-                                                  block_len)) < 0)
+                       } while (len >= 2 && data[0] == reg && block_len < 32);
+                       ret = i2c_master_send(client, block_data, block_len);
+                       if (ret < 0)
                                break;
                }
        } else {
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       if ((ret = saa7114_write(client, reg,
-                                                *data++)) < 0)
+                       ret = saa7114_write(client, reg, *data++);
+                       if (ret < 0)
                                break;
                        len -= 2;
                }
@@ -180,9 +151,7 @@ saa7114_write_block (struct i2c_client *client,
        return ret;
 }
 
-static inline int
-saa7114_read (struct i2c_client *client,
-             u8                 reg)
+static inline int saa7114_read(struct i2c_client *client, u8 reg)
 {
        return i2c_smbus_read_byte_data(client, reg);
 }
@@ -452,15 +421,11 @@ static const unsigned char init[] = {
        0xef, 0x00
 };
 
-static int
-saa7114_command (struct i2c_client *client,
-                unsigned int       cmd,
-                void              *arg)
+static int saa7114_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct saa7114 *decoder = i2c_get_clientdata(client);
 
        switch (cmd) {
-
        case 0:
                //dprintk(1, KERN_INFO "%s: writing init\n", I2C_NAME(client));
                //saa7114_write_block(client, init, sizeof(init));
@@ -470,27 +435,28 @@ saa7114_command (struct i2c_client *client,
        {
                int i;
 
-               dprintk(1, KERN_INFO "%s: decoder dump\n", I2C_NAME(client));
+               if (!debug)
+                       break;
+               v4l_info(client, "decoder dump\n");
 
                for (i = 0; i < 32; i += 16) {
                        int j;
 
-                       printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+                       v4l_info(client, "%03x", i);
                        for (j = 0; j < 16; ++j) {
-                               printk(" %02x",
+                               printk(KERN_CONT " %02x",
                                       saa7114_read(client, i + j));
                        }
-                       printk("\n");
+                       printk(KERN_CONT "\n");
                }
-       }
                break;
+       }
 
        case DECODER_GET_CAPABILITIES:
        {
                struct video_decoder_capability *cap = arg;
 
-               dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n",
-                       I2C_NAME(client));
+               v4l_dbg(1, debug, client, "get capabilities\n");
 
                cap->flags = VIDEO_DECODER_PAL |
                             VIDEO_DECODER_NTSC |
@@ -498,8 +464,8 @@ saa7114_command (struct i2c_client *client,
                             VIDEO_DECODER_CCIR;
                cap->inputs = 8;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case DECODER_GET_STATUS:
        {
@@ -509,8 +475,7 @@ saa7114_command (struct i2c_client *client,
 
                status = saa7114_read(client, 0x1f);
 
-               dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
-                       status);
+               v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
                res = 0;
                if ((status & (1 << 6)) == 0) {
                        res |= DECODER_STATUS_GOOD;
@@ -538,8 +503,8 @@ saa7114_command (struct i2c_client *client,
                        res |= DECODER_STATUS_COLOR;
                }
                *iarg = res;
-       }
                break;
+       }
 
        case DECODER_SET_NORM:
        {
@@ -547,12 +512,11 @@ saa7114_command (struct i2c_client *client,
 
                short int hoff = 0, voff = 0, w = 0, h = 0;
 
-               dprintk(1, KERN_DEBUG "%s: decoder set norm ",
-                       I2C_NAME(client));
-               switch (*iarg) {
+               v4l_dbg(1, debug, client, "set norm\n");
 
+               switch (*iarg) {
                case VIDEO_MODE_NTSC:
-                       dprintk(1, "NTSC\n");
+                       v4l_dbg(1, debug, client, "NTSC\n");
                        decoder->reg[REG_ADDR(0x06)] =
                            SAA_7114_NTSC_HSYNC_START;
                        decoder->reg[REG_ADDR(0x07)] =
@@ -571,7 +535,7 @@ saa7114_command (struct i2c_client *client,
                        break;
 
                case VIDEO_MODE_PAL:
-                       dprintk(1, "PAL\n");
+                       v4l_dbg(1, debug, client, "PAL\n");
                        decoder->reg[REG_ADDR(0x06)] =
                            SAA_7114_PAL_HSYNC_START;
                        decoder->reg[REG_ADDR(0x07)] =
@@ -590,9 +554,8 @@ saa7114_command (struct i2c_client *client,
                        break;
 
                default:
-                       dprintk(1, " Unknown video mode!!!\n");
+                       v4l_dbg(1, debug, client, "Unknown video mode\n");
                        return -EINVAL;
-
                }
 
 
@@ -644,22 +607,20 @@ saa7114_command (struct i2c_client *client,
                saa7114_write(client, 0x80, 0x36);      // i-port and scaler back end clock selection
 
                decoder->norm = *iarg;
-       }
                break;
+       }
 
        case DECODER_SET_INPUT:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n",
-                       I2C_NAME(client), *iarg);
+               v4l_dbg(1, debug, client, "set input (%d)\n", *iarg);
                if (*iarg < 0 || *iarg > 7) {
                        return -EINVAL;
                }
 
                if (decoder->input != *iarg) {
-                       dprintk(1, KERN_DEBUG "%s: now setting %s input\n",
-                               I2C_NAME(client),
+                       v4l_dbg(1, debug, client, "now setting %s input\n",
                                *iarg >= 6 ? "S-Video" : "Composite");
                        decoder->input = *iarg;
 
@@ -690,30 +651,29 @@ saa7114_command (struct i2c_client *client,
                        saa7114_write(client, 0x0e,
                                      decoder->reg[REG_ADDR(0x0e)]);
                }
-       }
                break;
+       }
 
        case DECODER_SET_OUTPUT:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_DEBUG "%s: decoder set output\n",
-                       I2C_NAME(client));
+               v4l_dbg(1, debug, client, "set output\n");
 
                /* not much choice of outputs */
                if (*iarg != 0) {
                        return -EINVAL;
                }
-       }
                break;
+       }
 
        case DECODER_ENABLE_OUTPUT:
        {
                int *iarg = arg;
                int enable = (*iarg != 0);
 
-               dprintk(1, KERN_DEBUG "%s: decoder %s output\n",
-                       I2C_NAME(client), enable ? "enable" : "disable");
+               v4l_dbg(1, debug, client, "%s output\n",
+                       enable ? "enable" : "disable");
 
                decoder->playback = !enable;
 
@@ -754,18 +714,16 @@ saa7114_command (struct i2c_client *client,
                        saa7114_write(client, 0x80, 0x36);
 
                }
-       }
                break;
+       }
 
        case DECODER_SET_PICTURE:
        {
                struct video_picture *pic = arg;
 
-               dprintk(1,
-                       KERN_DEBUG
-                       "%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
-                       I2C_NAME(client), pic->brightness, pic->contrast,
-                       pic->colour, pic->hue);
+               v4l_dbg(1, debug, client,
+                       "decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
+                       pic->brightness, pic->contrast, pic->colour, pic->hue);
 
                if (decoder->bright != pic->brightness) {
                        /* We want 0 to 255 we get 0-65535 */
@@ -789,8 +747,8 @@ saa7114_command (struct i2c_client *client,
                        saa7114_write(client, 0x0d,
                                      (decoder->hue - 32768) >> 8);
                }
-       }
                break;
+       }
 
        default:
                return -EINVAL;
@@ -801,58 +759,30 @@ saa7114_command (struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] =
-    { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END };
-
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
+static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
 
-static struct i2c_driver i2c_driver_saa7114;
+I2C_CLIENT_INSMOD;
 
-static int
-saa7114_detect_client (struct i2c_adapter *adapter,
-                      int                 address,
-                      int                 kind)
+static int saa7114_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        int i, err[30];
        short int hoff = SAA_7114_NTSC_HOFFSET;
        short int voff = SAA_7114_NTSC_VOFFSET;
        short int w = SAA_7114_NTSC_WIDTH;
        short int h = SAA_7114_NTSC_HEIGHT;
-       struct i2c_client *client;
        struct saa7114 *decoder;
 
-       dprintk(1,
-               KERN_INFO
-               "saa7114.c: detecting saa7114 client on address 0x%x\n",
-               address << 1);
-
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_saa7114;
-       strlcpy(I2C_NAME(client), "saa7114", sizeof(I2C_NAME(client)));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        decoder = kzalloc(sizeof(struct saa7114), GFP_KERNEL);
-       if (decoder == NULL) {
-               kfree(client);
+       if (decoder == NULL)
                return -ENOMEM;
-       }
        decoder->norm = VIDEO_MODE_NTSC;
        decoder->input = -1;
        decoder->enable = 1;
@@ -937,8 +867,7 @@ saa7114_detect_client (struct i2c_adapter *adapter,
        decoder->reg[REG_ADDR(0x0e)] |= 1;      // combfilter on
 
 
-       dprintk(1, KERN_DEBUG "%s_attach: starting decoder init\n",
-               I2C_NAME(client));
+       v4l_dbg(1, debug, client, "starting init\n");
 
        err[0] =
            saa7114_write_block(client, decoder->reg + (0x20 << 1),
@@ -962,28 +891,23 @@ saa7114_detect_client (struct i2c_adapter *adapter,
 
        for (i = 0; i <= 5; i++) {
                if (err[i] < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s_attach: init error %d at stage %d, leaving attach.\n",
-                               I2C_NAME(client), i, err[i]);
+                       v4l_dbg(1, debug, client,
+                               "init error %d at stage %d, leaving attach.\n",
+                               i, err[i]);
                        kfree(decoder);
-                       kfree(client);
-                       return 0;
+                       return -EIO;
                }
        }
 
        for (i = 6; i < 8; i++) {
-               dprintk(1,
-                       KERN_DEBUG
-                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       I2C_NAME(client), i, saa7114_read(client, i),
+               v4l_dbg(1, debug, client,
+                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       i, saa7114_read(client, i),
                        decoder->reg[REG_ADDR(i)]);
        }
 
-       dprintk(1,
-               KERN_DEBUG
-               "%s_attach: performing decoder reset sequence\n",
-               I2C_NAME(client));
+       v4l_dbg(1, debug, client,
+               "performing decoder reset sequence\n");
 
        err[6] = saa7114_write(client, 0x80, 0x06);     // i-port and scaler backend clock selection, task A&B off
        err[7] = saa7114_write(client, 0x88, 0xd8);     // sw reset scaler
@@ -991,19 +915,15 @@ saa7114_detect_client (struct i2c_adapter *adapter,
 
        for (i = 6; i <= 8; i++) {
                if (err[i] < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s_attach: init error %d at stage %d, leaving attach.\n",
-                               I2C_NAME(client), i, err[i]);
+                       v4l_dbg(1, debug, client,
+                               "init error %d at stage %d, leaving attach.\n",
+                               i, err[i]);
                        kfree(decoder);
-                       kfree(client);
-                       return 0;
+                       return -EIO;
                }
        }
 
-       dprintk(1, KERN_INFO "%s_attach: performing the rest of init\n",
-               I2C_NAME(client));
-
+       v4l_dbg(1, debug, client, "performing the rest of init\n");
 
        err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]);
        err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1);      // big seq
@@ -1039,37 +959,32 @@ saa7114_detect_client (struct i2c_adapter *adapter,
 
        for (i = 9; i <= 18; i++) {
                if (err[i] < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s_attach: init error %d at stage %d, leaving attach.\n",
-                               I2C_NAME(client), i, err[i]);
+                       v4l_dbg(1, debug, client,
+                               "init error %d at stage %d, leaving attach.\n",
+                               i, err[i]);
                        kfree(decoder);
-                       kfree(client);
-                       return 0;
+                       return -EIO;
                }
        }
 
 
        for (i = 6; i < 8; i++) {
-               dprintk(1,
-                       KERN_DEBUG
-                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       I2C_NAME(client), i, saa7114_read(client, i),
+               v4l_dbg(1, debug, client,
+                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       i, saa7114_read(client, i),
                        decoder->reg[REG_ADDR(i)]);
        }
 
 
        for (i = 0x11; i <= 0x13; i++) {
-               dprintk(1,
-                       KERN_DEBUG
-                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       I2C_NAME(client), i, saa7114_read(client, i),
+               v4l_dbg(1, debug, client,
+                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       i, saa7114_read(client, i),
                        decoder->reg[REG_ADDR(i)]);
        }
 
 
-       dprintk(1, KERN_DEBUG "%s_attach: setting video input\n",
-               I2C_NAME(client));
+       v4l_dbg(1, debug, client, "setting video input\n");
 
        err[19] =
            saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]);
@@ -1080,20 +995,15 @@ saa7114_detect_client (struct i2c_adapter *adapter,
 
        for (i = 19; i <= 21; i++) {
                if (err[i] < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s_attach: init error %d at stage %d, leaving attach.\n",
-                               I2C_NAME(client), i, err[i]);
+                       v4l_dbg(1, debug, client,
+                               "init error %d at stage %d, leaving attach.\n",
+                               i, err[i]);
                        kfree(decoder);
-                       kfree(client);
-                       return 0;
+                       return -EIO;
                }
        }
 
-       dprintk(1,
-               KERN_DEBUG
-               "%s_attach: performing decoder reset sequence\n",
-               I2C_NAME(client));
+       v4l_dbg(1, debug, client, "performing decoder reset sequence\n");
 
        err[22] = saa7114_write(client, 0x88, 0xd8);    // sw reset scaler
        err[23] = saa7114_write(client, 0x88, 0xf8);    // sw reset scaler release
@@ -1102,13 +1012,11 @@ saa7114_detect_client (struct i2c_adapter *adapter,
 
        for (i = 22; i <= 24; i++) {
                if (err[i] < 0) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s_attach: init error %d at stage %d, leaving attach.\n",
-                               I2C_NAME(client), i, err[i]);
+                       v4l_dbg(1, debug, client,
+                               "init error %d at stage %d, leaving attach.\n",
+                               i, err[i]);
                        kfree(decoder);
-                       kfree(client);
-                       return 0;
+                       return -EIO;
                }
        }
 
@@ -1116,101 +1024,45 @@ saa7114_detect_client (struct i2c_adapter *adapter,
        err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]);
        err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]);
 
-       dprintk(1,
-               KERN_INFO
-               "%s_attach: chip version %x, decoder status 0x%02x\n",
-               I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
+       v4l_dbg(1, debug, client, "chip version %x, decoder status 0x%02x\n",
+               saa7114_read(client, 0x00) >> 4,
                saa7114_read(client, 0x1f));
-       dprintk(1,
-               KERN_DEBUG
-               "%s_attach: power save control: 0x%02x, scaler status: 0x%02x\n",
-               I2C_NAME(client), saa7114_read(client, 0x88),
+       v4l_dbg(1, debug, client,
+               "power save control: 0x%02x, scaler status: 0x%02x\n",
+               saa7114_read(client, 0x88),
                saa7114_read(client, 0x8f));
 
 
        for (i = 0x94; i < 0x96; i++) {
-               dprintk(1,
-                       KERN_DEBUG
-                       "%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
-                       I2C_NAME(client), i, saa7114_read(client, i),
+               v4l_dbg(1, debug, client,
+                       "reg[0x%02x] = 0x%02x (0x%02x)\n",
+                       i, saa7114_read(client, i),
                        decoder->reg[REG_ADDR(i)]);
        }
 
-       i = i2c_attach_client(client);
-       if (i) {
-               kfree(client);
-               kfree(decoder);
-               return i;
-       }
-
        //i = saa7114_write_block(client, init, sizeof(init));
-       i = 0;
-       if (i < 0) {
-               dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
-                       I2C_NAME(client), i);
-       } else {
-               dprintk(1,
-                       KERN_INFO
-                       "%s_attach: chip version %x at address 0x%x\n",
-                       I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
-                       client->addr << 1);
-       }
-
        return 0;
 }
 
-static int
-saa7114_attach_adapter (struct i2c_adapter *adapter)
-{
-       dprintk(1,
-               KERN_INFO
-               "saa7114.c: starting probe for adapter %s (0x%x)\n",
-               I2C_NAME(adapter), adapter->id);
-       return i2c_probe(adapter, &addr_data, &saa7114_detect_client);
-}
-
-static int
-saa7114_detach_client (struct i2c_client *client)
+static int saa7114_remove(struct i2c_client *client)
 {
-       struct saa7114 *decoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(decoder);
-       kfree(client);
-
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7114 = {
-       .driver = {
-               .name = "saa7114",
-       },
-
-       .id = I2C_DRIVERID_SAA7114,
+static const struct i2c_device_id saa7114_id[] = {
+       { "saa7114_old", 0 },   /* "saa7114" maps to the saa7115 driver */
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7114_id);
 
-       .attach_adapter = saa7114_attach_adapter,
-       .detach_client = saa7114_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa7114",
+       .driverid = I2C_DRIVERID_SAA7114,
        .command = saa7114_command,
+       .probe = saa7114_probe,
+       .remove = saa7114_remove,
+       .id_table = saa7114_id,
 };
-
-static int __init
-saa7114_init (void)
-{
-       return i2c_add_driver(&i2c_driver_saa7114);
-}
-
-static void __exit
-saa7114_exit (void)
-{
-       i2c_del_driver(&i2c_driver_saa7114);
-}
-
-module_init(saa7114_init);
-module_exit(saa7114_exit);
index d0e83fe0ff5104024da62f8e948f65eae064c936..cc02fb18efa75bcc9662cedb194bfe378fe247b9 100644 (file)
@@ -29,7 +29,7 @@
  * Note: the saa7126 is identical to the saa7127, and the saa7128 is
  * identical to the saa7129, except that the saa7126 and saa7128 have
  * macrovision anti-taping support. This driver will almost certainly
- * work find for those chips, except of course for the missing anti-taping
+ * work fine for those chips, except of course for the missing anti-taping
  * support.
  *
  * This program is free software; you can redistribute it and/or modify
index 87c10983266f3392f3f4fa173e6046bd60e77e71..8c46115d4c7980a34f672ec75a4179848a11d3d7 100644 (file)
@@ -535,11 +535,16 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
                                struct tda1004x_config *cdec_conf,
                                struct tda827x_config *tuner_conf)
 {
-       dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
-       if (dev->dvb.frontend) {
+       struct videobuf_dvb_frontend *fe0;
+
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+
+       fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
+       if (fe0->dvb.frontend) {
                if (cdec_conf->i2c_gate)
-                       dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-               if (dvb_attach(tda827x_attach, dev->dvb.frontend,
+                       fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+               if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
                               cdec_conf->tuner_address,
                               &dev->i2c_adap, tuner_conf))
                        return 0;
@@ -944,12 +949,30 @@ static int dvb_init(struct saa7134_dev *dev)
 {
        int ret;
        int attach_xc3028 = 0;
+       struct videobuf_dvb_frontend *fe0;
+
+       /* FIXME: add support for multi-frontend */
+       mutex_init(&dev->frontends.lock);
+       INIT_LIST_HEAD(&dev->frontends.felist);
+       dev->frontends.active_fe_id = 0;
+
+       printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
+
+       if (videobuf_dvb_alloc_frontend(&dev->frontends, 1) == NULL) {
+               printk(KERN_ERR "%s() failed to alloc\n", __func__);
+               return -ENOMEM;
+       }
+
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+       if (!fe0)
+               return -EINVAL;
 
        /* init struct videobuf_dvb */
        dev->ts.nr_bufs    = 32;
        dev->ts.nr_packets = 32*4;
-       dev->dvb.name = dev->name;
-       videobuf_queue_sg_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+       fe0->dvb.name = dev->name;
+       videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
                            &dev->pci->dev, &dev->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
                            V4L2_FIELD_ALTERNATE,
@@ -959,47 +982,47 @@ static int dvb_init(struct saa7134_dev *dev)
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
                dprintk("pinnacle 300i dvb setup\n");
-               dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
+               fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+               if (fe0->dvb.frontend) {
+                       fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
                }
                break;
        case SAA7134_BOARD_AVERMEDIA_777:
        case SAA7134_BOARD_AVERMEDIA_A16AR:
                dprintk("avertv 777 dvb setup\n");
-               dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
+               fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend) {
+                       dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &dev->i2c_adap, 0x61,
                                   TUNER_PHILIPS_TD1316);
                }
                break;
        case SAA7134_BOARD_AVERMEDIA_A16D:
                dprintk("AverMedia A16D dvb setup\n");
-               dev->dvb.frontend = dvb_attach(mt352_attach,
+               fe0->dvb.frontend = dvb_attach(mt352_attach,
                                                &avermedia_xc3028_mt352_dev,
                                                &dev->i2c_adap);
                attach_xc3028 = 1;
                break;
        case SAA7134_BOARD_MD7134:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                               &medion_cardbus,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend) {
+                       dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &dev->i2c_adap, medion_cardbus.tuner_address,
                                   TUNER_PHILIPS_FMD1216ME_MK3);
                }
                break;
        case SAA7134_BOARD_PHILIPS_TOUGH:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                               &philips_tu1216_60_config,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+               if (fe0->dvb.frontend) {
+                       fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+                       fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
                }
                break;
        case SAA7134_BOARD_FLYDVBTDUO:
@@ -1010,24 +1033,24 @@ static int dvb_init(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_PHILIPS_EUROPA:
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                               &philips_europa_config,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
-                       dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
-                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+               if (fe0->dvb.frontend) {
+                       dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+                       fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+                       fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+                       fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+                       fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
                }
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                               &philips_tu1216_61_config,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+               if (fe0->dvb.frontend) {
+                       fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+                       fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
                }
                break;
        case SAA7134_BOARD_KWORLD_DVBT_210:
@@ -1066,14 +1089,14 @@ static int dvb_init(struct saa7134_dev *dev)
                                                 &tda827x_cfg_0) < 0)
                                goto dettach_frontend;
                } else {                /* satellite */
-                       dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
-                       if (dev->dvb.frontend) {
-                               if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
+                       fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+                       if (fe0->dvb.frontend) {
+                               if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
                                                                        &dev->i2c_adap, 0) == NULL) {
                                        wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
                                        goto dettach_frontend;
                                }
-                               if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
+                               if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
                                                                                0x08, 0, 0) == NULL) {
                                        wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
                                        goto dettach_frontend;
@@ -1083,11 +1106,11 @@ static int dvb_init(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
        case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                               &ads_tech_duo_config,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       if (dvb_attach(tda827x_attach,dev->dvb.frontend,
+               if (fe0->dvb.frontend) {
+                       if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
                                   ads_tech_duo_config.tuner_address, &dev->i2c_adap,
                                                                &ads_duo_cfg) == NULL) {
                                wprintk("no tda827x tuner found at addr: %02x\n",
@@ -1108,15 +1131,15 @@ static int dvb_init(struct saa7134_dev *dev)
                                                 &tda827x_cfg_0) < 0)
                                goto dettach_frontend;
                } else {        /* satellite */
-                       dev->dvb.frontend = dvb_attach(tda10086_attach,
+                       fe0->dvb.frontend = dvb_attach(tda10086_attach,
                                                        &flydvbs, &dev->i2c_adap);
-                       if (dev->dvb.frontend) {
-                               struct dvb_frontend *fe = dev->dvb.frontend;
+                       if (fe0->dvb.frontend) {
+                               struct dvb_frontend *fe = fe0->dvb.frontend;
                                u8 dev_id = dev->eedata[2];
                                u8 data = 0xc4;
                                struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
 
-                               if (dvb_attach(tda826x_attach, dev->dvb.frontend,
+                               if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
                                                0x60, &dev->i2c_adap, 0) == NULL) {
                                        wprintk("%s: Medion Quadro, no tda826x "
                                                "found !\n", __func__);
@@ -1150,31 +1173,31 @@ static int dvb_init(struct saa7134_dev *dev)
                }
                break;
        case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
-               dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
+               fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend)
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+               if (fe0->dvb.frontend)
+                       dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
                                   NULL, DVB_PLL_TDHU2);
                break;
        case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
        case SAA7134_BOARD_KWORLD_ATSC110:
-               dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
+               fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend)
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+               if (fe0->dvb.frontend)
+                       dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &dev->i2c_adap, 0x61,
                                   TUNER_PHILIPS_TUV1236D);
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
-               dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+               fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+               if (fe0->dvb.frontend) {
+                       if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
                                       &dev->i2c_adap, 0) == NULL) {
                                wprintk("%s: No tda826x found!\n", __func__);
                                goto dettach_frontend;
                        }
-                       if (dvb_attach(isl6421_attach, dev->dvb.frontend,
+                       if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
                                       &dev->i2c_adap, 0x08, 0, 0) == NULL) {
                                wprintk("%s: No ISL6421 found!\n", __func__);
                                goto dettach_frontend;
@@ -1182,25 +1205,25 @@ static int dvb_init(struct saa7134_dev *dev)
                }
                break;
        case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                               &medion_cardbus,
                                               &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
-                       dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+               if (fe0->dvb.frontend) {
+                       dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+                       fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
 
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                       dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &dev->i2c_adap, medion_cardbus.tuner_address,
                                   TUNER_PHILIPS_FMD1216ME_MK3);
                }
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                &philips_europa_config,
                                &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+               if (fe0->dvb.frontend) {
+                       fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
+                       fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
                }
                break;
        case SAA7134_BOARD_CINERGY_HT_PCMCIA:
@@ -1239,15 +1262,15 @@ static int dvb_init(struct saa7134_dev *dev)
                        goto dettach_frontend;
                break;
        case SAA7134_BOARD_PHILIPS_SNAKE:
-               dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+               fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
                                                &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+               if (fe0->dvb.frontend) {
+                       if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
                                        &dev->i2c_adap, 0) == NULL) {
                                wprintk("%s: No tda826x found!\n", __func__);
                                goto dettach_frontend;
                        }
-                       if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+                       if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
                                        &dev->i2c_adap, 0, 0) == NULL) {
                                wprintk("%s: No lnbp21 found!\n", __func__);
                                goto dettach_frontend;
@@ -1269,24 +1292,24 @@ static int dvb_init(struct saa7134_dev *dev)
                saa7134_set_gpio(dev, 25, 0);
                msleep(10);
                saa7134_set_gpio(dev, 25, 1);
-               dev->dvb.frontend = dvb_attach(mt352_attach,
+               fe0->dvb.frontend = dvb_attach(mt352_attach,
                                                &avermedia_xc3028_mt352_dev,
                                                &dev->i2c_adap);
                attach_xc3028 = 1;
                break;
        case SAA7134_BOARD_MD7134_BRIDGE_2:
-               dev->dvb.frontend = dvb_attach(tda10086_attach,
+               fe0->dvb.frontend = dvb_attach(tda10086_attach,
                                                &sd1878_4m, &dev->i2c_adap);
-               if (dev->dvb.frontend) {
+               if (fe0->dvb.frontend) {
                        struct dvb_frontend *fe;
-                       if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+                       if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
                                  &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
                                wprintk("%s: MD7134 DVB-S, no SD1878 "
                                        "found !\n", __func__);
                                goto dettach_frontend;
                        }
                        /* we need to open the i2c gate (we know it exists) */
-                       fe = dev->dvb.frontend;
+                       fe = fe0->dvb.frontend;
                        fe->ops.i2c_gate_ctrl(fe, 1);
                        if (dvb_attach(isl6405_attach, fe,
                                        &dev->i2c_adap, 0x08, 0, 0) == NULL) {
@@ -1305,7 +1328,7 @@ static int dvb_init(struct saa7134_dev *dev)
                saa7134_set_gpio(dev, 25, 0);
                msleep(10);
                saa7134_set_gpio(dev, 25, 1);
-               dev->dvb.frontend = dvb_attach(mt352_attach,
+               fe0->dvb.frontend = dvb_attach(mt352_attach,
                                                &avermedia_xc3028_mt352_dev,
                                                &dev->i2c_adap);
                attach_xc3028 = 1;
@@ -1316,17 +1339,17 @@ static int dvb_init(struct saa7134_dev *dev)
                                                        &tda827x_cfg_2) < 0)
                                goto dettach_frontend;
                } else {                /* satellite */
-                       dev->dvb.frontend = dvb_attach(tda10086_attach,
+                       fe0->dvb.frontend = dvb_attach(tda10086_attach,
                                                &flydvbs, &dev->i2c_adap);
-                       if (dev->dvb.frontend) {
+                       if (fe0->dvb.frontend) {
                                if (dvb_attach(tda826x_attach,
-                                               dev->dvb.frontend, 0x60,
+                                               fe0->dvb.frontend, 0x60,
                                                &dev->i2c_adap, 0) == NULL) {
                                        wprintk("%s: Asus Tiger 3in1, no "
                                                "tda826x found!\n", __func__);
                                        goto dettach_frontend;
                                }
-                               if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+                               if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
                                                &dev->i2c_adap, 0, 0) == NULL) {
                                        wprintk("%s: Asus Tiger 3in1, no lnbp21"
                                                " found!\n", __func__);
@@ -1352,10 +1375,10 @@ static int dvb_init(struct saa7134_dev *dev)
                        .i2c_addr  = 0x61,
                };
 
-               if (!dev->dvb.frontend)
+               if (!fe0->dvb.frontend)
                        return -1;
 
-               fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+               fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
                if (!fe) {
                        printk(KERN_ERR "%s/2: xc3028 attach failed\n",
                               dev->name);
@@ -1363,40 +1386,47 @@ static int dvb_init(struct saa7134_dev *dev)
                }
        }
 
-       if (NULL == dev->dvb.frontend) {
+       if (NULL == fe0->dvb.frontend) {
                printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
                return -1;
        }
        /* define general-purpose callback pointer */
-       dev->dvb.frontend->callback = saa7134_tuner_callback;
+       fe0->dvb.frontend->callback = saa7134_tuner_callback;
 
        /* register everything else */
-       ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
-                                   adapter_nr);
+       ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+               &dev->pci->dev, adapter_nr, 0);
 
        /* this sequence is necessary to make the tda1004x load its firmware
         * and to enter analog mode of hybrid boards
         */
        if (!ret) {
-               if (dev->dvb.frontend->ops.init)
-                       dev->dvb.frontend->ops.init(dev->dvb.frontend);
-               if (dev->dvb.frontend->ops.sleep)
-                       dev->dvb.frontend->ops.sleep(dev->dvb.frontend);
-               if (dev->dvb.frontend->ops.tuner_ops.sleep)
-                       dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
+               if (fe0->dvb.frontend->ops.init)
+                       fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
+               if (fe0->dvb.frontend->ops.sleep)
+                       fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
+               if (fe0->dvb.frontend->ops.tuner_ops.sleep)
+                       fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
        }
        return ret;
 
 dettach_frontend:
-       if (dev->dvb.frontend)
-               dvb_frontend_detach(dev->dvb.frontend);
-       dev->dvb.frontend = NULL;
+       if (fe0->dvb.frontend)
+               dvb_frontend_detach(fe0->dvb.frontend);
+       fe0->dvb.frontend = NULL;
 
        return -1;
 }
 
 static int dvb_fini(struct saa7134_dev *dev)
 {
+       struct videobuf_dvb_frontend *fe0;
+
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+       if (!fe0)
+               return -EINVAL;
+
        /* FIXME: I suspect that this code is bogus, since the entry for
           Pinnacle 300I DVB-T PAL already defines the proper init to allow
           the detection of mt2032 (TDA9887_PORT2_INACTIVE)
@@ -1416,7 +1446,7 @@ static int dvb_fini(struct saa7134_dev *dev)
                        u8 data = 0x80;
                        struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
                        struct dvb_frontend *fe;
-                       fe = dev->dvb.frontend;
+                       fe = fe0->dvb.frontend;
                        if (fe->ops.i2c_gate_ctrl) {
                                fe->ops.i2c_gate_ctrl(fe, 1);
                                i2c_transfer(&dev->i2c_adap, &msg, 1);
@@ -1424,8 +1454,8 @@ static int dvb_fini(struct saa7134_dev *dev)
                        }
                }
        }
-       if (dev->dvb.frontend)
-               videobuf_dvb_unregister(&dev->dvb);
+       if (fe0->dvb.frontend)
+               videobuf_dvb_unregister_bus(&dev->frontends);
        return 0;
 }
 
index 491ab1f8fdd3cbadba1a3421e8dfc2cd30bb6340..24096d6e1ef8071037148334ce2948b736b09d54 100644 (file)
@@ -581,7 +581,7 @@ struct saa7134_dev {
 
 #if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
        /* SAA7134_MPEG_DVB only */
-       struct videobuf_dvb        dvb;
+       struct videobuf_dvb_frontends frontends;
        int (*original_demod_sleep)(struct dvb_frontend *fe);
        int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
        int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
index 02fda4eecea3269080eb14c5cd36d20d22df5803..6debb65152ee1f88a3f455c731903d3dc0fe217b 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
 #include <linux/types.h>
-#include <linux/i2c.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
+#include <linux/ioctl.h>
 #include <asm/uaccess.h>
-
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <linux/video_encoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
 
-#define I2C_NAME(s) (s)->name
-
-
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* ----------------------------------------------------------------------- */
 
 struct saa7185 {
@@ -75,32 +57,24 @@ struct saa7185 {
        int sat;
 };
 
-#define   I2C_SAA7185        0x88
-
 /* ----------------------------------------------------------------------- */
 
-static inline int
-saa7185_read (struct i2c_client *client)
+static inline int saa7185_read(struct i2c_client *client)
 {
        return i2c_smbus_read_byte(client);
 }
 
-static int
-saa7185_write (struct i2c_client *client,
-              u8                 reg,
-              u8                 value)
+static int saa7185_write(struct i2c_client *client, u8 reg, u8 value)
 {
        struct saa7185 *encoder = i2c_get_clientdata(client);
 
-       dprintk(1, KERN_DEBUG "SAA7185: %02x set to %02x\n", reg, value);
+       v4l_dbg(1, debug, client, "%02x set to %02x\n", reg, value);
        encoder->reg[reg] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static int
-saa7185_write_block (struct i2c_client *client,
-                    const u8          *data,
-                    unsigned int       len)
+static int saa7185_write_block(struct i2c_client *client,
+               const u8 *data, unsigned int len)
 {
        int ret = -1;
        u8 reg;
@@ -121,18 +95,17 @@ saa7185_write_block (struct i2c_client *client,
                                    encoder->reg[reg++] = data[1];
                                len -= 2;
                                data += 2;
-                       } while (len >= 2 && data[0] == reg &&
-                                block_len < 32);
-                       if ((ret = i2c_master_send(client, block_data,
-                                                  block_len)) < 0)
+                       } while (len >= 2 && data[0] == reg && block_len < 32);
+                       ret = i2c_master_send(client, block_data, block_len);
+                       if (ret < 0)
                                break;
                }
        } else {
                /* do some slow I2C emulation kind of thing */
                while (len >= 2) {
                        reg = *data++;
-                       if ((ret = saa7185_write(client, reg,
-                                                *data++)) < 0)
+                       ret = saa7185_write(client, reg, *data++);
+                       if (ret < 0)
                                break;
                        len -= 2;
                }
@@ -240,15 +213,11 @@ static const unsigned char init_ntsc[] = {
        0x66, 0x21,             /* FSC3 */
 };
 
-static int
-saa7185_command (struct i2c_client *client,
-                unsigned int       cmd,
-                void              *arg)
+static int saa7185_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct saa7185 *encoder = i2c_get_clientdata(client);
 
        switch (cmd) {
-
        case 0:
                saa7185_write_block(client, init_common,
                                    sizeof(init_common));
@@ -264,7 +233,6 @@ saa7185_command (struct i2c_client *client,
                                            sizeof(init_pal));
                        break;
                }
-
                break;
 
        case ENCODER_GET_CAPABILITIES:
@@ -276,8 +244,8 @@ saa7185_command (struct i2c_client *client,
                    VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
                cap->inputs = 1;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case ENCODER_SET_NORM:
        {
@@ -286,7 +254,6 @@ saa7185_command (struct i2c_client *client,
                //saa7185_write_block(client, init_common, sizeof(init_common));
 
                switch (*iarg) {
-
                case VIDEO_MODE_NTSC:
                        saa7185_write_block(client, init_ntsc,
                                            sizeof(init_ntsc));
@@ -300,11 +267,10 @@ saa7185_command (struct i2c_client *client,
                case VIDEO_MODE_SECAM:
                default:
                        return -EINVAL;
-
                }
                encoder->norm = *iarg;
-       }
                break;
+       }
 
        case ENCODER_SET_INPUT:
        {
@@ -314,7 +280,6 @@ saa7185_command (struct i2c_client *client,
                 *iarg = 1: input is from ZR36060 */
 
                switch (*iarg) {
-
                case 0:
                        /* Switch RTCE to 1 */
                        saa7185_write(client, 0x61,
@@ -332,21 +297,19 @@ saa7185_command (struct i2c_client *client,
 
                default:
                        return -EINVAL;
-
                }
-       }
                break;
+       }
 
        case ENCODER_SET_OUTPUT:
        {
                int *iarg = arg;
 
                /* not much choice of outputs */
-               if (*iarg != 0) {
+               if (*iarg != 0)
                        return -EINVAL;
-               }
-       }
                break;
+       }
 
        case ENCODER_ENABLE_OUTPUT:
        {
@@ -356,8 +319,8 @@ saa7185_command (struct i2c_client *client,
                saa7185_write(client, 0x61,
                              (encoder->reg[0x61] & 0xbf) |
                              (encoder->enable ? 0x00 : 0x40));
-       }
                break;
+       }
 
        default:
                return -EINVAL;
@@ -368,138 +331,65 @@ saa7185_command (struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
-static unsigned short ignore = I2C_CLIENT_END;
+I2C_CLIENT_INSMOD;
 
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
-
-static struct i2c_driver i2c_driver_saa7185;
-
-static int
-saa7185_detect_client (struct i2c_adapter *adapter,
-                      int                 address,
-                      int                 kind)
+static int saa7185_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        int i;
-       struct i2c_client *client;
        struct saa7185 *encoder;
 
-       dprintk(1,
-               KERN_INFO
-               "saa7185.c: detecting saa7185 client on address 0x%x\n",
-               address << 1);
-
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &i2c_driver_saa7185;
-       strlcpy(I2C_NAME(client), "saa7185", sizeof(I2C_NAME(client)));
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
-       if (encoder == NULL) {
-               kfree(client);
+       if (encoder == NULL)
                return -ENOMEM;
-       }
        encoder->norm = VIDEO_MODE_NTSC;
        encoder->enable = 1;
        i2c_set_clientdata(client, encoder);
 
-       i = i2c_attach_client(client);
-       if (i) {
-               kfree(client);
-               kfree(encoder);
-               return i;
-       }
-
        i = saa7185_write_block(client, init_common, sizeof(init_common));
-       if (i >= 0) {
-               i = saa7185_write_block(client, init_ntsc,
-                                       sizeof(init_ntsc));
-       }
-       if (i < 0) {
-               dprintk(1, KERN_ERR "%s_attach: init error %d\n",
-                       I2C_NAME(client), i);
-       } else {
-               dprintk(1,
-                       KERN_INFO
-                       "%s_attach: chip version %d at address 0x%x\n",
-                       I2C_NAME(client), saa7185_read(client) >> 5,
-                       client->addr << 1);
-       }
-
+       if (i >= 0)
+               i = saa7185_write_block(client, init_ntsc, sizeof(init_ntsc));
+       if (i < 0)
+               v4l_dbg(1, debug, client, "init error %d\n", i);
+       else
+               v4l_dbg(1, debug, client, "revision 0x%x\n",
+                               saa7185_read(client) >> 5);
        return 0;
 }
 
-static int
-saa7185_attach_adapter (struct i2c_adapter *adapter)
-{
-       dprintk(1,
-               KERN_INFO
-               "saa7185.c: starting probe for adapter %s (0x%x)\n",
-               I2C_NAME(adapter), adapter->id);
-       return i2c_probe(adapter, &addr_data, &saa7185_detect_client);
-}
-
-static int
-saa7185_detach_client (struct i2c_client *client)
+static int saa7185_remove(struct i2c_client *client)
 {
        struct saa7185 *encoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
 
        saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40);       /* SW: output off is active */
        //saa7185_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
 
        kfree(encoder);
-       kfree(client);
-
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7185 = {
-       .driver = {
-               .name = "saa7185",      /* name */
-       },
-
-       .id = I2C_DRIVERID_SAA7185B,
+static const struct i2c_device_id saa7185_id[] = {
+       { "saa7185", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7185_id);
 
-       .attach_adapter = saa7185_attach_adapter,
-       .detach_client = saa7185_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa7185",
+       .driverid = I2C_DRIVERID_SAA7185B,
        .command = saa7185_command,
+       .probe = saa7185_probe,
+       .remove = saa7185_remove,
+       .id_table = saa7185_id,
 };
-
-static int __init
-saa7185_init (void)
-{
-       return i2c_add_driver(&i2c_driver_saa7185);
-}
-
-static void __exit
-saa7185_exit (void)
-{
-       i2c_del_driver(&i2c_driver_saa7185);
-}
-
-module_init(saa7185_init);
-module_exit(saa7185_exit);
index 76838091dc66ce05140b63912ec106422e2bc542..2407607f2eff1ce0c28a26262d5ffbb08439d000 100644 (file)
 
 /* register offsets for sh7722 / sh7723 */
 
-#define CAPSR  0x00
-#define CAPCR  0x04
-#define CAMCR  0x08
-#define CMCYR  0x0c
-#define CAMOR  0x10
-#define CAPWR  0x14
-#define CAIFR  0x18
-#define CSTCR  0x20 /* not on sh7723 */
-#define CSECR  0x24 /* not on sh7723 */
-#define CRCNTR 0x28
-#define CRCMPR 0x2c
-#define CFLCR  0x30
-#define CFSZR  0x34
-#define CDWDR  0x38
-#define CDAYR  0x3c
-#define CDACR  0x40
-#define CDBYR  0x44
-#define CDBCR  0x48
-#define CBDSR  0x4c
-#define CFWCR  0x5c
-#define CLFCR  0x60
-#define CDOCR  0x64
-#define CDDCR  0x68
-#define CDDAR  0x6c
-#define CEIER  0x70
-#define CETCR  0x74
-#define CSTSR  0x7c
-#define CSRTR  0x80
-#define CDSSR  0x84
-#define CDAYR2 0x90
-#define CDACR2 0x94
-#define CDBYR2 0x98
-#define CDBCR2 0x9c
+#define CAPSR  0x00 /* Capture start register */
+#define CAPCR  0x04 /* Capture control register */
+#define CAMCR  0x08 /* Capture interface control register */
+#define CMCYR  0x0c /* Capture interface cycle  register */
+#define CAMOR  0x10 /* Capture interface offset register */
+#define CAPWR  0x14 /* Capture interface width register */
+#define CAIFR  0x18 /* Capture interface input format register */
+#define CSTCR  0x20 /* Camera strobe control register (<= sh7722) */
+#define CSECR  0x24 /* Camera strobe emission count register (<= sh7722) */
+#define CRCNTR 0x28 /* CEU register control register */
+#define CRCMPR 0x2c /* CEU register forcible control register */
+#define CFLCR  0x30 /* Capture filter control register */
+#define CFSZR  0x34 /* Capture filter size clip register */
+#define CDWDR  0x38 /* Capture destination width register */
+#define CDAYR  0x3c /* Capture data address Y register */
+#define CDACR  0x40 /* Capture data address C register */
+#define CDBYR  0x44 /* Capture data bottom-field address Y register */
+#define CDBCR  0x48 /* Capture data bottom-field address C register */
+#define CBDSR  0x4c /* Capture bundle destination size register */
+#define CFWCR  0x5c /* Firewall operation control register */
+#define CLFCR  0x60 /* Capture low-pass filter control register */
+#define CDOCR  0x64 /* Capture data output control register */
+#define CDDCR  0x68 /* Capture data complexity level register */
+#define CDDAR  0x6c /* Capture data complexity level address register */
+#define CEIER  0x70 /* Capture event interrupt enable register */
+#define CETCR  0x74 /* Capture event flag clear register */
+#define CSTSR  0x7c /* Capture status register */
+#define CSRTR  0x80 /* Capture software reset register */
+#define CDSSR  0x84 /* Capture data size register */
+#define CDAYR2 0x90 /* Capture data address Y register 2 */
+#define CDACR2 0x94 /* Capture data address C register 2 */
+#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
+#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
 
 static DEFINE_MUTEX(camera_lock);
 
@@ -165,6 +165,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
        ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10);
 
        if (pcdev->active) {
+               pcdev->active->state = VIDEOBUF_ACTIVE;
                ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active));
                ceu_write(pcdev, CAPSR, 0x1); /* start capture */
        }
@@ -236,7 +237,7 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
        dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
                vb, vb->baddr, vb->bsize);
 
-       vb->state = VIDEOBUF_ACTIVE;
+       vb->state = VIDEOBUF_QUEUED;
        spin_lock_irqsave(&pcdev->lock, flags);
        list_add_tail(&vb->queue, &pcdev->capture);
 
@@ -323,12 +324,24 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       unsigned long flags;
 
        BUG_ON(icd != pcdev->icd);
 
        /* disable capture, disable interrupts */
        ceu_write(pcdev, CEIER, 0);
        ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+
+       /* make sure active buffer is canceled */
+       spin_lock_irqsave(&pcdev->lock, flags);
+       if (pcdev->active) {
+               list_del(&pcdev->active->queue);
+               pcdev->active->state = VIDEOBUF_ERROR;
+               wake_up_all(&pcdev->active->done);
+               pcdev->active = NULL;
+       }
+       spin_unlock_irqrestore(&pcdev->lock, flags);
+
        icd->ops->release(icd);
 
        dev_info(&icd->dev,
@@ -391,7 +404,20 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */
        ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width);
        ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */
-       ceu_write(pcdev, CDOCR, 0x00000016);
+
+       /* A few words about byte order (observed in Big Endian mode)
+        *
+        * In data fetch mode bytes are received in chunks of 8 bytes.
+        * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first)
+        *
+        * The data is however by default written to memory in reverse order:
+        * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte)
+        *
+        * The lowest three bits of CDOCR allows us to do swapping,
+        * using 7 we swap the data bytes to match the incoming order:
+        * D0, D1, D2, D3, D4, D5, D6, D7
+        */
+       ceu_write(pcdev, CDOCR, 0x00000017);
 
        ceu_write(pcdev, CDWDR, cdwdr_width);
        ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
index 1adc257ebdb97f00140d162dbdc51aacea04f7df..bb7a9d480e8f3ff94058f7521da413463da661d9 100644 (file)
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/soc_camera.h>
-
-struct soc_camera_platform_info {
-       int iface;
-       char *format_name;
-       unsigned long format_depth;
-       struct v4l2_pix_format format;
-       unsigned long bus_param;
-       int (*set_capture)(struct soc_camera_platform_info *info, int enable);
-};
+#include <media/soc_camera_platform.h>
 
 struct soc_camera_platform_priv {
        struct soc_camera_platform_info *info;
@@ -44,11 +36,21 @@ soc_camera_platform_get_info(struct soc_camera_device *icd)
 
 static int soc_camera_platform_init(struct soc_camera_device *icd)
 {
+       struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+
+       if (p->power)
+               p->power(1);
+
        return 0;
 }
 
 static int soc_camera_platform_release(struct soc_camera_device *icd)
 {
+       struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+
+       if (p->power)
+               p->power(0);
+
        return 0;
 }
 
index db69bc5556d6776c84a51c78f7460f927d04d350..edaea4964513ef3027a3673034877ee886d5743d 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/kref.h>
 
 #include <linux/usb.h>
 #include <linux/mm.h>
@@ -560,7 +559,7 @@ static void stk_clean_iso(struct stk_camera *dev)
 
                urb = dev->isobufs[i].urb;
                if (urb) {
-                       if (atomic_read(&dev->urbs_used))
+                       if (atomic_read(&dev->urbs_used) && is_present(dev))
                                usb_kill_urb(urb);
                        usb_free_urb(urb);
                }
@@ -689,18 +688,14 @@ static int v4l_stk_release(struct inode *inode, struct file *fp)
 {
        struct stk_camera *dev = fp->private_data;
 
-       if (dev->owner != fp) {
-               usb_autopm_put_interface(dev->interface);
-               return 0;
+       if (dev->owner == fp) {
+               stk_stop_stream(dev);
+               stk_free_buffers(dev);
+               dev->owner = NULL;
        }
 
-       stk_stop_stream(dev);
-
-       stk_free_buffers(dev);
-
-       dev->owner = NULL;
-
-       usb_autopm_put_interface(dev->interface);
+       if(is_present(dev))
+               usb_autopm_put_interface(dev->interface);
 
        return 0;
 }
@@ -714,9 +709,6 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
        struct stk_sio_buffer *sbuf;
        struct stk_camera *dev = fp->private_data;
 
-       if (dev == NULL)
-               return -EIO;
-
        if (!is_present(dev))
                return -EIO;
        if (dev->owner && dev->owner != fp)
@@ -773,9 +765,6 @@ static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
 {
        struct stk_camera *dev = fp->private_data;
 
-       if (dev == NULL)
-               return -ENODEV;
-
        poll_wait(fp, &dev->wait_frame, wait);
 
        if (!is_present(dev))
@@ -1436,7 +1425,7 @@ static void stk_camera_disconnect(struct usb_interface *interface)
        wake_up_interruptible(&dev->wait_frame);
        stk_remove_sysfs_files(&dev->vdev);
 
-       STK_INFO("Syntek USB2.0 Camera release resources"
+       STK_INFO("Syntek USB2.0 Camera release resources "
                "video device /dev/video%d\n", dev->vdev.minor);
 
        video_unregister_device(&dev->vdev);
index 084a85bdd16e642a49d27175a68677cbd2d8bda2..9f6736637571db8b0f7625854431d594cf578edf 100644 (file)
@@ -122,7 +122,6 @@ struct stk_camera {
 
 #define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
 
-void stk_camera_delete(struct kref *);
 int stk_camera_write_reg(struct stk_camera *, u16, u8);
 int stk_camera_read_reg(struct stk_camera *, u16, int *);
 
index bcc32fa92a81c68840b503d90eb947a8fe1d83e7..3b0b84c2e451524b2465effa64754c5db3b7d4be 100644 (file)
@@ -242,7 +242,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "TCL M2523_3DBH_E"},
        { TUNER_ABSENT,                 "TCL M2523_3DIH_E"},
        { TUNER_ABSENT,                 "TCL MFPE05_2_U"},
-       { TUNER_PHILIPS_FMD1216ME_MK3,  "Philips FMD1216MEX"},
+       { TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"},
        { TUNER_ABSENT,                 "Philips FRH2036B"},
        { TUNER_ABSENT,                 "Panasonic ENGF75_01GF"},
        { TUNER_ABSENT,                 "MaxLinear MXL5005"},
index b56cffcbfd458152829b0973ade0f6646380aee8..917277d3660562b670399c3dc8eae25d72777b89 100644 (file)
@@ -126,7 +126,6 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
        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;
        }
@@ -134,30 +133,38 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
        return err;
 }
 
-/* ------------------------------------------------------------------ */
-
-int videobuf_dvb_register(struct videobuf_dvb *dvb,
+static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
                          struct module *module,
                          void *adapter_priv,
                          struct device *device,
-                         short *adapter_nr)
+                         char *adapter_name,
+                         short *adapter_nr,
+                         int mfe_shared)
 {
        int result;
 
-       mutex_init(&dvb->lock);
+       mutex_init(&fe->lock);
 
        /* register adapter */
-       result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device,
-                                     adapter_nr);
+       result = dvb_register_adapter(&fe->adapter, adapter_name, module,
+               device, adapter_nr);
        if (result < 0) {
                printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
-                      dvb->name, result);
-               goto fail_adapter;
+                      adapter_name, result);
        }
-       dvb->adapter.priv = adapter_priv;
+       fe->adapter.priv = adapter_priv;
+       fe->adapter.mfe_shared = mfe_shared;
+
+       return result;
+}
+
+static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter,
+       struct videobuf_dvb *dvb)
+{
+       int result;
 
        /* register frontend */
-       result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+       result = dvb_register_frontend(adapter, dvb->frontend);
        if (result < 0) {
                printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
                       dvb->name, result);
@@ -183,7 +190,8 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
        dvb->dmxdev.filternum    = 256;
        dvb->dmxdev.demux        = &dvb->demux.dmx;
        dvb->dmxdev.capabilities = 0;
-       result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+       result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
+
        if (result < 0) {
                printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
                       dvb->name, result);
@@ -214,7 +222,11 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
        }
 
        /* register network adapter */
-       dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+       dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
+       if (dvb->net.dvbdev == NULL) {
+               result = -ENOMEM;
+               goto fail_fe_conn;
+       }
        return 0;
 
 fail_fe_conn:
@@ -229,30 +241,151 @@ fail_dmx:
        dvb_unregister_frontend(dvb->frontend);
 fail_frontend:
        dvb_frontend_detach(dvb->frontend);
-       dvb_unregister_adapter(&dvb->adapter);
-fail_adapter:
+       dvb->frontend = NULL;
+
        return result;
 }
 
-void videobuf_dvb_unregister(struct videobuf_dvb *dvb)
+/* ------------------------------------------------------------------ */
+/* Register a single adapter and one or more frontends */
+int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
+                         struct module *module,
+                         void *adapter_priv,
+                         struct device *device,
+                         short *adapter_nr,
+                         int mfe_shared)
 {
-       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);
+       struct list_head *list, *q;
+       struct videobuf_dvb_frontend *fe;
+       int res;
+
+       fe = videobuf_dvb_get_frontend(f, 1);
+       if (!fe) {
+               printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
+               return -EINVAL;
+       }
+
+       /* Bring up the adapter */
+       res = videobuf_dvb_register_adapter(f, module, adapter_priv, device,
+               fe->dvb.name, adapter_nr, mfe_shared);
+       if (res < 0) {
+               printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
+               return res;
+       }
+
+       /* Attach all of the frontends to the adapter */
+       mutex_lock(&f->lock);
+       list_for_each_safe(list, q, &f->felist) {
+               fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+               res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb);
+               if (res < 0) {
+                       printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n",
+                               fe->dvb.name, res);
+                       goto err;
+               }
+       }
+       mutex_unlock(&f->lock);
+       return 0;
+
+err:
+       mutex_unlock(&f->lock);
+       videobuf_dvb_unregister_bus(f);
+       return res;
 }
+EXPORT_SYMBOL(videobuf_dvb_register_bus);
 
-EXPORT_SYMBOL(videobuf_dvb_register);
-EXPORT_SYMBOL(videobuf_dvb_unregister);
+void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f)
+{
+       struct list_head *list, *q;
+       struct videobuf_dvb_frontend *fe;
+
+       mutex_lock(&f->lock);
+       list_for_each_safe(list, q, &f->felist) {
+               fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+               if (fe->dvb.net.dvbdev) {
+                       dvb_net_release(&fe->dvb.net);
+                       fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+                               &fe->dvb.fe_mem);
+                       fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+                               &fe->dvb.fe_hw);
+                       dvb_dmxdev_release(&fe->dvb.dmxdev);
+                       dvb_dmx_release(&fe->dvb.demux);
+                       dvb_unregister_frontend(fe->dvb.frontend);
+               }
+               if (fe->dvb.frontend)
+                       /* always allocated, may have been reset */
+                       dvb_frontend_detach(fe->dvb.frontend);
+               list_del(list);
+               kfree(fe);
+       }
+       mutex_unlock(&f->lock);
 
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * compile-command: "make DVB=1"
- * End:
- */
+       dvb_unregister_adapter(&f->adapter);
+}
+EXPORT_SYMBOL(videobuf_dvb_unregister_bus);
+
+struct videobuf_dvb_frontend *videobuf_dvb_get_frontend(
+       struct videobuf_dvb_frontends *f, int id)
+{
+       struct list_head *list, *q;
+       struct videobuf_dvb_frontend *fe, *ret = NULL;
+
+       mutex_lock(&f->lock);
+
+       list_for_each_safe(list, q, &f->felist) {
+               fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+               if (fe->id == id) {
+                       ret = fe;
+                       break;
+               }
+       }
+
+       mutex_unlock(&f->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(videobuf_dvb_get_frontend);
+
+int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f,
+       struct dvb_frontend *p)
+{
+       struct list_head *list, *q;
+       struct videobuf_dvb_frontend *fe = NULL;
+       int ret = 0;
+
+       mutex_lock(&f->lock);
+
+       list_for_each_safe(list, q, &f->felist) {
+               fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+               if (fe->dvb.frontend == p) {
+                       ret = fe->id;
+                       break;
+               }
+       }
+
+       mutex_unlock(&f->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(videobuf_dvb_find_frontend);
+
+struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend(
+       struct videobuf_dvb_frontends *f, int id)
+{
+       struct videobuf_dvb_frontend *fe;
+
+       fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL);
+       if (fe == NULL)
+               goto fail_alloc;
+
+       fe->id = id;
+       mutex_init(&fe->dvb.lock);
+
+       mutex_lock(&f->lock);
+       list_add_tail(&fe->felist, &f->felist);
+       mutex_unlock(&f->lock);
+
+fail_alloc:
+       return fe;
+}
+EXPORT_SYMBOL(videobuf_dvb_alloc_frontend);
index 65c8af18e767a7e889ac239517b23823e71c9993..7d7e51def461b10d11d0efd7968b3fa21b6abb3d 100644 (file)
@@ -128,12 +128,56 @@ struct vivi_fmt {
        int   depth;
 };
 
-static struct vivi_fmt format = {
-       .name     = "4:2:2, packed, YUYV",
-       .fourcc   = V4L2_PIX_FMT_YUYV,
-       .depth    = 16,
+static struct vivi_fmt formats[] = {
+       {
+               .name     = "4:2:2, packed, YUYV",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+       },
+       {
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB565 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB565 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB555 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+               .depth    = 16,
+       },
 };
 
+static struct vivi_fmt *get_format(struct v4l2_format *f)
+{
+       struct vivi_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < ARRAY_SIZE(formats); k++) {
+               fmt = &formats[k];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+
+       if (k == ARRAY_SIZE(formats))
+               return NULL;
+
+       return &formats[k];
+}
+
 struct sg_to_addr {
        int pos;
        struct scatterlist *sg;
@@ -190,6 +234,7 @@ struct vivi_fh {
        struct videobuf_queue      vb_vidq;
 
        enum v4l2_buf_type         type;
+       unsigned char              bars[8][3];
 };
 
 /* ------------------------------------------------------------------
@@ -234,42 +279,118 @@ static u8 bars[8][3] = {
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-static void gen_line(char *basep, int inipos, int wmax,
-               int hmax, int line, int count, char *timestr)
+static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
 {
-       int  w, i, j, y;
-       int pos = inipos;
-       char *p, *s;
-       u8   chr, r, g, b, color;
+       unsigned char r_y, g_u, b_v;
+       unsigned char *p;
+       int color;
 
-       /* We will just duplicate the second pixel at the packet */
-       wmax /= 2;
+       r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
+       g_u = fh->bars[colorpos][1]; /* G or precalculated U */
+       b_v = fh->bars[colorpos][2]; /* B or precalculated V */
 
-       /* Generate a standard color bar pattern */
-       for (w = 0; w < wmax; w++) {
-               int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
-               r = bars[colorpos][0];
-               g = bars[colorpos][1];
-               b = bars[colorpos][2];
-
-               for (color = 0; color < 4; color++) {
-                       p = basep + pos;
+       for (color = 0; color < 4; color++) {
+               p = buf + color;
 
+               switch (fh->fmt->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
                        switch (color) {
                        case 0:
                        case 2:
-                               *p = TO_Y(r, g, b);     /* Luma */
+                               *p = r_y;
                                break;
                        case 1:
-                               *p = TO_U(r, g, b);     /* Cb */
+                               *p = g_u;
                                break;
                        case 3:
-                               *p = TO_V(r, g, b);     /* Cr */
+                               *p = b_v;
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_UYVY:
+                       switch (color) {
+                       case 1:
+                       case 3:
+                               *p = r_y;
+                               break;
+                       case 0:
+                               *p = g_u;
+                               break;
+                       case 2:
+                               *p = b_v;
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (r_y << 3) | (g_u >> 3);
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB565X:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (r_y << 3) | (g_u >> 3);
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (g_u << 5) | b_v;
                                break;
                        }
-                       pos++;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (r_y << 2) | (g_u >> 3);
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB555X:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (r_y << 2) | (g_u >> 3);
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       }
+                       break;
                }
        }
+}
+
+static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
+               int hmax, int line, int count, char *timestr)
+{
+       int  w, i, j;
+       int pos = inipos;
+       char *s;
+       u8 chr;
+
+       /* We will just duplicate the second pixel at the packet */
+       wmax /= 2;
+
+       /* Generate a standard color bar pattern */
+       for (w = 0; w < wmax; w++) {
+               int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
+
+               gen_twopix(fh, basep + pos, colorpos);
+               pos += 4; /* only 16 bpp supported for now */
+       }
 
        /* Checks if it is possible to show timestamp */
        if (TSTAMP_MAX_Y >= hmax)
@@ -283,38 +404,12 @@ static void gen_line(char *basep, int inipos, int wmax,
                for (s = timestr; *s; s++) {
                        chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
                        for (i = 0; i < 7; i++) {
-                               if (chr & 1 << (7 - i)) {
-                                       /* Font color*/
-                                       r = 0;
-                                       g = 198;
-                                       b = 0;
-                               } else {
-                                       /* Background color */
-                                       r = bars[BLACK][0];
-                                       g = bars[BLACK][1];
-                                       b = bars[BLACK][2];
-                               }
-
                                pos = inipos + j * 2;
-                               for (color = 0; color < 4; color++) {
-                                       p = basep + pos;
-
-                                       y = TO_Y(r, g, b);
-
-                                       switch (color) {
-                                       case 0:
-                                       case 2:
-                                               *p = TO_Y(r, g, b); /* Luma */
-                                               break;
-                                       case 1:
-                                               *p = TO_U(r, g, b); /* Cb */
-                                               break;
-                                       case 3:
-                                               *p = TO_V(r, g, b); /* Cr */
-                                               break;
-                                       }
-                                       pos++;
-                               }
+                               /* Draw white font on black background */
+                               if (chr & 1 << (7 - i))
+                                       gen_twopix(fh, basep + pos, WHITE);
+                               else
+                                       gen_twopix(fh, basep + pos, BLACK);
                                j++;
                        }
                }
@@ -324,8 +419,9 @@ end:
        return;
 }
 
-static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
+static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
 {
+       struct vivi_dev *dev = fh->dev;
        int h , pos = 0;
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
@@ -341,7 +437,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                return;
 
        for (h = 0; h < hmax; h++) {
-               gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+               gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
                         dev->timestr);
                memcpy(vbuf + pos, tmpbuf, wmax * 2);
                pos += wmax*2;
@@ -410,7 +506,7 @@ static void vivi_thread_tick(struct vivi_fh *fh)
        do_gettimeofday(&buf->vb.ts);
 
        /* Fill buffer */
-       vivi_fillbuff(dev, buf);
+       vivi_fillbuff(fh, buf);
        dprintk(dev, 1, "filled buffer %p\n", buf);
 
        wake_up(&buf->vb.done);
@@ -636,11 +732,15 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
 {
-       if (f->index > 0)
+       struct vivi_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(formats))
                return -EINVAL;
 
-       strlcpy(f->description, format.name, sizeof(f->description));
-       f->pixelformat = format.fourcc;
+       fmt = &formats[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
        return 0;
 }
 
@@ -670,13 +770,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        enum v4l2_field field;
        unsigned int maxw, maxh;
 
-       if (format.fourcc != f->fmt.pix.pixelformat) {
-               dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
-                       "Driver accepts only 0x%08x\n",
-                       f->fmt.pix.pixelformat, format.fourcc);
+       fmt = get_format(f);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
+                       f->fmt.pix.pixelformat);
                return -EINVAL;
        }
-       fmt = &format;
 
        field = f->fmt.pix.field;
 
@@ -714,6 +813,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 {
        struct vivi_fh  *fh = priv;
        struct videobuf_queue *q = &fh->vb_vidq;
+       unsigned char r, g, b;
+       int k, is_yuv;
 
        int ret = vidioc_try_fmt_vid_cap(file, fh, f);
        if (ret < 0)
@@ -727,12 +828,49 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                goto out;
        }
 
-       fh->fmt           = &format;
+       fh->fmt           = get_format(f);
        fh->width         = f->fmt.pix.width;
        fh->height        = f->fmt.pix.height;
        fh->vb_vidq.field = f->fmt.pix.field;
        fh->type          = f->type;
 
+       /* precalculate color bar values to speed up rendering */
+       for (k = 0; k < 8; k++) {
+               r = bars[k][0];
+               g = bars[k][1];
+               b = bars[k][2];
+               is_yuv = 0;
+
+               switch (fh->fmt->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+                       is_yuv = 1;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       r >>= 3;
+                       g >>= 2;
+                       b >>= 3;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       r >>= 3;
+                       g >>= 3;
+                       b >>= 3;
+                       break;
+               }
+
+               if (is_yuv) {
+                       fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
+                       fh->bars[k][1] = TO_U(r, g, b); /* Cb */
+                       fh->bars[k][2] = TO_V(r, g, b); /* Cr */
+               } else {
+                       fh->bars[k][0] = r;
+                       fh->bars[k][1] = g;
+                       fh->bars[k][2] = b;
+               }
+       }
+
        ret = 0;
 out:
        mutex_unlock(&q->vb_lock);
@@ -886,8 +1024,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        File operations for the device
    ------------------------------------------------------------------*/
 
-#define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8)
-
 static int vivi_open(struct inode *inode, struct file *file)
 {
        int minor = iminor(inode);
@@ -936,7 +1072,7 @@ unlock:
        fh->dev      = dev;
 
        fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       fh->fmt      = &format;
+       fh->fmt      = &formats[0];
        fh->width    = 640;
        fh->height   = 480;
 
index 45be9ec8edc4a10cba99ad26f5b7b446852506b2..67aa0db4b81a1049d21b7a096650d86362325a41 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/types.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
 #include <asm/uaccess.h>
-
 #include <linux/i2c.h>
-
-#define I2C_NAME(x) (x)->name
-
-#include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include <linux/videodev.h>
 #include <linux/video_decoder.h>
 
-#define I2C_VPX3220        0x86
-#define VPX3220_DEBUG  KERN_DEBUG "vpx3220: "
+MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
+MODULE_AUTHOR("Laurent Pinchart");
+MODULE_LICENSE("GPL");
 
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
-       do { \
-               if (debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 #define VPX_TIMEOUT_COUNT  10
 
 /* ----------------------------------------------------------------------- */
@@ -67,10 +56,8 @@ struct vpx3220 {
 static char *inputs[] = { "internal", "composite", "svideo" };
 
 /* ----------------------------------------------------------------------- */
-static inline int
-vpx3220_write (struct i2c_client *client,
-              u8                 reg,
-              u8                 value)
+
+static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value)
 {
        struct vpx3220 *decoder = i2c_get_clientdata(client);
 
@@ -78,15 +65,12 @@ vpx3220_write (struct i2c_client *client,
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int
-vpx3220_read (struct i2c_client *client,
-             u8                 reg)
+static inline int vpx3220_read(struct i2c_client *client, u8 reg)
 {
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int
-vpx3220_fp_status (struct i2c_client *client)
+static int vpx3220_fp_status(struct i2c_client *client)
 {
        unsigned char status;
        unsigned int i;
@@ -106,14 +90,11 @@ vpx3220_fp_status (struct i2c_client *client)
        return -1;
 }
 
-static int
-vpx3220_fp_write (struct i2c_client *client,
-                 u8                 fpaddr,
-                 u16                data)
+static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data)
 {
        /* Write the 16-bit address to the FPWR register */
        if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
-               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
                return -1;
        }
 
@@ -122,22 +103,20 @@ vpx3220_fp_write (struct i2c_client *client,
 
        /* Write the 16-bit data to the FPDAT register */
        if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
-               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
                return -1;
        }
 
        return 0;
 }
 
-static u16
-vpx3220_fp_read (struct i2c_client *client,
-                u16                fpaddr)
+static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr)
 {
        s16 data;
 
        /* Write the 16-bit address to the FPRD register */
        if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
-               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
                return -1;
        }
 
@@ -147,25 +126,22 @@ vpx3220_fp_read (struct i2c_client *client,
        /* Read the 16-bit data from the FPDAT register */
        data = i2c_smbus_read_word_data(client, 0x28);
        if (data == -1) {
-               dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
+               v4l_dbg(1, debug, client, "%s: failed\n", __func__);
                return -1;
        }
 
        return swab16(data);
 }
 
-static int
-vpx3220_write_block (struct i2c_client *client,
-                    const u8          *data,
-                    unsigned int       len)
+static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
 {
        u8 reg;
        int ret = -1;
 
        while (len >= 2) {
                reg = *data++;
-               if ((ret =
-                    vpx3220_write(client, reg, *data++)) < 0)
+               ret = vpx3220_write(client, reg, *data++);
+               if (ret < 0)
                        break;
                len -= 2;
        }
@@ -173,10 +149,8 @@ vpx3220_write_block (struct i2c_client *client,
        return ret;
 }
 
-static int
-vpx3220_write_fp_block (struct i2c_client *client,
-                       const u16         *data,
-                       unsigned int       len)
+static int vpx3220_write_fp_block(struct i2c_client *client,
+               const u16 *data, unsigned int len)
 {
        u8 reg;
        int ret = 0;
@@ -285,25 +259,20 @@ static const unsigned short init_fp[] = {
        0x4b, 0x298,            /* PLL gain */
 };
 
-static void
-vpx3220_dump_i2c (struct i2c_client *client)
+static void vpx3220_dump_i2c(struct i2c_client *client)
 {
        int len = sizeof(init_common);
        const unsigned char *data = init_common;
 
        while (len > 1) {
-               dprintk(1,
-                       KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n",
+               v4l_dbg(1, debug, client, "i2c reg 0x%02x data 0x%02x\n",
                        *data, vpx3220_read(client, *data));
                data += 2;
                len -= 2;
        }
 }
 
-static int
-vpx3220_command (struct i2c_client *client,
-                unsigned int       cmd,
-                void              *arg)
+static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct vpx3220 *decoder = i2c_get_clientdata(client);
 
@@ -315,7 +284,6 @@ vpx3220_command (struct i2c_client *client,
                vpx3220_write_fp_block(client, init_fp,
                                       sizeof(init_fp) >> 1);
                switch (decoder->norm) {
-
                case VIDEO_MODE_NTSC:
                        vpx3220_write_fp_block(client, init_ntsc,
                                               sizeof(init_ntsc) >> 1);
@@ -334,21 +302,20 @@ vpx3220_command (struct i2c_client *client,
                                               sizeof(init_pal) >> 1);
                        break;
                }
-       }
                break;
+       }
 
        case DECODER_DUMP:
        {
                vpx3220_dump_i2c(client);
-       }
                break;
+       }
 
        case DECODER_GET_CAPABILITIES:
        {
                struct video_decoder_capability *cap = arg;
 
-               dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n",
-                       I2C_NAME(client));
+               v4l_dbg(1, debug, client, "DECODER_GET_CAPABILITIES\n");
 
                cap->flags = VIDEO_DECODER_PAL |
                             VIDEO_DECODER_NTSC |
@@ -357,20 +324,18 @@ vpx3220_command (struct i2c_client *client,
                             VIDEO_DECODER_CCIR;
                cap->inputs = 3;
                cap->outputs = 1;
-       }
                break;
+       }
 
        case DECODER_GET_STATUS:
        {
                int res = 0, status;
 
-               dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n",
-                       I2C_NAME(client));
+               v4l_dbg(1, debug, client, "DECODER_GET_STATUS\n");
 
                status = vpx3220_fp_read(client, 0x0f3);
 
-               dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client),
-                       status);
+               v4l_dbg(1, debug, client, "status: 0x%04x\n", status);
 
                if (status < 0)
                        return status;
@@ -379,7 +344,6 @@ vpx3220_command (struct i2c_client *client,
                        res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR;
 
                        switch (status & 0x18) {
-
                        case 0x00:
                        case 0x10:
                        case 0x14:
@@ -400,8 +364,8 @@ vpx3220_command (struct i2c_client *client,
                }
 
                *(int *) arg = res;
-       }
                break;
+       }
 
        case DECODER_SET_NORM:
        {
@@ -413,50 +377,43 @@ vpx3220_command (struct i2c_client *client,
                   choosen video norm */
                temp_input = vpx3220_fp_read(client, 0xf2);
 
-               dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n",
-                       I2C_NAME(client), *iarg);
+               v4l_dbg(1, debug, client, "DECODER_SET_NORM %d\n", *iarg);
                switch (*iarg) {
-
                case VIDEO_MODE_NTSC:
                        vpx3220_write_fp_block(client, init_ntsc,
                                               sizeof(init_ntsc) >> 1);
-                       dprintk(1, KERN_INFO "%s: norm switched to NTSC\n",
-                               I2C_NAME(client));
+                       v4l_dbg(1, debug, client, "norm switched to NTSC\n");
                        break;
 
                case VIDEO_MODE_PAL:
                        vpx3220_write_fp_block(client, init_pal,
                                               sizeof(init_pal) >> 1);
-                       dprintk(1, KERN_INFO "%s: norm switched to PAL\n",
-                               I2C_NAME(client));
+                       v4l_dbg(1, debug, client, "norm switched to PAL\n");
                        break;
 
                case VIDEO_MODE_SECAM:
                        vpx3220_write_fp_block(client, init_secam,
                                               sizeof(init_secam) >> 1);
-                       dprintk(1, KERN_INFO "%s: norm switched to SECAM\n",
-                               I2C_NAME(client));
+                       v4l_dbg(1, debug, client, "norm switched to SECAM\n");
                        break;
 
                case VIDEO_MODE_AUTO:
                        /* FIXME This is only preliminary support */
                        data = vpx3220_fp_read(client, 0xf2) & 0x20;
                        vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
-                       dprintk(1, KERN_INFO "%s: norm switched to Auto\n",
-                               I2C_NAME(client));
+                       v4l_dbg(1, debug, client, "norm switched to AUTO\n");
                        break;
 
                default:
                        return -EINVAL;
-
                }
                decoder->norm = *iarg;
 
                /* And here we set the backed up video input again */
                vpx3220_fp_write(client, 0xf2, temp_input | 0x0010);
                udelay(10);
-       }
                break;
+       }
 
        case DECODER_SET_INPUT:
        {
@@ -475,8 +432,7 @@ vpx3220_command (struct i2c_client *client,
                if (*iarg < 0 || *iarg > 2)
                        return -EINVAL;
 
-               dprintk(1, KERN_INFO "%s: input switched to %s\n",
-                       I2C_NAME(client), inputs[*iarg]);
+               v4l_dbg(1, debug, client, "input switched to %s\n", inputs[*iarg]);
 
                vpx3220_write(client, 0x33, input[*iarg][0]);
 
@@ -488,8 +444,8 @@ vpx3220_command (struct i2c_client *client,
                                 data | (input[*iarg][1] << 5) | 0x0010);
 
                udelay(10);
-       }
                break;
+       }
 
        case DECODER_SET_OUTPUT:
        {
@@ -499,19 +455,18 @@ vpx3220_command (struct i2c_client *client,
                if (*iarg != 0) {
                        return -EINVAL;
                }
-       }
                break;
+       }
 
        case DECODER_ENABLE_OUTPUT:
        {
                int *iarg = arg;
 
-               dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n",
-                       I2C_NAME(client), *iarg);
+               v4l_dbg(1, debug, client, "DECODER_ENABLE_OUTPUT %d\n", *iarg);
 
                vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00));
-       }
                break;
+       }
 
        case DECODER_SET_PICTURE:
        {
@@ -542,8 +497,8 @@ vpx3220_command (struct i2c_client *client,
                        vpx3220_fp_write(client, 0x1c,
                                         ((decoder->hue - 32768) >> 6) & 0xFFF);
                }
-       }
                break;
+       }
 
        default:
                return -EINVAL;
@@ -552,8 +507,7 @@ vpx3220_command (struct i2c_client *client,
        return 0;
 }
 
-static int
-vpx3220_init_client (struct i2c_client *client)
+static int vpx3220_init_client(struct i2c_client *client)
 {
        vpx3220_write_block(client, init_common, sizeof(init_common));
        vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1);
@@ -567,115 +521,26 @@ vpx3220_init_client (struct i2c_client *client)
  * Client management code
  */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] =
-    { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4,
-       I2C_CLIENT_END
-};
-
-static unsigned short ignore = I2C_CLIENT_END;
+static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
 
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c             = normal_i2c,
-       .probe                  = &ignore,
-       .ignore                 = &ignore,
-};
-
-static struct i2c_driver vpx3220_i2c_driver;
-
-static int
-vpx3220_detach_client (struct i2c_client *client)
-{
-       struct vpx3220 *decoder = i2c_get_clientdata(client);
-       int err;
-
-       err = i2c_detach_client(client);
-       if (err) {
-               return err;
-       }
-
-       kfree(decoder);
-       kfree(client);
-
-       return 0;
-}
+I2C_CLIENT_INSMOD;
 
-static int
-vpx3220_detect_client (struct i2c_adapter *adapter,
-                      int                 address,
-                      int                 kind)
+static int vpx3220_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       int err;
-       struct i2c_client *client;
        struct vpx3220 *decoder;
-
-       dprintk(1, VPX3220_DEBUG "%s\n", __func__);
+       const char *name = NULL;
+       u8 ver;
+       u16 pn;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality
-           (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
-               return 0;
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == NULL) {
-               return -ENOMEM;
-       }
-
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &vpx3220_i2c_driver;
-
-       /* Check for manufacture ID and part number */
-       if (kind < 0) {
-               u8 id;
-               u16 pn;
-
-               id = vpx3220_read(client, 0x00);
-               if (id != 0xec) {
-                       dprintk(1,
-                               KERN_INFO
-                               "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n",
-                               id);
-                       kfree(client);
-                       return 0;
-               }
-
-               pn = (vpx3220_read(client, 0x02) << 8) +
-                   vpx3220_read(client, 0x01);
-               switch (pn) {
-               case 0x4680:
-                       strlcpy(I2C_NAME(client), "vpx3220a",
-                               sizeof(I2C_NAME(client)));
-                       break;
-               case 0x4260:
-                       strlcpy(I2C_NAME(client), "vpx3216b",
-                               sizeof(I2C_NAME(client)));
-                       break;
-               case 0x4280:
-                       strlcpy(I2C_NAME(client), "vpx3214c",
-                               sizeof(I2C_NAME(client)));
-                       break;
-               default:
-                       dprintk(1,
-                               KERN_INFO
-                               "%s: Wrong part number (0x%04x)\n",
-                               __func__, pn);
-                       kfree(client);
-                       return 0;
-               }
-       } else {
-               strlcpy(I2C_NAME(client), "forced vpx32xx",
-                       sizeof(I2C_NAME(client)));
-       }
+       if (!i2c_check_functionality(client->adapter,
+               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
 
        decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
-       if (decoder == NULL) {
-               kfree(client);
+       if (decoder == NULL)
                return -ENOMEM;
-       }
        decoder->norm = VIDEO_MODE_PAL;
        decoder->input = 0;
        decoder->enable = 1;
@@ -685,63 +550,52 @@ vpx3220_detect_client (struct i2c_adapter *adapter,
        decoder->sat = 32768;
        i2c_set_clientdata(client, decoder);
 
-       err = i2c_attach_client(client);
-       if (err) {
-               kfree(client);
-               kfree(decoder);
-               return err;
+       ver = i2c_smbus_read_byte_data(client, 0x00);
+       pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
+               i2c_smbus_read_byte_data(client, 0x01);
+       if (ver == 0xec) {
+               switch (pn) {
+               case 0x4680:
+                       name = "vpx3220a";
+                       break;
+               case 0x4260:
+                       name = "vpx3216b";
+                       break;
+               case 0x4280:
+                       name = "vpx3214c";
+                       break;
+               }
        }
-
-       dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n",
-               I2C_NAME(client), client->addr << 1);
+       if (name)
+               v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+                       client->addr << 1, client->adapter->name);
+       else
+               v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n",
+                       ver, pn, client->addr << 1, client->adapter->name);
 
        vpx3220_init_client(client);
-
        return 0;
 }
 
-static int
-vpx3220_attach_adapter (struct i2c_adapter *adapter)
+static int vpx3220_remove(struct i2c_client *client)
 {
-       int ret;
-
-       ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client);
-       dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n",
-               __func__, ret);
-       return ret;
+       kfree(i2c_get_clientdata(client));
+       return 0;
 }
 
-/* -----------------------------------------------------------------------
- * Driver initialization and cleanup code
- */
-
-static struct i2c_driver vpx3220_i2c_driver = {
-       .driver = {
-               .name = "vpx3220",
-       },
-
-       .id = I2C_DRIVERID_VPX3220,
+static const struct i2c_device_id vpx3220_id[] = {
+       { "vpx3220a", 0 },
+       { "vpx3216b", 0 },
+       { "vpx3214c", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, vpx3220_id);
 
-       .attach_adapter = vpx3220_attach_adapter,
-       .detach_client = vpx3220_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "vpx3220",
+       .driverid = I2C_DRIVERID_VPX3220,
        .command = vpx3220_command,
+       .probe = vpx3220_probe,
+       .remove = vpx3220_remove,
+       .id_table = vpx3220_id,
 };
-
-static int __init
-vpx3220_init (void)
-{
-       return i2c_add_driver(&vpx3220_i2c_driver);
-}
-
-static void __exit
-vpx3220_cleanup (void)
-{
-       i2c_del_driver(&vpx3220_i2c_driver);
-}
-
-module_init(vpx3220_init);
-module_exit(vpx3220_cleanup);
-
-MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
-MODULE_AUTHOR("Laurent Pinchart");
-MODULE_LICENSE("GPL");
index 3282be730298a1ee2be50c7a3fc4cbe55b342eae..fa5f2f8f518a1e37dab4e2ba6150e41c71295c24 100644 (file)
@@ -817,6 +817,7 @@ zoran_register_i2c (struct zoran *zr)
        memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
               sizeof(struct i2c_algo_bit_data));
        zr->i2c_algo.data = zr;
+       zr->i2c_adapter.class = I2C_CLASS_TV_ANALOG;
        zr->i2c_adapter.id = I2C_HW_B_ZR36067;
        zr->i2c_adapter.client_register = zoran_i2c_client_register;
        zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
index 25de7631443e9c912bf3362dae1aa9632d764d92..db11ab9e60da289e9073c792dce72415b4ca632c 100644 (file)
@@ -2996,7 +2996,6 @@ zoran_do_ioctl (struct inode *inode,
                        break;
 
                default:
-                       dprintk(3, "unsupported\n");
                        dprintk(1,
                                KERN_ERR
                                "%s: VIDIOC_S_FMT - unsupported type %d\n",
index 9e9d70c02a07c9a8876f71c3445ac5092c563810..d0a1174fb516c14f63862e42919d74c044df7882 100644 (file)
@@ -160,7 +160,7 @@ config EXT4_FS
          filesystem initially.
 
          To compile this file system support as a module, choose M here. The
-         module will be called ext4dev.
+         module will be called ext4.
 
          If unsure, say N.
 
index d0c69f57e5bfdebd65a668443428c44373360ab0..2168c902d5ca61027236bb75812591d16575ec1d 100644 (file)
@@ -71,7 +71,7 @@ obj-$(CONFIG_DLM)             += dlm/
 # Do not add any filesystems before this line
 obj-$(CONFIG_REISERFS_FS)      += reiserfs/
 obj-$(CONFIG_EXT3_FS)          += ext3/ # Before ext2 so root fs can be ext3
-obj-$(CONFIG_EXT4_FS)          += ext4/ # Before ext2 so root fs can be ext4dev
+obj-$(CONFIG_EXT4_FS)          += ext4/ # Before ext2 so root fs can be ext4
 obj-$(CONFIG_JBD)              += jbd/
 obj-$(CONFIG_JBD2)             += jbd2/
 obj-$(CONFIG_EXT2_FS)          += ext2/
index bd2ece22882755b02599563a1bee89c5b10d2b87..b9821be709bddb000077b9a4b15efe34e9392bd0 100644 (file)
@@ -568,8 +568,16 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
 
        /* this isn't the right place to decide whether block is metadata
         * inode.c/extents.c knows better, but for safety ... */
-       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
-                       ext4_should_journal_data(inode))
+       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+               metadata = 1;
+
+       /* We need to make sure we don't reuse
+        * block released untill the transaction commit.
+        * writeback mode have weak data consistency so
+        * don't force data as metadata when freeing block
+        * for writeback mode.
+        */
+       if (metadata == 0 && !ext4_should_writeback_data(inode))
                metadata = 1;
 
        sb = inode->i_sb;
index 6690a41cdd9fc8ca6536d3a6077222e65830a834..4880cc3e672778d54944326d265fa9b50b8d7275 100644 (file)
@@ -511,7 +511,6 @@ do {                                                                               \
 /*
  * Mount flags
  */
-#define EXT4_MOUNT_CHECK               0x00001 /* Do mount-time checks */
 #define EXT4_MOUNT_OLDALLOC            0x00002  /* Don't use the new Orlov allocator */
 #define EXT4_MOUNT_GRPID               0x00004 /* Create files with directory's group */
 #define EXT4_MOUNT_DEBUG               0x00008 /* Some debugging messages */
index 6a0b40d43264b232a806f0e265150343c6375077..445fde603df800cb4a1bf8144f34eb9aeb17b52a 100644 (file)
@@ -99,9 +99,6 @@ struct ext4_sb_info {
        struct inode *s_buddy_cache;
        long s_blocks_reserved;
        spinlock_t s_reserve_lock;
-       struct list_head s_active_transaction;
-       struct list_head s_closed_transaction;
-       struct list_head s_committed_transaction;
        spinlock_t s_md_lock;
        tid_t s_last_transaction;
        unsigned short *s_mb_offsets, *s_mb_maxs;
index 9b4ec9decfd1b6020c13bbd57d86af7eab46006b..8dbf6953845ba61097703006553c34d1d83bd81f 100644 (file)
@@ -1648,6 +1648,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
        int ret = 0, err, nr_pages, i;
        unsigned long index, end;
        struct pagevec pvec;
+       long pages_skipped;
 
        BUG_ON(mpd->next_page <= mpd->first_page);
        pagevec_init(&pvec, 0);
@@ -1655,20 +1656,30 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
        end = mpd->next_page - 1;
 
        while (index <= end) {
-               /* XXX: optimize tail */
-               nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE);
+               /*
+                * We can use PAGECACHE_TAG_DIRTY lookup here because
+                * even though we have cleared the dirty flag on the page
+                * We still keep the page in the radix tree with tag
+                * PAGECACHE_TAG_DIRTY. See clear_page_dirty_for_io.
+                * The PAGECACHE_TAG_DIRTY is cleared in set_page_writeback
+                * which is called via the below writepage callback.
+                */
+               nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                                       PAGECACHE_TAG_DIRTY,
+                                       min(end - index,
+                                       (pgoff_t)PAGEVEC_SIZE-1) + 1);
                if (nr_pages == 0)
                        break;
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
 
-                       index = page->index;
-                       if (index > end)
-                               break;
-                       index++;
-
+                       pages_skipped = mpd->wbc->pages_skipped;
                        err = mapping->a_ops->writepage(page, mpd->wbc);
-                       if (!err)
+                       if (!err && (pages_skipped == mpd->wbc->pages_skipped))
+                               /*
+                                * have successfully written the page
+                                * without skipping the same
+                                */
                                mpd->pages_written++;
                        /*
                         * In error case, we have to continue because
@@ -2104,7 +2115,6 @@ static int mpage_da_writepages(struct address_space *mapping,
                               struct writeback_control *wbc,
                               struct mpage_da_data *mpd)
 {
-       long to_write;
        int ret;
 
        if (!mpd->get_block)
@@ -2119,19 +2129,18 @@ static int mpage_da_writepages(struct address_space *mapping,
        mpd->pages_written = 0;
        mpd->retval = 0;
 
-       to_write = wbc->nr_to_write;
-
        ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, mpd);
-
        /*
         * Handle last extent of pages
         */
        if (!mpd->io_done && mpd->next_page != mpd->first_page) {
                if (mpage_da_map_blocks(mpd) == 0)
                        mpage_da_submit_io(mpd);
-       }
 
-       wbc->nr_to_write = to_write - mpd->pages_written;
+               mpd->io_done = 1;
+               ret = MPAGE_DA_EXTENT_TAIL;
+       }
+       wbc->nr_to_write -= mpd->pages_written;
        return ret;
 }
 
@@ -2360,12 +2369,14 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
 static int ext4_da_writepages(struct address_space *mapping,
                              struct writeback_control *wbc)
 {
+       pgoff_t index;
+       int range_whole = 0;
        handle_t *handle = NULL;
-       loff_t range_start = 0;
        struct mpage_da_data mpd;
        struct inode *inode = mapping->host;
+       int no_nrwrite_index_update;
+       long pages_written = 0, pages_skipped;
        int needed_blocks, ret = 0, nr_to_writebump = 0;
-       long to_write, pages_skipped = 0;
        struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
 
        /*
@@ -2385,23 +2396,26 @@ static int ext4_da_writepages(struct address_space *mapping,
                nr_to_writebump = sbi->s_mb_stream_request - wbc->nr_to_write;
                wbc->nr_to_write = sbi->s_mb_stream_request;
        }
+       if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+               range_whole = 1;
 
-       if (!wbc->range_cyclic)
-               /*
-                * If range_cyclic is not set force range_cont
-                * and save the old writeback_index
-                */
-               wbc->range_cont = 1;
-
-       range_start =  wbc->range_start;
-       pages_skipped = wbc->pages_skipped;
+       if (wbc->range_cyclic)
+               index = mapping->writeback_index;
+       else
+               index = wbc->range_start >> PAGE_CACHE_SHIFT;
 
        mpd.wbc = wbc;
        mpd.inode = mapping->host;
 
-restart_loop:
-       to_write = wbc->nr_to_write;
-       while (!ret && to_write > 0) {
+       /*
+        * we don't want write_cache_pages to update
+        * nr_to_write and writeback_index
+        */
+       no_nrwrite_index_update = wbc->no_nrwrite_index_update;
+       wbc->no_nrwrite_index_update = 1;
+       pages_skipped = wbc->pages_skipped;
+
+       while (!ret && wbc->nr_to_write > 0) {
 
                /*
                 * we  insert one extent at a time. So we need
@@ -2422,48 +2436,53 @@ restart_loop:
                        dump_stack();
                        goto out_writepages;
                }
-               to_write -= wbc->nr_to_write;
-
                mpd.get_block = ext4_da_get_block_write;
                ret = mpage_da_writepages(mapping, wbc, &mpd);
 
                ext4_journal_stop(handle);
 
-               if (mpd.retval == -ENOSPC)
+               if (mpd.retval == -ENOSPC) {
+                       /* commit the transaction which would
+                        * free blocks released in the transaction
+                        * and try again
+                        */
                        jbd2_journal_force_commit_nested(sbi->s_journal);
-
-               /* reset the retry count */
-               if (ret == MPAGE_DA_EXTENT_TAIL) {
+                       wbc->pages_skipped = pages_skipped;
+                       ret = 0;
+               } else if (ret == MPAGE_DA_EXTENT_TAIL) {
                        /*
                         * got one extent now try with
                         * rest of the pages
                         */
-                       to_write += wbc->nr_to_write;
+                       pages_written += mpd.pages_written;
+                       wbc->pages_skipped = pages_skipped;
                        ret = 0;
-               } else if (wbc->nr_to_write) {
+               } else if (wbc->nr_to_write)
                        /*
                         * There is no more writeout needed
                         * or we requested for a noblocking writeout
                         * and we found the device congested
                         */
-                       to_write += wbc->nr_to_write;
                        break;
-               }
-               wbc->nr_to_write = to_write;
-       }
-
-       if (wbc->range_cont && (pages_skipped != wbc->pages_skipped)) {
-               /* We skipped pages in this loop */
-               wbc->range_start = range_start;
-               wbc->nr_to_write = to_write +
-                               wbc->pages_skipped - pages_skipped;
-               wbc->pages_skipped = pages_skipped;
-               goto restart_loop;
        }
+       if (pages_skipped != wbc->pages_skipped)
+               printk(KERN_EMERG "This should not happen leaving %s "
+                               "with nr_to_write = %ld ret = %d\n",
+                               __func__, wbc->nr_to_write, ret);
+
+       /* Update index */
+       index += pages_written;
+       if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
+               /*
+                * set the writeback_index so that range_cyclic
+                * mode will write it back later
+                */
+               mapping->writeback_index = index;
 
 out_writepages:
-       wbc->nr_to_write = to_write - nr_to_writebump;
-       wbc->range_start = range_start;
+       if (!no_nrwrite_index_update)
+               wbc->no_nrwrite_index_update = 0;
+       wbc->nr_to_write -= nr_to_writebump;
        return ret;
 }
 
@@ -4175,7 +4194,6 @@ static int ext4_inode_blocks_set(handle_t *handle,
        struct inode *inode = &(ei->vfs_inode);
        u64 i_blocks = inode->i_blocks;
        struct super_block *sb = inode->i_sb;
-       int err = 0;
 
        if (i_blocks <= ~0U) {
                /*
@@ -4185,36 +4203,27 @@ static int ext4_inode_blocks_set(handle_t *handle,
                raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
                raw_inode->i_blocks_high = 0;
                ei->i_flags &= ~EXT4_HUGE_FILE_FL;
-       } else if (i_blocks <= 0xffffffffffffULL) {
+               return 0;
+       }
+       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
+               return -EFBIG;
+
+       if (i_blocks <= 0xffffffffffffULL) {
                /*
                 * i_blocks can be represented in a 48 bit variable
                 * as multiple of 512 bytes
                 */
-               err = ext4_update_rocompat_feature(handle, sb,
-                                           EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
-               if (err)
-                       goto  err_out;
-               /* i_block is stored in the split  48 bit fields */
                raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
                raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
                ei->i_flags &= ~EXT4_HUGE_FILE_FL;
        } else {
-               /*
-                * i_blocks should be represented in a 48 bit variable
-                * as multiple of  file system block size
-                */
-               err = ext4_update_rocompat_feature(handle, sb,
-                                           EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
-               if (err)
-                       goto  err_out;
                ei->i_flags |= EXT4_HUGE_FILE_FL;
                /* i_block is stored in file system block size */
                i_blocks = i_blocks >> (inode->i_blkbits - 9);
                raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
                raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
        }
-err_out:
-       return err;
+       return 0;
 }
 
 /*
index b580714f0d859c107e94a3f6c61286141fb0cdab..dfe17a1340523c9c10d3c1f14a1077b4fd6939c9 100644 (file)
@@ -2300,6 +2300,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
        }
 
        INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list);
+       meta_group_info[i]->bb_free_root.rb_node = NULL;;
 
 #ifdef DOUBLE_CHECK
        {
@@ -2522,9 +2523,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        }
 
        spin_lock_init(&sbi->s_md_lock);
-       INIT_LIST_HEAD(&sbi->s_active_transaction);
-       INIT_LIST_HEAD(&sbi->s_closed_transaction);
-       INIT_LIST_HEAD(&sbi->s_committed_transaction);
        spin_lock_init(&sbi->s_bal_lock);
 
        sbi->s_mb_max_to_scan = MB_DEFAULT_MAX_TO_SCAN;
@@ -2553,6 +2551,8 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        ext4_mb_init_per_dev_proc(sb);
        ext4_mb_history_init(sb);
 
+       sbi->s_journal->j_commit_callback = release_blocks_on_commit;
+
        printk(KERN_INFO "EXT4-fs: mballoc enabled\n");
        return 0;
 }
@@ -2568,7 +2568,7 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
                pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list);
                list_del(&pa->pa_group_list);
                count++;
-               kfree(pa);
+               kmem_cache_free(ext4_pspace_cachep, pa);
        }
        if (count)
                mb_debug("mballoc: %u PAs left\n", count);
@@ -2582,15 +2582,6 @@ int ext4_mb_release(struct super_block *sb)
        struct ext4_group_info *grinfo;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       /* release freed, non-committed blocks */
-       spin_lock(&sbi->s_md_lock);
-       list_splice_init(&sbi->s_closed_transaction,
-                       &sbi->s_committed_transaction);
-       list_splice_init(&sbi->s_active_transaction,
-                       &sbi->s_committed_transaction);
-       spin_unlock(&sbi->s_md_lock);
-       ext4_mb_free_committed_blocks(sb);
-
        if (sbi->s_group_info) {
                for (i = 0; i < sbi->s_groups_count; i++) {
                        grinfo = ext4_get_group_info(sb, i);
@@ -2644,61 +2635,57 @@ int ext4_mb_release(struct super_block *sb)
        return 0;
 }
 
-static noinline_for_stack void
-ext4_mb_free_committed_blocks(struct super_block *sb)
+/*
+ * This function is called by the jbd2 layer once the commit has finished,
+ * so we know we can free the blocks that were released with that commit.
+ */
+static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
 {
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       int err;
-       int i;
-       int count = 0;
-       int count2 = 0;
-       struct ext4_free_metadata *md;
+       struct super_block *sb = journal->j_private;
        struct ext4_buddy e4b;
+       struct ext4_group_info *db;
+       int err, count = 0, count2 = 0;
+       struct ext4_free_data *entry;
+       ext4_fsblk_t discard_block;
+       struct list_head *l, *ltmp;
 
-       if (list_empty(&sbi->s_committed_transaction))
-               return;
-
-       /* there is committed blocks to be freed yet */
-       do {
-               /* get next array of blocks */
-               md = NULL;
-               spin_lock(&sbi->s_md_lock);
-               if (!list_empty(&sbi->s_committed_transaction)) {
-                       md = list_entry(sbi->s_committed_transaction.next,
-                                       struct ext4_free_metadata, list);
-                       list_del(&md->list);
-               }
-               spin_unlock(&sbi->s_md_lock);
-
-               if (md == NULL)
-                       break;
+       list_for_each_safe(l, ltmp, &txn->t_private_list) {
+               entry = list_entry(l, struct ext4_free_data, list);
 
                mb_debug("gonna free %u blocks in group %lu (0x%p):",
-                               md->num, md->group, md);
+                        entry->count, entry->group, entry);
 
-               err = ext4_mb_load_buddy(sb, md->group, &e4b);
+               err = ext4_mb_load_buddy(sb, entry->group, &e4b);
                /* we expect to find existing buddy because it's pinned */
                BUG_ON(err != 0);
 
+               db = e4b.bd_info;
                /* there are blocks to put in buddy to make them really free */
-               count += md->num;
+               count += entry->count;
                count2++;
-               ext4_lock_group(sb, md->group);
-               for (i = 0; i < md->num; i++) {
-                       mb_debug(" %u", md->blocks[i]);
-                       mb_free_blocks(NULL, &e4b, md->blocks[i], 1);
+               ext4_lock_group(sb, entry->group);
+               /* Take it out of per group rb tree */
+               rb_erase(&entry->node, &(db->bb_free_root));
+               mb_free_blocks(NULL, &e4b, entry->start_blk, entry->count);
+
+               if (!db->bb_free_root.rb_node) {
+                       /* No more items in the per group rb tree
+                        * balance refcounts from ext4_mb_free_metadata()
+                        */
+                       page_cache_release(e4b.bd_buddy_page);
+                       page_cache_release(e4b.bd_bitmap_page);
                }
-               mb_debug("\n");
-               ext4_unlock_group(sb, md->group);
-
-               /* balance refcounts from ext4_mb_free_metadata() */
-               page_cache_release(e4b.bd_buddy_page);
-               page_cache_release(e4b.bd_bitmap_page);
-
-               kfree(md);
+               ext4_unlock_group(sb, entry->group);
+               discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb)
+                       + entry->start_blk
+                       + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+               trace_mark(ext4_discard_blocks, "dev %s blk %llu count %u", sb->s_id,
+                          (unsigned long long) discard_block, entry->count);
+               sb_issue_discard(sb, discard_block, entry->count);
+
+               kmem_cache_free(ext4_free_ext_cachep, entry);
                ext4_mb_release_desc(&e4b);
-
-       } while (md);
+       }
 
        mb_debug("freed %u blocks in %u structures\n", count, count2);
 }
@@ -2712,6 +2699,7 @@ ext4_mb_free_committed_blocks(struct super_block *sb)
 
 static int ext4_mb_init_per_dev_proc(struct super_block *sb)
 {
+#ifdef CONFIG_PROC_FS
        mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct proc_dir_entry *proc;
@@ -2735,10 +2723,14 @@ err_out:
        remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
        remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
        return -ENOMEM;
+#else
+       return 0;
+#endif
 }
 
 static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
 {
+#ifdef CONFIG_PROC_FS
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (sbi->s_proc == NULL)
@@ -2750,7 +2742,7 @@ static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
        remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
        remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
        remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
-
+#endif
        return 0;
 }
 
@@ -2771,6 +2763,16 @@ int __init init_ext4_mballoc(void)
                kmem_cache_destroy(ext4_pspace_cachep);
                return -ENOMEM;
        }
+
+       ext4_free_ext_cachep =
+               kmem_cache_create("ext4_free_block_extents",
+                                    sizeof(struct ext4_free_data),
+                                    0, SLAB_RECLAIM_ACCOUNT, NULL);
+       if (ext4_free_ext_cachep == NULL) {
+               kmem_cache_destroy(ext4_pspace_cachep);
+               kmem_cache_destroy(ext4_ac_cachep);
+               return -ENOMEM;
+       }
        return 0;
 }
 
@@ -2779,6 +2781,7 @@ void exit_ext4_mballoc(void)
        /* XXX: synchronize_rcu(); */
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
+       kmem_cache_destroy(ext4_free_ext_cachep);
 }
 
 
@@ -4324,8 +4327,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
                goto out1;
        }
 
-       ext4_mb_poll_new_transaction(sb, handle);
-
        *errp = ext4_mb_initialize_context(ac, ar);
        if (*errp) {
                ar->len = 0;
@@ -4384,35 +4385,20 @@ out1:
 
        return block;
 }
-static void ext4_mb_poll_new_transaction(struct super_block *sb,
-                                               handle_t *handle)
-{
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-       if (sbi->s_last_transaction == handle->h_transaction->t_tid)
-               return;
-
-       /* new transaction! time to close last one and free blocks for
-        * committed transaction. we know that only transaction can be
-        * active, so previos transaction can be being logged and we
-        * know that transaction before previous is known to be already
-        * logged. this means that now we may free blocks freed in all
-        * transactions before previous one. hope I'm clear enough ... */
 
-       spin_lock(&sbi->s_md_lock);
-       if (sbi->s_last_transaction != handle->h_transaction->t_tid) {
-               mb_debug("new transaction %lu, old %lu\n",
-                               (unsigned long) handle->h_transaction->t_tid,
-                               (unsigned long) sbi->s_last_transaction);
-               list_splice_init(&sbi->s_closed_transaction,
-                               &sbi->s_committed_transaction);
-               list_splice_init(&sbi->s_active_transaction,
-                               &sbi->s_closed_transaction);
-               sbi->s_last_transaction = handle->h_transaction->t_tid;
-       }
-       spin_unlock(&sbi->s_md_lock);
-
-       ext4_mb_free_committed_blocks(sb);
+/*
+ * We can merge two free data extents only if the physical blocks
+ * are contiguous, AND the extents were freed by the same transaction,
+ * AND the blocks are associated with the same group.
+ */
+static int can_merge(struct ext4_free_data *entry1,
+                       struct ext4_free_data *entry2)
+{
+       if ((entry1->t_tid == entry2->t_tid) &&
+           (entry1->group == entry2->group) &&
+           ((entry1->start_blk + entry1->count) == entry2->start_blk))
+               return 1;
+       return 0;
 }
 
 static noinline_for_stack int
@@ -4422,57 +4408,80 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        struct ext4_group_info *db = e4b->bd_info;
        struct super_block *sb = e4b->bd_sb;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_free_metadata *md;
-       int i;
+       struct ext4_free_data *entry, *new_entry;
+       struct rb_node **n = &db->bb_free_root.rb_node, *node;
+       struct rb_node *parent = NULL, *new_node;
+
 
        BUG_ON(e4b->bd_bitmap_page == NULL);
        BUG_ON(e4b->bd_buddy_page == NULL);
 
+       new_entry  = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS);
+       new_entry->start_blk = block;
+       new_entry->group  = group;
+       new_entry->count = count;
+       new_entry->t_tid = handle->h_transaction->t_tid;
+       new_node = &new_entry->node;
+
        ext4_lock_group(sb, group);
-       for (i = 0; i < count; i++) {
-               md = db->bb_md_cur;
-               if (md && db->bb_tid != handle->h_transaction->t_tid) {
-                       db->bb_md_cur = NULL;
-                       md = NULL;
+       if (!*n) {
+               /* first free block exent. We need to
+                  protect buddy cache from being freed,
+                * otherwise we'll refresh it from
+                * on-disk bitmap and lose not-yet-available
+                * blocks */
+               page_cache_get(e4b->bd_buddy_page);
+               page_cache_get(e4b->bd_bitmap_page);
+       }
+       while (*n) {
+               parent = *n;
+               entry = rb_entry(parent, struct ext4_free_data, node);
+               if (block < entry->start_blk)
+                       n = &(*n)->rb_left;
+               else if (block >= (entry->start_blk + entry->count))
+                       n = &(*n)->rb_right;
+               else {
+                       ext4_error(sb, __func__,
+                           "Double free of blocks %d (%d %d)\n",
+                           block, entry->start_blk, entry->count);
+                       return 0;
                }
+       }
 
-               if (md == NULL) {
-                       ext4_unlock_group(sb, group);
-                       md = kmalloc(sizeof(*md), GFP_NOFS);
-                       if (md == NULL)
-                               return -ENOMEM;
-                       md->num = 0;
-                       md->group = group;
-
-                       ext4_lock_group(sb, group);
-                       if (db->bb_md_cur == NULL) {
-                               spin_lock(&sbi->s_md_lock);
-                               list_add(&md->list, &sbi->s_active_transaction);
-                               spin_unlock(&sbi->s_md_lock);
-                               /* protect buddy cache from being freed,
-                                * otherwise we'll refresh it from
-                                * on-disk bitmap and lose not-yet-available
-                                * blocks */
-                               page_cache_get(e4b->bd_buddy_page);
-                               page_cache_get(e4b->bd_bitmap_page);
-                               db->bb_md_cur = md;
-                               db->bb_tid = handle->h_transaction->t_tid;
-                               mb_debug("new md 0x%p for group %lu\n",
-                                               md, md->group);
-                       } else {
-                               kfree(md);
-                               md = db->bb_md_cur;
-                       }
+       rb_link_node(new_node, parent, n);
+       rb_insert_color(new_node, &db->bb_free_root);
+
+       /* Now try to see the extent can be merged to left and right */
+       node = rb_prev(new_node);
+       if (node) {
+               entry = rb_entry(node, struct ext4_free_data, node);
+               if (can_merge(entry, new_entry)) {
+                       new_entry->start_blk = entry->start_blk;
+                       new_entry->count += entry->count;
+                       rb_erase(node, &(db->bb_free_root));
+                       spin_lock(&sbi->s_md_lock);
+                       list_del(&entry->list);
+                       spin_unlock(&sbi->s_md_lock);
+                       kmem_cache_free(ext4_free_ext_cachep, entry);
                }
+       }
 
-               BUG_ON(md->num >= EXT4_BB_MAX_BLOCKS);
-               md->blocks[md->num] = block + i;
-               md->num++;
-               if (md->num == EXT4_BB_MAX_BLOCKS) {
-                       /* no more space, put full container on a sb's list */
-                       db->bb_md_cur = NULL;
+       node = rb_next(new_node);
+       if (node) {
+               entry = rb_entry(node, struct ext4_free_data, node);
+               if (can_merge(new_entry, entry)) {
+                       new_entry->count += entry->count;
+                       rb_erase(node, &(db->bb_free_root));
+                       spin_lock(&sbi->s_md_lock);
+                       list_del(&entry->list);
+                       spin_unlock(&sbi->s_md_lock);
+                       kmem_cache_free(ext4_free_ext_cachep, entry);
                }
        }
+       /* Add the extent to transaction's private list */
+       spin_lock(&sbi->s_md_lock);
+       list_add(&new_entry->list, &handle->h_transaction->t_private_list);
+       spin_unlock(&sbi->s_md_lock);
        ext4_unlock_group(sb, group);
        return 0;
 }
@@ -4500,8 +4509,6 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
 
        *freed = 0;
 
-       ext4_mb_poll_new_transaction(sb, handle);
-
        sbi = EXT4_SB(sb);
        es = EXT4_SB(sb)->s_es;
        if (block < le32_to_cpu(es->s_first_data_block) ||
index b3b4828f8b894c3cda416e0af366f2ecc890a284..b5dff1fff1e5b33af1c583f026b883fae74eca82 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
 #include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/marker.h>
 #include "ext4_jbd2.h"
 #include "ext4.h"
 #include "group.h"
 
 static struct kmem_cache *ext4_pspace_cachep;
 static struct kmem_cache *ext4_ac_cachep;
+static struct kmem_cache *ext4_free_ext_cachep;
 
-#ifdef EXT4_BB_MAX_BLOCKS
-#undef EXT4_BB_MAX_BLOCKS
-#endif
-#define EXT4_BB_MAX_BLOCKS     30
+struct ext4_free_data {
+       /* this links the free block information from group_info */
+       struct rb_node node;
 
-struct ext4_free_metadata {
-       ext4_group_t group;
-       unsigned short num;
-       ext4_grpblk_t  blocks[EXT4_BB_MAX_BLOCKS];
+       /* this links the free block information from ext4_sb_info */
        struct list_head list;
+
+       /* group which free block extent belongs */
+       ext4_group_t group;
+
+       /* free block extent */
+       ext4_grpblk_t start_blk;
+       ext4_grpblk_t count;
+
+       /* transaction which freed this extent */
+       tid_t   t_tid;
 };
 
 struct ext4_group_info {
        unsigned long   bb_state;
-       unsigned long   bb_tid;
-       struct ext4_free_metadata *bb_md_cur;
+       struct rb_root  bb_free_root;
        unsigned short  bb_first_free;
        unsigned short  bb_free;
        unsigned short  bb_fragments;
@@ -261,8 +269,6 @@ struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
 
 static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group);
-static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *);
-static void ext4_mb_free_committed_blocks(struct super_block *);
 static void ext4_mb_return_to_preallocation(struct inode *inode,
                                        struct ext4_buddy *e4b, sector_t block,
                                        int count);
@@ -270,6 +276,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *,
                        struct super_block *, struct ext4_prealloc_space *pa);
 static int ext4_mb_init_per_dev_proc(struct super_block *sb);
 static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
+static void release_blocks_on_commit(journal_t *journal, transaction_t *txn);
 
 
 static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)
index dea8f13c2fd98f3457c50faefd84be2c78399adf..9b2b2bc4ec175e2ac43bf43113866e1c5dde38e5 100644 (file)
@@ -374,66 +374,6 @@ void ext4_update_dynamic_rev(struct super_block *sb)
         */
 }
 
-int ext4_update_compat_feature(handle_t *handle,
-                                       struct super_block *sb, __u32 compat)
-{
-       int err = 0;
-       if (!EXT4_HAS_COMPAT_FEATURE(sb, compat)) {
-               err = ext4_journal_get_write_access(handle,
-                               EXT4_SB(sb)->s_sbh);
-               if (err)
-                       return err;
-               EXT4_SET_COMPAT_FEATURE(sb, compat);
-               sb->s_dirt = 1;
-               handle->h_sync = 1;
-               BUFFER_TRACE(EXT4_SB(sb)->s_sbh,
-                                       "call ext4_journal_dirty_met adata");
-               err = ext4_journal_dirty_metadata(handle,
-                               EXT4_SB(sb)->s_sbh);
-       }
-       return err;
-}
-
-int ext4_update_rocompat_feature(handle_t *handle,
-                                       struct super_block *sb, __u32 rocompat)
-{
-       int err = 0;
-       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, rocompat)) {
-               err = ext4_journal_get_write_access(handle,
-                               EXT4_SB(sb)->s_sbh);
-               if (err)
-                       return err;
-               EXT4_SET_RO_COMPAT_FEATURE(sb, rocompat);
-               sb->s_dirt = 1;
-               handle->h_sync = 1;
-               BUFFER_TRACE(EXT4_SB(sb)->s_sbh,
-                                       "call ext4_journal_dirty_met adata");
-               err = ext4_journal_dirty_metadata(handle,
-                               EXT4_SB(sb)->s_sbh);
-       }
-       return err;
-}
-
-int ext4_update_incompat_feature(handle_t *handle,
-                                       struct super_block *sb, __u32 incompat)
-{
-       int err = 0;
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, incompat)) {
-               err = ext4_journal_get_write_access(handle,
-                               EXT4_SB(sb)->s_sbh);
-               if (err)
-                       return err;
-               EXT4_SET_INCOMPAT_FEATURE(sb, incompat);
-               sb->s_dirt = 1;
-               handle->h_sync = 1;
-               BUFFER_TRACE(EXT4_SB(sb)->s_sbh,
-                                       "call ext4_journal_dirty_met adata");
-               err = ext4_journal_dirty_metadata(handle,
-                               EXT4_SB(sb)->s_sbh);
-       }
-       return err;
-}
-
 /*
  * Open the external journal device
  */
@@ -904,7 +844,7 @@ static const struct export_operations ext4_export_ops = {
 enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-       Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+       Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
        Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
        Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
@@ -915,7 +855,7 @@ enum {
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
        Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version,
-       Opt_mballoc, Opt_nomballoc, Opt_stripe, Opt_delalloc, Opt_nodelalloc,
+       Opt_stripe, Opt_delalloc, Opt_nodelalloc,
        Opt_inode_readahead_blks
 };
 
@@ -933,8 +873,6 @@ static const match_table_t tokens = {
        {Opt_err_panic, "errors=panic"},
        {Opt_err_ro, "errors=remount-ro"},
        {Opt_nouid32, "nouid32"},
-       {Opt_nocheck, "nocheck"},
-       {Opt_nocheck, "check=none"},
        {Opt_debug, "debug"},
        {Opt_oldalloc, "oldalloc"},
        {Opt_orlov, "orlov"},
@@ -973,8 +911,6 @@ static const match_table_t tokens = {
        {Opt_extents, "extents"},
        {Opt_noextents, "noextents"},
        {Opt_i_version, "i_version"},
-       {Opt_mballoc, "mballoc"},
-       {Opt_nomballoc, "nomballoc"},
        {Opt_stripe, "stripe=%u"},
        {Opt_resize, "resize"},
        {Opt_delalloc, "delalloc"},
@@ -1073,9 +1009,6 @@ static int parse_options(char *options, struct super_block *sb,
                case Opt_nouid32:
                        set_opt(sbi->s_mount_opt, NO_UID32);
                        break;
-               case Opt_nocheck:
-                       clear_opt(sbi->s_mount_opt, CHECK);
-                       break;
                case Opt_debug:
                        set_opt(sbi->s_mount_opt, DEBUG);
                        break;
@@ -1618,14 +1551,14 @@ static int ext4_check_descriptors(struct super_block *sb)
                if (block_bitmap < first_block || block_bitmap > last_block) {
                        printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
                               "Block bitmap for group %lu not in group "
-                              "(block %llu)!", i, block_bitmap);
+                              "(block %llu)!\n", i, block_bitmap);
                        return 0;
                }
                inode_bitmap = ext4_inode_bitmap(sb, gdp);
                if (inode_bitmap < first_block || inode_bitmap > last_block) {
                        printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
                               "Inode bitmap for group %lu not in group "
-                              "(block %llu)!", i, inode_bitmap);
+                              "(block %llu)!\n", i, inode_bitmap);
                        return 0;
                }
                inode_table = ext4_inode_table(sb, gdp);
@@ -1633,7 +1566,7 @@ static int ext4_check_descriptors(struct super_block *sb)
                    inode_table + sbi->s_itb_per_group - 1 > last_block) {
                        printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
                               "Inode table for group %lu not in group "
-                              "(block %llu)!", i, inode_table);
+                              "(block %llu)!\n", i, inode_table);
                        return 0;
                }
                spin_lock(sb_bgl_lock(sbi, i));
@@ -1778,13 +1711,13 @@ static void ext4_orphan_cleanup(struct super_block *sb,
  *
  * Note, this does *not* consider any metadata overhead for vfs i_blocks.
  */
-static loff_t ext4_max_size(int blkbits)
+static loff_t ext4_max_size(int blkbits, int has_huge_files)
 {
        loff_t res;
        loff_t upper_limit = MAX_LFS_FILESIZE;
 
        /* small i_blocks in vfs inode? */
-       if (sizeof(blkcnt_t) < sizeof(u64)) {
+       if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
                /*
                 * CONFIG_LSF is not enabled implies the inode
                 * i_block represent total blocks in 512 bytes
@@ -1814,7 +1747,7 @@ static loff_t ext4_max_size(int blkbits)
  * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
  * We need to be 1 filesystem block less than the 2^48 sector limit.
  */
-static loff_t ext4_max_bitmap_size(int bits)
+static loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
 {
        loff_t res = EXT4_NDIR_BLOCKS;
        int meta_blocks;
@@ -1827,11 +1760,11 @@ static loff_t ext4_max_bitmap_size(int bits)
         * total number of  512 bytes blocks of the file
         */
 
-       if (sizeof(blkcnt_t) < sizeof(u64)) {
+       if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
                /*
-                * CONFIG_LSF is not enabled implies the inode
-                * i_block represent total blocks in 512 bytes
-                * 32 == size of vfs inode i_blocks * 8
+                * !has_huge_files or CONFIG_LSF is not enabled
+                * implies the inode i_block represent total blocks in
+                * 512 bytes 32 == size of vfs inode i_blocks * 8
                 */
                upper_limit = (1LL << 32) - 1;
 
@@ -1940,7 +1873,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        int blocksize;
        int db_count;
        int i;
-       int needs_recovery;
+       int needs_recovery, has_huge_files;
        __le32 features;
        __u64 blocks_count;
        int err;
@@ -2081,7 +2014,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                       sb->s_id, le32_to_cpu(features));
                goto failed_mount;
        }
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+       has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb,
+                                   EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
+       if (has_huge_files) {
                /*
                 * Large file size enabled file system can only be
                 * mount if kernel is build with CONFIG_LSF
@@ -2131,8 +2066,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                }
        }
 
-       sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits);
-       sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits);
+       sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits,
+                                                     has_huge_files);
+       sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files);
 
        if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {
                sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE;
@@ -2456,6 +2392,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        "available.\n");
        }
 
+       if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
+               printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - "
+                               "requested data journaling mode\n");
+               clear_opt(sbi->s_mount_opt, DELALLOC);
+       } else if (test_opt(sb, DELALLOC))
+               printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
+
+       ext4_ext_init(sb);
+       err = ext4_mb_init(sb, needs_recovery);
+       if (err) {
+               printk(KERN_ERR "EXT4-fs: failed to initalize mballoc (%d)\n",
+                      err);
+               goto failed_mount4;
+       }
+
        /*
         * akpm: core read_super() calls in here with the superblock locked.
         * That deadlocks, because orphan cleanup needs to lock the superblock
@@ -2475,21 +2426,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
               test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered":
               "writeback");
 
-       if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
-               printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - "
-                               "requested data journaling mode\n");
-               clear_opt(sbi->s_mount_opt, DELALLOC);
-       } else if (test_opt(sb, DELALLOC))
-               printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
-
-       ext4_ext_init(sb);
-       err = ext4_mb_init(sb, needs_recovery);
-       if (err) {
-               printk(KERN_ERR "EXT4-fs: failed to initalize mballoc (%d)\n",
-                      err);
-               goto failed_mount4;
-       }
-
        lock_kernel();
        return 0;
 
index 0abe02c4242aa82d28aeef435a8f459a4ec729f5..8b119e16aa36d9970c881a5c41b0f98ff06962fa 100644 (file)
@@ -995,6 +995,9 @@ restart_loop:
        }
        spin_unlock(&journal->j_list_lock);
 
+       if (journal->j_commit_callback)
+               journal->j_commit_callback(journal, commit_transaction);
+
        trace_mark(jbd2_end_commit, "dev %s transaction %d head %d",
                   journal->j_devname, commit_transaction->t_tid,
                   journal->j_tail_sequence);
index e5d540588fa9609296f446c232278202bd1f2d6b..39b7805a599a79fd80c0150073cbf0f473fe8bcf 100644 (file)
@@ -52,6 +52,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
        transaction->t_expires = jiffies + journal->j_commit_interval;
        spin_lock_init(&transaction->t_handle_lock);
        INIT_LIST_HEAD(&transaction->t_inode_list);
+       INIT_LIST_HEAD(&transaction->t_private_list);
 
        /* Set up the commit timer for the new transaction. */
        journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
index 38d3c6b8276aec19755d1037378ba34f7e7ab80a..f46ba4b57da4aedda3e3c4ac170056474bf8c102 100644 (file)
@@ -36,7 +36,6 @@
 #ifndef _DRM_H_
 #define _DRM_H_
 
-#if defined(__linux__)
 #if defined(__KERNEL__)
 #endif
 #include <asm/ioctl.h>         /* For _IO* macros */
 #define DRM_IOC_WRITE          _IOC_WRITE
 #define DRM_IOC_READWRITE      _IOC_READ|_IOC_WRITE
 #define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-#if defined(__FreeBSD__) && defined(IN_MODULE)
-/* Prevent name collision when including sys/ioccom.h */
-#undef ioctl
-#include <sys/ioccom.h>
-#define ioctl(a,b,c)           xf86ioctl(a,b,c)
-#else
-#include <sys/ioccom.h>
-#endif                         /* __FreeBSD__ && xf86ioctl */
-#define DRM_IOCTL_NR(n)                ((n) & 0xff)
-#define DRM_IOC_VOID           IOC_VOID
-#define DRM_IOC_READ           IOC_OUT
-#define DRM_IOC_WRITE          IOC_IN
-#define DRM_IOC_READWRITE      IOC_INOUT
-#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
-#endif
 
 #define DRM_MAJOR       226
 #define DRM_MAX_MINOR   15
@@ -471,6 +454,7 @@ struct drm_irq_busid {
 enum drm_vblank_seq_type {
        _DRM_VBLANK_ABSOLUTE = 0x0,     /**< Wait for specific vblank sequence number */
        _DRM_VBLANK_RELATIVE = 0x1,     /**< Wait for given number of vblanks */
+       _DRM_VBLANK_FLIP = 0x8000000,   /**< Scheduled buffer swap should flip */
        _DRM_VBLANK_NEXTONMISS = 0x10000000,    /**< If missed, wait for next vblank */
        _DRM_VBLANK_SECONDARY = 0x20000000,     /**< Secondary display controller */
        _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
@@ -503,6 +487,19 @@ union drm_wait_vblank {
        struct drm_wait_vblank_reply reply;
 };
 
+#define _DRM_PRE_MODESET 1
+#define _DRM_POST_MODESET 2
+
+/**
+ * DRM_IOCTL_MODESET_CTL ioctl argument type
+ *
+ * \sa drmModesetCtl().
+ */
+struct drm_modeset_ctl {
+       uint32_t crtc;
+       uint32_t cmd;
+};
+
 /**
  * DRM_IOCTL_AGP_ENABLE ioctl argument type.
  *
@@ -573,6 +570,34 @@ struct drm_set_version {
        int drm_dd_minor;
 };
 
+/** DRM_IOCTL_GEM_CLOSE ioctl argument type */
+struct drm_gem_close {
+       /** Handle of the object to be closed. */
+       uint32_t handle;
+       uint32_t pad;
+};
+
+/** DRM_IOCTL_GEM_FLINK ioctl argument type */
+struct drm_gem_flink {
+       /** Handle for the object being named */
+       uint32_t handle;
+
+       /** Returned global name */
+       uint32_t name;
+};
+
+/** DRM_IOCTL_GEM_OPEN ioctl argument type */
+struct drm_gem_open {
+       /** Name of object being opened */
+       uint32_t name;
+
+       /** Returned handle for the object */
+       uint32_t handle;
+
+       /** Returned size of the object */
+       uint64_t size;
+};
+
 #define DRM_IOCTL_BASE                 'd'
 #define DRM_IO(nr)                     _IO(DRM_IOCTL_BASE,nr)
 #define DRM_IOR(nr,type)               _IOR(DRM_IOCTL_BASE,nr,type)
@@ -587,6 +612,10 @@ struct drm_set_version {
 #define DRM_IOCTL_GET_CLIENT            DRM_IOWR(0x05, struct drm_client)
 #define DRM_IOCTL_GET_STATS             DRM_IOR( 0x06, struct drm_stats)
 #define DRM_IOCTL_SET_VERSION          DRM_IOWR(0x07, struct drm_set_version)
+#define DRM_IOCTL_MODESET_CTL           DRM_IOW(0x08, struct drm_modeset_ctl)
+#define DRM_IOCTL_GEM_CLOSE            DRM_IOW (0x09, struct drm_gem_close)
+#define DRM_IOCTL_GEM_FLINK            DRM_IOWR(0x0a, struct drm_gem_flink)
+#define DRM_IOCTL_GEM_OPEN             DRM_IOWR(0x0b, struct drm_gem_open)
 
 #define DRM_IOCTL_SET_UNIQUE           DRM_IOW( 0x10, struct drm_unique)
 #define DRM_IOCTL_AUTH_MAGIC           DRM_IOW( 0x11, struct drm_auth)
index 1c1b13e29223a6e170372f4911e91af3a2021527..59c796b46ee7a5b7a6b05e135b539d079744e360 100644 (file)
@@ -104,6 +104,7 @@ struct drm_device;
 #define DRIVER_DMA_QUEUE   0x200
 #define DRIVER_FB_DMA      0x400
 #define DRIVER_IRQ_VBL2    0x800
+#define DRIVER_GEM         0x1000
 
 /***********************************************************************/
 /** \name Begin the DRM... */
@@ -387,6 +388,10 @@ struct drm_file {
        struct drm_minor *minor;
        int remove_auth_on_close;
        unsigned long lock_count;
+       /** Mapping of mm object handles to object pointers. */
+       struct idr object_idr;
+       /** Lock for synchronization of access to object_idr. */
+       spinlock_t table_lock;
        struct file *filp;
        void *driver_priv;
 };
@@ -557,6 +562,56 @@ struct drm_ati_pcigart_info {
        int table_size;
 };
 
+/**
+ * This structure defines the drm_mm memory object, which will be used by the
+ * DRM for its buffer objects.
+ */
+struct drm_gem_object {
+       /** Reference count of this object */
+       struct kref refcount;
+
+       /** Handle count of this object. Each handle also holds a reference */
+       struct kref handlecount;
+
+       /** Related drm device */
+       struct drm_device *dev;
+
+       /** File representing the shmem storage */
+       struct file *filp;
+
+       /**
+        * Size of the object, in bytes.  Immutable over the object's
+        * lifetime.
+        */
+       size_t size;
+
+       /**
+        * Global name for this object, starts at 1. 0 means unnamed.
+        * Access is covered by the object_name_lock in the related drm_device
+        */
+       int name;
+
+       /**
+        * Memory domains. These monitor which caches contain read/write data
+        * related to the object. When transitioning from one set of domains
+        * to another, the driver is called to ensure that caches are suitably
+        * flushed and invalidated
+        */
+       uint32_t read_domains;
+       uint32_t write_domain;
+
+       /**
+        * While validating an exec operation, the
+        * new read/write domain values are computed here.
+        * They will be transferred to the above values
+        * at the point that any cache flushing occurs
+        */
+       uint32_t pending_read_domains;
+       uint32_t pending_write_domain;
+
+       void *driver_private;
+};
+
 /**
  * DRM driver structure. This structure represent the common code for
  * a family of cards. There will one drm_device for each card present
@@ -580,10 +635,53 @@ struct drm_driver {
        int (*kernel_context_switch) (struct drm_device *dev, int old,
                                      int new);
        void (*kernel_context_switch_unlock) (struct drm_device *dev);
-       int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence);
-       int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence);
        int (*dri_library_name) (struct drm_device *dev, char *buf);
 
+       /**
+        * get_vblank_counter - get raw hardware vblank counter
+        * @dev: DRM device
+        * @crtc: counter to fetch
+        *
+        * Driver callback for fetching a raw hardware vblank counter
+        * for @crtc.  If a device doesn't have a hardware counter, the
+        * driver can simply return the value of drm_vblank_count and
+        * make the enable_vblank() and disable_vblank() hooks into no-ops,
+        * leaving interrupts enabled at all times.
+        *
+        * Wraparound handling and loss of events due to modesetting is dealt
+        * with in the DRM core code.
+        *
+        * RETURNS
+        * Raw vblank counter value.
+        */
+       u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
+
+       /**
+        * enable_vblank - enable vblank interrupt events
+        * @dev: DRM device
+        * @crtc: which irq to enable
+        *
+        * Enable vblank interrupts for @crtc.  If the device doesn't have
+        * a hardware vblank counter, this routine should be a no-op, since
+        * interrupts will have to stay on to keep the count accurate.
+        *
+        * RETURNS
+        * Zero on success, appropriate errno if the given @crtc's vblank
+        * interrupt cannot be enabled.
+        */
+       int (*enable_vblank) (struct drm_device *dev, int crtc);
+
+       /**
+        * disable_vblank - disable vblank interrupt events
+        * @dev: DRM device
+        * @crtc: which irq to enable
+        *
+        * Disable vblank interrupts for @crtc.  If the device doesn't have
+        * a hardware vblank counter, this routine should be a no-op, since
+        * interrupts will have to stay on to keep the count accurate.
+        */
+       void (*disable_vblank) (struct drm_device *dev, int crtc);
+
        /**
         * Called by \c drm_device_is_agp.  Typically used to determine if a
         * card is really attached to AGP or not.
@@ -601,7 +699,7 @@ struct drm_driver {
 
        irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
        void (*irq_preinstall) (struct drm_device *dev);
-       void (*irq_postinstall) (struct drm_device *dev);
+       int (*irq_postinstall) (struct drm_device *dev);
        void (*irq_uninstall) (struct drm_device *dev);
        void (*reclaim_buffers) (struct drm_device *dev,
                                 struct drm_file * file_priv);
@@ -614,6 +712,18 @@ struct drm_driver {
        void (*set_version) (struct drm_device *dev,
                             struct drm_set_version *sv);
 
+       int (*proc_init)(struct drm_minor *minor);
+       void (*proc_cleanup)(struct drm_minor *minor);
+
+       /**
+        * Driver-specific constructor for drm_gem_objects, to set up
+        * obj->driver_private.
+        *
+        * Returns 0 on success.
+        */
+       int (*gem_init_object) (struct drm_gem_object *obj);
+       void (*gem_free_object) (struct drm_gem_object *obj);
+
        int major;
        int minor;
        int patchlevel;
@@ -714,7 +824,6 @@ struct drm_device {
 
        /** \name Context support */
        /*@{ */
-       int irq;                        /**< Interrupt used by board */
        int irq_enabled;                /**< True if irq handler is enabled */
        __volatile__ long context_flag; /**< Context swapping flag */
        __volatile__ long interrupt_flag; /**< Interruption handler flag */
@@ -730,13 +839,28 @@ struct drm_device {
        /** \name VBLANK IRQ support */
        /*@{ */
 
-       wait_queue_head_t vbl_queue;    /**< VBLANK wait queue */
-       atomic_t vbl_received;
-       atomic_t vbl_received2;         /**< number of secondary VBLANK interrupts */
+       /*
+        * At load time, disabling the vblank interrupt won't be allowed since
+        * old clients may not call the modeset ioctl and therefore misbehave.
+        * Once the modeset ioctl *has* been called though, we can safely
+        * disable them when unused.
+        */
+       int vblank_disable_allowed;
+
+       wait_queue_head_t *vbl_queue;   /**< VBLANK wait queue */
+       atomic_t *_vblank_count;        /**< number of VBLANK interrupts (driver must alloc the right number of counters) */
        spinlock_t vbl_lock;
-       struct list_head vbl_sigs;              /**< signal list to send on VBLANK */
-       struct list_head vbl_sigs2;     /**< signals to send on secondary VBLANK */
-       unsigned int vbl_pending;
+       struct list_head *vbl_sigs;     /**< signal list to send on VBLANK */
+       atomic_t vbl_signal_pending;    /* number of signals pending on all crtcs*/
+       atomic_t *vblank_refcount;      /* number of users of vblank interruptsper crtc */
+       u32 *last_vblank;               /* protected by dev->vbl_lock, used */
+                                       /* for wraparound handling */
+       int *vblank_enabled;            /* so we don't call enable more than
+                                          once per disable */
+       int *vblank_inmodeset;          /* Display driver is setting mode */
+       struct timer_list vblank_disable_timer;
+
+       u32 max_vblank_count;           /**< size of vblank counter register */
        spinlock_t tasklet_lock;        /**< For drm_locked_tasklet */
        void (*locked_tasklet_func)(struct drm_device *dev);
 
@@ -757,6 +881,7 @@ struct drm_device {
        struct pci_controller *hose;
 #endif
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
+       int num_crtcs;                  /**< Number of CRTCs on this device */
        void *dev_private;              /**< device private data */
        struct drm_sigdata sigdata;        /**< For block_all_signals */
        sigset_t sigmask;
@@ -771,8 +896,29 @@ struct drm_device {
        spinlock_t drw_lock;
        struct idr drw_idr;
        /*@} */
+
+       /** \name GEM information */
+       /*@{ */
+       spinlock_t object_name_lock;
+       struct idr object_name_idr;
+       atomic_t object_count;
+       atomic_t object_memory;
+       atomic_t pin_count;
+       atomic_t pin_memory;
+       atomic_t gtt_count;
+       atomic_t gtt_memory;
+       uint32_t gtt_total;
+       uint32_t invalidate_domains;    /* domains pending invalidation */
+       uint32_t flush_domains;         /* domains pending flush */
+       /*@} */
+
 };
 
+static inline int drm_dev_to_irq(struct drm_device *dev)
+{
+       return dev->pdev->irq;
+}
+
 static __inline__ int drm_core_check_feature(struct drm_device *dev,
                                             int feature)
 {
@@ -867,6 +1013,11 @@ extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
 extern DRM_AGP_MEM *drm_alloc_agp(struct drm_device *dev, int pages, u32 type);
 extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
 extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
+extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
+                                      struct page **pages,
+                                      unsigned long num_pages,
+                                      uint32_t gtt_offset,
+                                      uint32_t type);
 extern int drm_unbind_agp(DRM_AGP_MEM * handle);
 
                                /* Misc. IOCTL support (drm_ioctl.h) */
@@ -929,6 +1080,9 @@ extern int drm_getmagic(struct drm_device *dev, void *data,
 extern int drm_authmagic(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 
+/* Cache management (drm_cache.c) */
+void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
+
                                /* Locking IOCTL support (drm_lock.h) */
 extern int drm_lock(struct drm_device *dev, void *data,
                    struct drm_file *file_priv);
@@ -985,15 +1139,25 @@ extern void drm_core_reclaim_buffers(struct drm_device *dev,
 extern int drm_control(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
 extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
+extern int drm_irq_install(struct drm_device *dev);
 extern int drm_irq_uninstall(struct drm_device *dev);
 extern void drm_driver_irq_preinstall(struct drm_device *dev);
 extern void drm_driver_irq_postinstall(struct drm_device *dev);
 extern void drm_driver_irq_uninstall(struct drm_device *dev);
 
+extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
 extern int drm_wait_vblank(struct drm_device *dev, void *data,
-                          struct drm_file *file_priv);
+                          struct drm_file *filp);
 extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
-extern void drm_vbl_send_signals(struct drm_device *dev);
+extern void drm_locked_tasklet(struct drm_device *dev,
+                              void(*func)(struct drm_device *));
+extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
+extern void drm_handle_vblank(struct drm_device *dev, int crtc);
+extern int drm_vblank_get(struct drm_device *dev, int crtc);
+extern void drm_vblank_put(struct drm_device *dev, int crtc);
+/* Modesetting support */
+extern int drm_modeset_ctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
 extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
 
                                /* AGP/GART support (drm_agpsupport.h) */
@@ -1026,6 +1190,7 @@ extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size
 extern int drm_agp_free_memory(DRM_AGP_MEM * handle);
 extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start);
 extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
+extern void drm_agp_chipset_flush(struct drm_device *dev);
 
                                /* Stub support (drm_stub.h) */
 extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
@@ -1088,6 +1253,66 @@ extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
 extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
 extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
 
+/* Graphics Execution Manager library functions (drm_gem.c) */
+int drm_gem_init(struct drm_device *dev);
+void drm_gem_object_free(struct kref *kref);
+struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
+                                           size_t size);
+void drm_gem_object_handle_free(struct kref *kref);
+
+static inline void
+drm_gem_object_reference(struct drm_gem_object *obj)
+{
+       kref_get(&obj->refcount);
+}
+
+static inline void
+drm_gem_object_unreference(struct drm_gem_object *obj)
+{
+       if (obj == NULL)
+               return;
+
+       kref_put(&obj->refcount, drm_gem_object_free);
+}
+
+int drm_gem_handle_create(struct drm_file *file_priv,
+                         struct drm_gem_object *obj,
+                         int *handlep);
+
+static inline void
+drm_gem_object_handle_reference(struct drm_gem_object *obj)
+{
+       drm_gem_object_reference(obj);
+       kref_get(&obj->handlecount);
+}
+
+static inline void
+drm_gem_object_handle_unreference(struct drm_gem_object *obj)
+{
+       if (obj == NULL)
+               return;
+
+       /*
+        * Must bump handle count first as this may be the last
+        * ref, in which case the object would disappear before we
+        * checked for a name
+        */
+       kref_put(&obj->handlecount, drm_gem_object_handle_free);
+       drm_gem_object_unreference(obj);
+}
+
+struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev,
+                                            struct drm_file *filp,
+                                            int handle);
+int drm_gem_close_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_gem_flink_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_gem_open_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
+void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
+
 extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
 extern void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev);
 extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
index 135bd19499fcc82f8d41e9b6216f9e70205ab814..da04109741e83dfe0c45ed4456a97d78c4e6f3a8 100644 (file)
        {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
        {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
        {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
        {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
        {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-       {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
-       {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+       {0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+       {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
        {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
        {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
-       {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
        {0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x796c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x796d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x796e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
+       {0x1002, 0x796f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
        {0, 0, 0}
 
 #define r128_PCI_IDS \
index 05c66cf03a9eb02a0da22304ab4d07d95209b16b..eb4b35031a55601ac333490650a4a48082b6faca 100644 (file)
@@ -143,6 +143,22 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GET_VBLANK_PIPE       0x0e
 #define DRM_I915_VBLANK_SWAP   0x0f
 #define DRM_I915_HWS_ADDR      0x11
+#define DRM_I915_GEM_INIT      0x13
+#define DRM_I915_GEM_EXECBUFFER        0x14
+#define DRM_I915_GEM_PIN       0x15
+#define DRM_I915_GEM_UNPIN     0x16
+#define DRM_I915_GEM_BUSY      0x17
+#define DRM_I915_GEM_THROTTLE  0x18
+#define DRM_I915_GEM_ENTERVT   0x19
+#define DRM_I915_GEM_LEAVEVT   0x1a
+#define DRM_I915_GEM_CREATE    0x1b
+#define DRM_I915_GEM_PREAD     0x1c
+#define DRM_I915_GEM_PWRITE    0x1d
+#define DRM_I915_GEM_MMAP      0x1e
+#define DRM_I915_GEM_SET_DOMAIN        0x1f
+#define DRM_I915_GEM_SW_FINISH 0x20
+#define DRM_I915_GEM_SET_TILING        0x21
+#define DRM_I915_GEM_GET_TILING        0x22
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -160,6 +176,20 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
 #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
 #define DRM_IOCTL_I915_VBLANK_SWAP     DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
+#define DRM_IOCTL_I915_GEM_PIN         DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
+#define DRM_IOCTL_I915_GEM_UNPIN       DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
+#define DRM_IOCTL_I915_GEM_BUSY                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
+#define DRM_IOCTL_I915_GEM_THROTTLE    DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
+#define DRM_IOCTL_I915_GEM_ENTERVT     DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
+#define DRM_IOCTL_I915_GEM_LEAVEVT     DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
+#define DRM_IOCTL_I915_GEM_CREATE      DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
+#define DRM_IOCTL_I915_GEM_PREAD       DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
+#define DRM_IOCTL_I915_GEM_PWRITE      DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
+#define DRM_IOCTL_I915_GEM_MMAP                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
+#define DRM_IOCTL_I915_GEM_SET_DOMAIN  DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain)
+#define DRM_IOCTL_I915_GEM_SW_FINISH   DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish)
+#define DRM_IOCTL_I915_GEM_SET_TILING  DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
+#define DRM_IOCTL_I915_GEM_GET_TILING  DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -200,6 +230,8 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_IRQ_ACTIVE            1
 #define I915_PARAM_ALLOW_BATCHBUFFER     2
 #define I915_PARAM_LAST_DISPATCH         3
+#define I915_PARAM_CHIPSET_ID            4
+#define I915_PARAM_HAS_GEM               5
 
 typedef struct drm_i915_getparam {
        int param;
@@ -267,4 +299,305 @@ typedef struct drm_i915_hws_addr {
        uint64_t addr;
 } drm_i915_hws_addr_t;
 
+struct drm_i915_gem_init {
+       /**
+        * Beginning offset in the GTT to be managed by the DRM memory
+        * manager.
+        */
+       uint64_t gtt_start;
+       /**
+        * Ending offset in the GTT to be managed by the DRM memory
+        * manager.
+        */
+       uint64_t gtt_end;
+};
+
+struct drm_i915_gem_create {
+       /**
+        * Requested size for the object.
+        *
+        * The (page-aligned) allocated size for the object will be returned.
+        */
+       uint64_t size;
+       /**
+        * Returned handle for the object.
+        *
+        * Object handles are nonzero.
+        */
+       uint32_t handle;
+       uint32_t pad;
+};
+
+struct drm_i915_gem_pread {
+       /** Handle for the object being read. */
+       uint32_t handle;
+       uint32_t pad;
+       /** Offset into the object to read from */
+       uint64_t offset;
+       /** Length of data to read */
+       uint64_t size;
+       /**
+        * Pointer to write the data into.
+        *
+        * This is a fixed-size type for 32/64 compatibility.
+        */
+       uint64_t data_ptr;
+};
+
+struct drm_i915_gem_pwrite {
+       /** Handle for the object being written to. */
+       uint32_t handle;
+       uint32_t pad;
+       /** Offset into the object to write to */
+       uint64_t offset;
+       /** Length of data to write */
+       uint64_t size;
+       /**
+        * Pointer to read the data from.
+        *
+        * This is a fixed-size type for 32/64 compatibility.
+        */
+       uint64_t data_ptr;
+};
+
+struct drm_i915_gem_mmap {
+       /** Handle for the object being mapped. */
+       uint32_t handle;
+       uint32_t pad;
+       /** Offset in the object to map. */
+       uint64_t offset;
+       /**
+        * Length of data to map.
+        *
+        * The value will be page-aligned.
+        */
+       uint64_t size;
+       /**
+        * Returned pointer the data was mapped at.
+        *
+        * This is a fixed-size type for 32/64 compatibility.
+        */
+       uint64_t addr_ptr;
+};
+
+struct drm_i915_gem_set_domain {
+       /** Handle for the object */
+       uint32_t handle;
+
+       /** New read domains */
+       uint32_t read_domains;
+
+       /** New write domain */
+       uint32_t write_domain;
+};
+
+struct drm_i915_gem_sw_finish {
+       /** Handle for the object */
+       uint32_t handle;
+};
+
+struct drm_i915_gem_relocation_entry {
+       /**
+        * Handle of the buffer being pointed to by this relocation entry.
+        *
+        * It's appealing to make this be an index into the mm_validate_entry
+        * list to refer to the buffer, but this allows the driver to create
+        * a relocation list for state buffers and not re-write it per
+        * exec using the buffer.
+        */
+       uint32_t target_handle;
+
+       /**
+        * Value to be added to the offset of the target buffer to make up
+        * the relocation entry.
+        */
+       uint32_t delta;
+
+       /** Offset in the buffer the relocation entry will be written into */
+       uint64_t offset;
+
+       /**
+        * Offset value of the target buffer that the relocation entry was last
+        * written as.
+        *
+        * If the buffer has the same offset as last time, we can skip syncing
+        * and writing the relocation.  This value is written back out by
+        * the execbuffer ioctl when the relocation is written.
+        */
+       uint64_t presumed_offset;
+
+       /**
+        * Target memory domains read by this operation.
+        */
+       uint32_t read_domains;
+
+       /**
+        * Target memory domains written by this operation.
+        *
+        * Note that only one domain may be written by the whole
+        * execbuffer operation, so that where there are conflicts,
+        * the application will get -EINVAL back.
+        */
+       uint32_t write_domain;
+};
+
+/** @{
+ * Intel memory domains
+ *
+ * Most of these just align with the various caches in
+ * the system and are used to flush and invalidate as
+ * objects end up cached in different domains.
+ */
+/** CPU cache */
+#define I915_GEM_DOMAIN_CPU            0x00000001
+/** Render cache, used by 2D and 3D drawing */
+#define I915_GEM_DOMAIN_RENDER         0x00000002
+/** Sampler cache, used by texture engine */
+#define I915_GEM_DOMAIN_SAMPLER                0x00000004
+/** Command queue, used to load batch buffers */
+#define I915_GEM_DOMAIN_COMMAND                0x00000008
+/** Instruction cache, used by shader programs */
+#define I915_GEM_DOMAIN_INSTRUCTION    0x00000010
+/** Vertex address cache */
+#define I915_GEM_DOMAIN_VERTEX         0x00000020
+/** GTT domain - aperture and scanout */
+#define I915_GEM_DOMAIN_GTT            0x00000040
+/** @} */
+
+struct drm_i915_gem_exec_object {
+       /**
+        * User's handle for a buffer to be bound into the GTT for this
+        * operation.
+        */
+       uint32_t handle;
+
+       /** Number of relocations to be performed on this buffer */
+       uint32_t relocation_count;
+       /**
+        * Pointer to array of struct drm_i915_gem_relocation_entry containing
+        * the relocations to be performed in this buffer.
+        */
+       uint64_t relocs_ptr;
+
+       /** Required alignment in graphics aperture */
+       uint64_t alignment;
+
+       /**
+        * Returned value of the updated offset of the object, for future
+        * presumed_offset writes.
+        */
+       uint64_t offset;
+};
+
+struct drm_i915_gem_execbuffer {
+       /**
+        * List of buffers to be validated with their relocations to be
+        * performend on them.
+        *
+        * This is a pointer to an array of struct drm_i915_gem_validate_entry.
+        *
+        * These buffers must be listed in an order such that all relocations
+        * a buffer is performing refer to buffers that have already appeared
+        * in the validate list.
+        */
+       uint64_t buffers_ptr;
+       uint32_t buffer_count;
+
+       /** Offset in the batchbuffer to start execution from. */
+       uint32_t batch_start_offset;
+       /** Bytes used in batchbuffer from batch_start_offset */
+       uint32_t batch_len;
+       uint32_t DR1;
+       uint32_t DR4;
+       uint32_t num_cliprects;
+       /** This is a struct drm_clip_rect *cliprects */
+       uint64_t cliprects_ptr;
+};
+
+struct drm_i915_gem_pin {
+       /** Handle of the buffer to be pinned. */
+       uint32_t handle;
+       uint32_t pad;
+
+       /** alignment required within the aperture */
+       uint64_t alignment;
+
+       /** Returned GTT offset of the buffer. */
+       uint64_t offset;
+};
+
+struct drm_i915_gem_unpin {
+       /** Handle of the buffer to be unpinned. */
+       uint32_t handle;
+       uint32_t pad;
+};
+
+struct drm_i915_gem_busy {
+       /** Handle of the buffer to check for busy */
+       uint32_t handle;
+
+       /** Return busy status (1 if busy, 0 if idle) */
+       uint32_t busy;
+};
+
+#define I915_TILING_NONE       0
+#define I915_TILING_X          1
+#define I915_TILING_Y          2
+
+#define I915_BIT_6_SWIZZLE_NONE                0
+#define I915_BIT_6_SWIZZLE_9           1
+#define I915_BIT_6_SWIZZLE_9_10                2
+#define I915_BIT_6_SWIZZLE_9_11                3
+#define I915_BIT_6_SWIZZLE_9_10_11     4
+/* Not seen by userland */
+#define I915_BIT_6_SWIZZLE_UNKNOWN     5
+
+struct drm_i915_gem_set_tiling {
+       /** Handle of the buffer to have its tiling state updated */
+       uint32_t handle;
+
+       /**
+        * Tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
+        * I915_TILING_Y).
+        *
+        * This value is to be set on request, and will be updated by the
+        * kernel on successful return with the actual chosen tiling layout.
+        *
+        * The tiling mode may be demoted to I915_TILING_NONE when the system
+        * has bit 6 swizzling that can't be managed correctly by GEM.
+        *
+        * Buffer contents become undefined when changing tiling_mode.
+        */
+       uint32_t tiling_mode;
+
+       /**
+        * Stride in bytes for the object when in I915_TILING_X or
+        * I915_TILING_Y.
+        */
+       uint32_t stride;
+
+       /**
+        * Returned address bit 6 swizzling required for CPU access through
+        * mmap mapping.
+        */
+       uint32_t swizzle_mode;
+};
+
+struct drm_i915_gem_get_tiling {
+       /** Handle of the buffer to get tiling state for. */
+       uint32_t handle;
+
+       /**
+        * Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
+        * I915_TILING_Y).
+        */
+       uint32_t tiling_mode;
+
+       /**
+        * Returned address bit 6 swizzling required for CPU access through
+        * mmap mapping.
+        */
+       uint32_t swizzle_mode;
+};
+
 #endif                         /* _I915_DRM_H_ */
index 6e4ace27027691fa42c4920bcf5bf4e60e12494d..79a8ed8e6a7d6c02517c7407019b0302806035c1 100644 (file)
@@ -166,6 +166,7 @@ typedef enum fe_modulation {
        VSB_16,
        PSK_8,
        APSK_16,
+       APSK_32,
        DQPSK,
 } fe_modulation_t;
 
@@ -295,6 +296,7 @@ typedef enum fe_delivery_system {
        SYS_DVBC_ANNEX_AC,
        SYS_DVBC_ANNEX_B,
        SYS_DVBT,
+       SYS_DSS,
        SYS_DVBS,
        SYS_DVBS2,
        SYS_DVBH,
index 493435bcdbe52189c9e55fab95b03a614447a799..01d67ba9e985c86c3f98a8a5c2ff90f12ed364d1 100644 (file)
@@ -60,7 +60,7 @@
 #define I2C_DRIVERID_WM8775    69      /* wm8775 audio processor       */
 #define I2C_DRIVERID_CS53L32A  70      /* cs53l32a audio processor     */
 #define I2C_DRIVERID_CX25840   71      /* cx2584x video encoder        */
-#define I2C_DRIVERID_SAA7127   72      /* saa7124 video encoder        */
+#define I2C_DRIVERID_SAA7127   72      /* saa7127 video encoder        */
 #define I2C_DRIVERID_SAA711X   73      /* saa711x video encoders       */
 #define I2C_DRIVERID_AKITAIOEXP        74      /* IO Expander on Sharp SL-C1000 */
 #define I2C_DRIVERID_INFRARED  75      /* I2C InfraRed on Video boards */
index 463d6f10b64f7ffaea2f4fc13e57bc2ca4a95c8e..c7d106ef22e2f535f2c78f470a300b5fb7e8b930 100644 (file)
@@ -641,6 +641,11 @@ struct transaction_s
         */
        int t_handle_count;
 
+       /*
+        * For use by the filesystem to store fs-specific data
+        * structures associated with the transaction
+        */
+       struct list_head        t_private_list;
 };
 
 struct transaction_run_stats_s {
@@ -935,6 +940,10 @@ struct journal_s
 
        pid_t                   j_last_sync_writer;
 
+       /* This function is called when a transaction is closed */
+       void                    (*j_commit_callback)(journal_t *,
+                                                    transaction_t *);
+
        /*
         * Journal statistics
         */
index 12b15c561a1f1ca3dcfe91c9f64e439857fc6bd6..e585657e9831afe4c5d36e5f52fabd1246b03ab1 100644 (file)
@@ -63,7 +63,15 @@ struct writeback_control {
        unsigned for_writepages:1;      /* This is a writepages() call */
        unsigned range_cyclic:1;        /* range_start is cyclic */
        unsigned more_io:1;             /* more io to be dispatched */
-       unsigned range_cont:1;
+       /*
+        * write_cache_pages() won't update wbc->nr_to_write and
+        * mapping->writeback_index if no_nrwrite_index_update
+        * is set.  write_cache_pages() may write more than we
+        * requested and we want to make sure nr_to_write and
+        * writeback_index are updated in a consistent manner
+        * so we use a single control to update them
+        */
+       unsigned no_nrwrite_index_update:1;
 };
 
 /*
index 851f1822098438ac1f55bcc21fd6a2eb7439a743..1d092b4678aa508c7b3aa19e10105f6b228ec3d3 100644 (file)
@@ -1,3 +1,13 @@
+/*
+ * Generic Platform Camera Driver Header
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * 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.
+ */
+
 #ifndef __SOC_CAMERA_H__
 #define __SOC_CAMERA_H__
 
@@ -9,6 +19,7 @@ struct soc_camera_platform_info {
        unsigned long format_depth;
        struct v4l2_pix_format format;
        unsigned long bus_param;
+       void (*power)(int);
        int (*set_capture)(struct soc_camera_platform_info *info, int enable);
 };
 
index 67c1f514d0e297884a914b2c5c065f5996deea78..7d4e2db780767709579367fe6e50cb15ee825c85 100644 (file)
 #define TUNER_TEA5761                  75      /* Only FM Radio Tuner */
 #define TUNER_XC5000                   76      /* Xceive Silicon Tuner */
 #define TUNER_TCL_MF02GIP_5N           77      /* TCL MF02GIP_5N */
+#define TUNER_PHILIPS_FMD1216MEX_MK3   78
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
index 975ffbf4e2c537a93cd6e9fc50de12df0c1a104b..e65dd9d84e8b1ee80f6f262c930fa0369ca743ac 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* NOTE: the full version of this header is in the v4l-dvb repository
+ * and allows v4l i2c drivers to be compiled on older kernels as well.
+ * The version of this header as it appears in the kernel is a stripped
+ * version (without all the backwards compatibility stuff) and so it
+ * looks a bit odd.
+ *
+ * If you look at the full version then you will understand the reason
+ * for introducing this header since you really don't want to have all
+ * the tricky backwards compatibility code in each and every i2c driver.
+ */
+
 struct v4l2_i2c_driver_data {
        const char * const name;
        int driverid;
index 40ecef29801d3be1e5902cea4aee4a823e87f158..efdc8bf27f87cc3aa09ca51e1e41459d1434d485 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* NOTE: the full version of this header is in the v4l-dvb repository
+ * and allows v4l i2c drivers to be compiled on older kernels as well.
+ * The version of this header as it appears in the kernel is a stripped
+ * version (without all the backwards compatibility stuff) and so it
+ * looks a bit odd.
+ *
+ * If you look at the full version then you will understand the reason
+ * for introducing this header since you really don't want to have all
+ * the tricky backwards compatibility code in each and every i2c driver.
+ */
+
 #ifndef __V4L2_I2C_DRV_H__
 #define __V4L2_I2C_DRV_H__
 
index b777486963292443ebd9ed9e07b732d34a997ffe..80471c2b63436d3dc45a8cb730782552b8849f55 100644 (file)
@@ -16,7 +16,6 @@ struct videobuf_dvb {
        int                        nfeeds;
 
        /* videobuf_dvb_(un)register manges this */
-       struct dvb_adapter         adapter;
        struct dvb_demux           demux;
        struct dmxdev              dmxdev;
        struct dmx_frontend        fe_hw;
@@ -24,12 +23,34 @@ struct videobuf_dvb {
        struct dvb_net             net;
 };
 
-int videobuf_dvb_register(struct videobuf_dvb *dvb,
+struct videobuf_dvb_frontend {
+       struct list_head felist;
+       int id;
+       struct videobuf_dvb dvb;
+};
+
+struct videobuf_dvb_frontends {
+       struct list_head felist;
+       struct mutex lock;
+       struct dvb_adapter adapter;
+       int active_fe_id; /* Indicates which frontend in the felist is in use */
+       int gate; /* Frontend with gate control 0=!MFE,1=fe0,2=fe1 etc */
+};
+
+int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
                          struct module *module,
                          void *adapter_priv,
                          struct device *device,
-                         short *adapter_nr);
-void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
+                         short *adapter_nr,
+                         int mfe_shared);
+
+void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f);
+
+struct videobuf_dvb_frontend * videobuf_dvb_alloc_frontend(struct videobuf_dvb_frontends *f, int id);
+
+struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id);
+int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p);
+
 
 /*
  * Local variables:
index c130a137c12938cb0d7baa3ac6a9b8f333beb53c..b40f6d5f8fe9bc24750fb829742ef655f0f4c42c 100644 (file)
@@ -876,6 +876,7 @@ int write_cache_pages(struct address_space *mapping,
        pgoff_t end;            /* Inclusive */
        int scanned = 0;
        int range_whole = 0;
+       long nr_to_write = wbc->nr_to_write;
 
        if (wbc->nonblocking && bdi_write_congested(bdi)) {
                wbc->encountered_congestion = 1;
@@ -939,7 +940,7 @@ retry:
                                unlock_page(page);
                                ret = 0;
                        }
-                       if (ret || (--(wbc->nr_to_write) <= 0))
+                       if (ret || (--nr_to_write <= 0))
                                done = 1;
                        if (wbc->nonblocking && bdi_write_congested(bdi)) {
                                wbc->encountered_congestion = 1;
@@ -958,11 +959,12 @@ retry:
                index = 0;
                goto retry;
        }
-       if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
-               mapping->writeback_index = index;
+       if (!wbc->no_nrwrite_index_update) {
+               if (wbc->range_cyclic || (range_whole && nr_to_write > 0))
+                       mapping->writeback_index = index;
+               wbc->nr_to_write = nr_to_write;
+       }
 
-       if (wbc->range_cont)
-               wbc->range_start = index << PAGE_CACHE_SHIFT;
        return ret;
 }
 EXPORT_SYMBOL(write_cache_pages);
index bf66d0191baf57e36a72143335f0d3d93e24d548..d87958a5f03e95b2cb851722fb91d2c6e5447f66 100644 (file)
@@ -2580,6 +2580,7 @@ put_memory:
        shmem_unacct_size(flags, size);
        return ERR_PTR(error);
 }
+EXPORT_SYMBOL_GPL(shmem_file_setup);
 
 /**
  * shmem_zero_setup - setup a shared anonymous mapping