]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.30pre1 2.3.30pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:28:48 +0000 (15:28 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:28:48 +0000 (15:28 -0500)
52 files changed:
CREDITS
Documentation/00-INDEX
Documentation/Configure.help
Documentation/filesystems/00-INDEX
Documentation/networking/00-INDEX
Documentation/sound/CMI8338
Documentation/video4linux/zr36120.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/kernel/setup.c
arch/alpha/mm/init.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/process.c
arch/i386/kernel/smp.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/visws_apic.c
drivers/char/Config.in
drivers/char/Makefile
drivers/char/buz.c
drivers/char/mem.c
drivers/char/ppdev.c
drivers/char/saa7110.c [new file with mode: 0644]
drivers/char/videodev.c
drivers/char/zr36120.c [new file with mode: 0644]
drivers/char/zr36120.h [new file with mode: 0644]
drivers/char/zr36120_i2c.c [new file with mode: 0644]
drivers/char/zr36120_mem.c [new file with mode: 0644]
drivers/char/zr36120_mem.h [new file with mode: 0644]
drivers/net/tokenring/tms380tr.c
drivers/net/wavelan.c
drivers/net/wavelan.p.h
drivers/scsi/sd.c
drivers/sound/Config.in
drivers/sound/cmpci.c
drivers/video/Config.in
fs/binfmt_misc.c
include/asm-alpha/page.h
include/asm-alpha/system.h
include/asm-arm/arch-cl7500/acornfb.h
include/asm-arm/pgtable.h
include/asm-arm/processor.h
include/asm-i386/highmem.h
include/asm-i386/hw_irq.h
include/asm-i386/smp.h
include/asm-i386/spinlock.h
include/linux/bootmem.h
include/linux/videodev.h
include/linux/wireless.h
kernel/sched.c
mm/bootmem.c
mm/highmem.c

diff --git a/CREDITS b/CREDITS
index 219d23734696e015eb7fef4bcaa73ab205567bbd..c2de4b2ac2353bb2bdefe081f10afff9057d92bd 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1468,8 +1468,10 @@ S: Victoria 3163
 S: Australia
 
 N: Pauline Middelink
-E: middelin@polyware.iaf.nl
+E: middelin@polyware.nl
 D: General low-level bug fixes, /proc fixes, identd support
+D: Author of IP masquerading
+D: Zoran ZR36120 Video For Linux driver
 S: Boterkorfhoek 34
 S: 7546 JA  Enschede
 S: Netherlands
index f29b280e4152a85fc9788936287fa8de6d409d68..20599cac7ab36cf99f985bcf8ca5e97b82716ada 100644 (file)
@@ -69,12 +69,12 @@ isdn/
        - directory with info on the Linux ISDN support, and supported cards.
 java.txt
        - info on the in-kernel binary support for Java(tm)
-joystick.txt
-       - info on using joystick devices (and driver) with Linux.
 joystick-api.txt
        - API specification for applications that will be using the joystick.
 joystick-parport.txt 
        - info on how to hook joysticks/gamepads to the parallel port.
+joystick.txt
+       - info on using joystick devices (and driver) with Linux.
 kbuild/
        - directory with info about the kernel build process
 kernel-docs.txt
@@ -127,8 +127,6 @@ pcwd-watchdog.txt
        - info and sample code for using with the PC Watchdog reset card.
 powerpc/
        - directory with info on using Linux with the PowerPC.
-proc.txt
-       - detailed info on Linux's /proc filesystem.
 proc_usb_info.txt
        - info on /proc/bus/usb direcory generated for USB devices
 ramdisk.txt
@@ -178,4 +176,3 @@ watchdog.txt
 xterm-linux.xpm
        - XPM image of penguin logo (see logo.txt) sitting on an xterm.
 
-
index e79a4e7add1751d16ffadb40f090b6e663461055..52aa2370d4f7a6023d2d19a3436e80108454b165 100644 (file)
@@ -12447,6 +12447,18 @@ CONFIG_VIDEO_BT848
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
+ZR36120/36125 Video for Linux
+CONFIG_VIDEO_ZR36120
+  Support for ZR36120/ZR36125 based frame grabber/overlay boards.
+  This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV,
+  and Buster boards. Please read the material in
+  Documentation/video4linux/zr36120.txt for more information.
+
+  This driver is also available as a module called zr36120.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
 SAA5249 Teletext processor
 CONFIG_VIDEO_SAA5249
   Support for I2C bus based teletext using the SAA5249 chip. At the
index b4ffac0228b8ad0b6eaa9e853ab9f4c4e1a599c0..a5312faaf7e2c089586ccc4dd4e54d2e469bebfb 100644 (file)
@@ -18,6 +18,8 @@ ncpfs.txt
        - info on Novell Netware(tm) filesystem using NCP protocol.
 ntfs.txt
        - info and mount options for the NTFS filesystem (Windows NT).
+proc.txt
+       - info on Linux's /proc filesystem.
 romfs.txt
        - Description of the ROMFS filesystem.
 smbfs.txt
index be39d93e40b84080995179d4a63be97843f9f0d2..59de4ac195caa1a9ef99cadbe562ca104d92cb1a 100644 (file)
@@ -58,8 +58,6 @@ net-modules.txt
        - info and "insmod" parameters for all network driver modules.
 policy-routing.txt
        - IP policy-based routing
-ppp.txt
-       - info on what software you should use to run PPP.
 pt.txt
        - the Gracilis Packetwin AX.25 device driver
 routing.txt
index 85dfd1c911abd86b31a7973f180c4d5f971cfe59..70423953c9f297a47dddde291340155513780880 100644 (file)
@@ -1,5 +1,22 @@
 Audio driver for CM8338/CM8738 chips by Chen-Li Tien
 
+
+HARDWARE SUPPORTED
+================================================================================
+C-Media CMI8338
+C-Media CMI8738
+On-board C-Media chips
+
+
+WHAT'S NEW
+================================================================================
+
+  1. Support modem interface for 8738. (select in kernel configuration)
+  2. Enable S/PDIF-in to S/PDIF-out (S/PDIF loop).
+  3. Enable 4 channels analog duplicate mode on 3 jack or 4 jack
+     configurateion.
+
+
    Be aware: C-Media Electronics Inc. is basically an IC design house,
    and whose development of software drivers is mainly for use by its OEM
    customers in their products. C-Media Electronics Inc. itself does not
@@ -27,6 +44,23 @@ Audio driver for CM8338/CM8738 chips by Chen-Li Tien
 7. To install the driver, enter 'modprobe cmpci'.
 
 
-Bugs:
+DRIVER PARAMETERS
+================================================================================
+
+  Some functions for the cm8738 can be configured in Kernel Configuration
+  or modules parameters. Set these parameters to 1 to enable.
+
+  spdif_loop:   Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
+                directly.
+  four_ch:      Enable 4 channels mode, rear-out or line-in will output
+                the same as line-out.
+  rear_out:     Enable this if you have independent rear-out jacket on
+                your sound card, otherwise line-in will be used as
+                rear-out.
+  modem:       You will need to set this parameter if you want to use
+               the HSP modem. You need install the pctel.o, the modem
+               driver itself.
 
-1. Real player cannot be run (the same as es1371).
+  (You will need to get the pctel driver (binary only) and the support for
+  this option from the CMI site. It is not included in the Linux kernel 
+  proper as it is non-free).
diff --git a/Documentation/video4linux/zr36120.txt b/Documentation/video4linux/zr36120.txt
new file mode 100644 (file)
index 0000000..a028f2b
--- /dev/null
@@ -0,0 +1,159 @@
+Driver for Trust Computer Products Framegrabber, version 0.6.1
+------ --- ----- -------- -------- ------------  ------- - - -
+
+- ZORAN ------------------------------------------------------
+ Author: Pauline Middelink <middelin@polyware.nl> 
+   Date: 18 September 1999
+Version: 0.6.1
+
+- Description ------------------------------------------------
+
+Video4Linux compatible driver for an unknown brand framegrabber
+(Sold in the Netherlands by TRUST Computer Products) and various
+other zoran zr36120 based framegrabbers.
+
+The card contains a ZR36120 Multimedia PCI Interface and a Philips
+SAA7110 Onechip Frontend videodecoder. There is also an DSP of
+which I have forgotten the number, since i will never get that thing
+to work without specs from the vendor itself.
+
+The SAA711x are capable of processing 6 different video inputs,
+CVBS1..6 and Y1+C1, Y2+C2, Y3+C3. All in 50/60Hz, NTSC, PAL or
+SECAM and delivering a YUV datastream.  On my card the input
+'CVBS-0' corresponds to channel CVBS2 and 'S-Video' to Y2+C2.
+
+I have some reports of other cards working with the mentioned
+chip sets. For a list of other working cards please have a look
+at the cards named in the tvcards struct in the beginning of
+zr36120.c
+
+After some testing, I discovered that the carddesigner messed up
+on the I2C interface. The Zoran chip includes 2 lines SDA and SCL
+which (s)he connected reversely. So we have to clock on the SDA
+and r/w data on the SCL pin. Life is fun... Each cardtype now has
+a bit which signifies if you have a card with the same deficiancy.
+
+Oh, for the completness of this story I must mention that my
+card delivers the VSYNC pulse of the SAA chip to GIRQ1, not
+GIRQ0 as some other cards have. This is also incorperated in
+the driver be clearing/setting the 'useirq1' bit in the tvcard
+description.
+
+Another problems of contingious capturing data with a Zoran chip
+is something nasty inside the chip. It effectively halves the
+fps we ought to get... Here is the scenario: capturing frames
+to memory is done in the so-called snapshot mode. In this mode
+the Zoran stops after capturing a frame worth of data and wait
+till the application set GRAB bit to indicate readyness for the
+next frame. After detecting a set bit, the chip neetly waits
+till the start of a frame, captures it and it goes back to off.
+Smart ppl will notice the problem here. Its the waiting on the
+_next_ frame each time we set the GRAB bit... Oh well, 12,5 fps
+is still plenty fast for me.
+-- update 28/7/1999 --
+Don't believe a word I just said... Proof is the output
+of `streamer -t 300 -r 25 -f avi15 -o /dev/null`
+       ++--+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
+       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+-
+       syncer: done
+       writer: done
+(note the /dev/null is prudent here, my system is not able to
+ grab /and/ write 25 fps to a file... gifts welcome :) )
+The technical reasoning follows: The zoran completed the last
+frame, the VSYNC goes low, and GRAB is cleared. The interrupt
+routine starts to work since its VSYNC driven, and again
+activates the GRAB bit. A few ms later the VSYNC (re-)rises and
+the zoran starts to work on a new and freshly broadcasted frame....
+
+For pointers I used the specs of both chips. Below are the URLs:
+       http://www.zoran.com/ftp/download/devices/pci/ZR36120/36120data.pdf
+       http://www-us.semiconductor.philips.com/acrobat/datasheets/SAA_7110_A_1.pdf
+
+The documentation has very little on absolute numbers or timings
+needed for the various modes/resolutions, but there are other
+programs you can borrow those from.
+
+------ Install --------------------------------------------
+Read the file called TODO.  Note its long list of limitations.
+
+Build a kernel with VIDEO4LINUX enabled. Activate the
+BT848 driver; we need this because we have need for the
+other modules (i2c and videodev) it enables.
+
+To install this software, extract it into a suitable directory.
+Examine the makefile and change anything you don't like.  Type "make".
+
+After making the modules check if you have the much needed
+/dev/video devices. If not, execute the following 4 lines:
+       mknod /dev/video c 81 0
+       mknod /dev/video1 c 81 1
+       mknod /dev/video2 c 81 2
+       mknod /dev/video3 c 81 3
+       mknod /dev/video4 c 81 4
+
+After makeing/checking the devices do:
+       modprobe i2c
+       modprobe videodev
+       modprobe saa7110        (optional)
+       modprobe saa7111        (optional)
+       modprobe tuner          (optional)
+       insmod zoran cardtype=<n>
+
+<n> is the cardtype of the card you have. The cardnumber can
+be found in the source of zr36120. Look for tvcards. If your
+card is not there, please try if any other card gives some
+response, and mail me if you got a working tvcard addition. 
+
+PS. <TVCard editors behold!)
+    Dont forget to set video_input to the number of inputs
+    you defined in the video_mux part of the tvcard definition.
+    Its a common error to add a channel but not incrementing
+    video_input and getting angry with me/v4l/linux/linus :(
+
+You are now ready to test the framegrabber with your favorite
+video4linux compatible tool
+
+------ Application ----------------------------------------
+
+This device works with all Video4Linux compatible applications,
+given the limitations in the TODO file.
+
+------ API ------------------------------------------------
+
+This uses the V4L interface as of kernel release 2.1.116, and in
+fact has not been tested on any lower version.  There are a couple
+of minor differences due to the fact that the amount of data returned
+with each frame varies, and no doubt there are discrepancies due to my
+misunderstanding of the API.  I intend to convert this driver to the
+new V4L2 API when it has stabilized more.
+
+------ Current state --------------------------------------
+
+The driver is capable of overlaying a video image in screen, and
+even capable of grabbing frames. It uses the BIGPHYSAREA patch
+to allocate lots of large memory blocks when tis patch is
+found in the kernel, but it doesn't need it.
+The consequence is that, when loading the driver as a module,
+the module may tell you it's out of memory, but 'free' says
+otherwise. The reason is simple; the modules wants its memory
+contingious, not fragmented, and after a long uptime there
+probably isn't a fragment of memory large enough...
+
+The driver uses a double buffering scheme, which should realy
+be an n-way buffer, depending on the size of allocated framebuffer
+and the requested grab-size/format.
+This current version also fixes a dead-lock situation during irq
+time, which really, really froze my system... :)
+
+Good luck.
+  Pauline
index 975f50e6efe2c7ce16c8970f6c246298e11a1596..ae8c7b540809d59d2355feaa492bf88e005de5fd 100644 (file)
@@ -1007,6 +1007,13 @@ W:       http://qsl.net/dl1bke/
 L:     linux-hams@vger.rutgers.edu
 S:     Maintained
 
+ZR36120 VIDEO FOR LINUX DRIVER
+P:     Pauline Middelink
+M:     middelin@polyware.nl
+W:     http://www.polyware.nl/~middelin/En/hobbies.html
+W:     http://www.polyware.nl/~middelin/hobbies.html
+S:     Maintained
+
 THE REST
 P:     Linus Torvalds
 S:     Buried alive in reporters
index 8629b2482b788cb9eab8c328adf82ebdf7d590f7..2139dcbf1c947b313a02009b1f45318fb10b6258 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 29
+SUBLEVEL = 30
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
index 2d8422f238c74333caebdb4bce4d1eacae3dc4af..578bd69612339b53ac9d143802253100ad6b3642 100644 (file)
@@ -189,29 +189,26 @@ reserve_std_resources(void)
 #define PFN_DOWN(x)    ((x) >> PAGE_SHIFT)
 #define PFN_PHYS(x)    ((x) << PAGE_SHIFT)
 #define PFN_MAX                PFN_DOWN(0x80000000)
+#define for_each_mem_cluster(memdesc, cluster, i)              \
+       for ((cluster) = (memdesc)->cluster, (i) = 0;           \
+            (i) < (memdesc)->numclusters; (i)++, (cluster)++)
 static void __init setup_memory(void)
 {
        struct memclust_struct * cluster;
        struct memdesc_struct * memdesc;
-       unsigned long start_pfn, bootmap_size;
+       unsigned long start_pfn, bootmap_size, bootmap_pages, bootmap_start;
+       unsigned long start, end;
        extern char _end[];
        int i;
 
-       /* alloc the bootmem after the kernel */
-       start_pfn = PFN_UP(virt_to_phys(_end));
-       SRM_printf("_end %p\n", _end);
-
        /* find free clusters, and init and free the bootmem accordingly */
        memdesc = (struct memdesc_struct *) (hwrpb->mddt_offset + (unsigned long) hwrpb);
 
-       for (cluster = memdesc->cluster, i = memdesc->numclusters;
-            i > 0; i--, cluster++)
+       for_each_mem_cluster(memdesc, cluster, i)
        {
-               unsigned long end;
-
-               printk("memcluster %d, usage %02lx, start %8lu, end %8lu\n",
+               printk("memcluster %d, usage %01lx, start %8lu, end %8lu\n",
                       i, cluster->usage, cluster->start_pfn,
-                      cluster->numpages);
+                      cluster->start_pfn + cluster->numpages);
 
                /* Bit 0 is console/PALcode reserved.  Bit 1 is
                   non-volatile memory -- we might want to mark
@@ -226,38 +223,89 @@ static void __init setup_memory(void)
        /* Enforce maximum of 2GB even if there is more.  Blah.  */
        if (max_low_pfn > PFN_MAX)
                max_low_pfn = PFN_MAX;
-       SRM_printf("max_low_pfn %d\n", max_low_pfn);
+       printk("max_low_pfn %ld\n", max_low_pfn);
 
-       /* allocate the bootmem array after the kernel and mark
-          the whole MM as reserved */
-       bootmap_size = init_bootmem(start_pfn, max_low_pfn);
+       /* find the end of the kernel memory */
+       start_pfn = PFN_UP(virt_to_phys(_end));
+       printk("_end %p, start_pfn %ld\n", _end, start_pfn);
 
-       for (cluster = memdesc->cluster, i = memdesc->numclusters;
-            i > 0; i--, cluster++)
-       {
-               unsigned long end, start;
+       bootmap_start = -1;
 
-               /* Bit 0 is console/PALcode reserved.  Bit 1 is
-                  non-volatile memory -- we might want to mark
-                  this for later */
+ try_again:
+       if (max_low_pfn <= start_pfn)
+               panic("not enough memory to boot");
+
+       /* we need to know how many physically contigous pages
+          we'll need for the bootmap */
+       bootmap_pages = bootmem_bootmap_pages(max_low_pfn);
+       printk("bootmap size: %ld pages\n", bootmap_pages);
+
+       /* now find a good region where to allocate the bootmap */
+       for_each_mem_cluster(memdesc, cluster, i)
+       {
                if (cluster->usage & 3)
                        continue;
 
-               start = PFN_PHYS(cluster->start_pfn);
-               if (start < PFN_PHYS(start_pfn) + bootmap_size)
-                       start = PFN_PHYS(start_pfn) + bootmap_size;
-               if (PFN_DOWN(start) >= PFN_MAX)
+               start = cluster->start_pfn;
+               end = start + cluster->numpages;
+               if (end <= start_pfn)
+                       continue;
+               if (start >= max_low_pfn)
+                       continue;
+               if (start < start_pfn)
+                       start = start_pfn;
+               if (end > max_low_pfn)
+                       end = max_low_pfn;
+               if (end - start >= bootmap_pages)
+               {
+                       printk("allocating bootmap in area %ld:%ld\n",
+                              start, start+bootmap_pages);
+                       bootmap_start = start;
+                       break;
+               }
+       }
+
+       if (bootmap_start == -1)
+       {
+               max_low_pfn >>= 1;
+               printk("bootmap area not found now trying with %ld pages\n",
+                      max_low_pfn);
+               goto try_again;
+       }
+
+       /* allocate the bootmap and mark the whole MM as reserved */
+       bootmap_size = init_bootmem(bootmap_start, max_low_pfn);
+
+       /* mark the free regions */
+       for_each_mem_cluster(memdesc, cluster, i)
+       {
+               if (cluster->usage & 3)
                        continue;
 
-               end = PFN_PHYS(cluster->start_pfn + cluster->numpages);
-               if (PFN_DOWN(end) > PFN_MAX)
-                       end = PFN_PHYS(PFN_MAX);
+               start = cluster->start_pfn;
+               if (start < start_pfn)
+                       start = start_pfn;
+
+               end = cluster->start_pfn + cluster->numpages;
+               if (end > max_low_pfn)
+                       end = max_low_pfn;
 
                if (start >= end)
                        continue;
-               free_bootmem(start, end-start);
+
+               start = PFN_PHYS(start);
+               end = PFN_PHYS(end);
+
+               free_bootmem(start, end - start);
+               printk("freeing pages %ld:%ld\n",
+                      PFN_UP(start), PFN_DOWN(end));
        }
 
+       /* reserve the bootmap memory */
+       reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size);
+       printk("reserving bootmap %ld:%ld\n", bootmap_start,
+              bootmap_start + PFN_UP(bootmap_size));
+
 #ifdef CONFIG_BLK_DEV_INITRD
        initrd_start = INITRD_START;
        if (initrd_start) {
@@ -355,10 +403,6 @@ setup_arch(char **cmdline_p)
        alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0;
 #endif
 
-       SRM_printf("Booting on %s%s%s using machine vector %s\n",
-              type_name, (*var_name ? " variation " : ""),
-              var_name, alpha_mv.vector_name);
-
        printk("Booting "
 #ifdef CONFIG_ALPHA_GENERIC
               "GENERIC "
index 105963a334c5c61cab9e9995c58f6411c733c6eb..f1635118adb5edea6cac76d9abf834b255e1dddb 100644 (file)
@@ -212,7 +212,7 @@ void paging_init(void)
                zones_size[ZONE_DMA] = high_pfn;
        else
        {
-               zones_size[0] = dma_pfn;
+               zones_size[ZONE_DMA] = dma_pfn;
                zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
        }
 
@@ -278,7 +278,7 @@ mem_init(void)
 {
        max_mapnr = num_physpages = max_low_pfn;
        totalram_pages += free_all_bootmem();
-       printk("Memory: %luk available\n", totalram_pages >> 10);
+       printk("Memory: %luk available\n", totalram_pages << (PAGE_SHIFT-10));
 }
 
 void
index 9fb8bcd3a0b7bcdb31cbae7a3b06e42092243991..5ed9255f6a79f2bc5fd0469b523f0241bda4e259 100644 (file)
@@ -940,7 +940,7 @@ void print_all_local_APICs (void)
        print_local_APIC(NULL);
 }
 
-static void __init init_sym_mode(void)
+static void __init enable_IO_APIC(void)
 {
        struct IO_APIC_reg_01 reg_01;
        int i;
@@ -976,31 +976,15 @@ static void __init init_sym_mode(void)
        clear_IO_APIC();
 }
 
-static void clear_lapic_ints (void * dummy)
-{
-       int maxlvt;
-
-       maxlvt = get_maxlvt();
-       apic_write_around(APIC_LVTT, 0x00010000);
-       apic_write_around(APIC_LVT0, 0x00010000);
-       apic_write_around(APIC_LVT1, 0x00010000);
-       if (maxlvt >= 3)
-               apic_write_around(APIC_LVTERR, 0x00010000);
-       if (maxlvt >= 4)
-               apic_write_around(APIC_LVTPC, 0x00010000);
-}
-
 /*
  * Not an __init, needed by the reboot code
  */
-void init_pic_mode(void)
+void disable_IO_APIC(void)
 {
        /*
-        * Clear the IO-APIC and local APICs before rebooting:
+        * Clear the IO-APIC before rebooting:
         */
        clear_IO_APIC();
-       smp_call_function(clear_lapic_ints, NULL, 1, 1);
-       clear_lapic_ints(NULL);
 
        /*
         * Put it back into PIC mode (has an effect only on
@@ -1379,8 +1363,10 @@ static inline void check_timer(void)
        }
        printk(" failed.\n");
 
-       if (nmi_watchdog)
-               printk("timer doesnt work through the IO-APIC - cannot activate NMI Watchdog!\n");
+       if (nmi_watchdog) {
+               printk("timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n");
+               nmi_watchdog = 0;
+       }
 
        printk("...trying to set up timer as Virtual Wire IRQ...");
 
@@ -1417,7 +1403,7 @@ static inline void check_timer(void)
 
 void __init setup_IO_APIC(void)
 {
-       init_sym_mode();
+       enable_IO_APIC();
 
        printk("ENABLING IO-APIC IRQs\n");
        io_apic_irqs = ~PIC_IRQS;
index e9feeca3ad979a6a235a33f255356daf8155c0c9..854cff8d834596cadffc73cc2105b5be80b4690e 100644 (file)
@@ -263,7 +263,7 @@ static inline void wait_on_bh(void)
  * i thought that such things are guaranteed by design, since we use
  * the 'LOCK' prefix.
  */
-#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 1
+#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0
 
 #if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND
 # define SYNC_OTHER_CORES(x) udelay(x+1)
index 429c4eacd9b12420cc35f4245d8011623810334a..680563959e2c47c1a2809a12fad2143ecc915a1d 100644 (file)
@@ -204,9 +204,11 @@ void machine_restart(char * __unused)
 {
 #if __SMP__
        /*
-        * turn off the IO-APIC, so we can do a clean reboot
+        * Stop all CPUs and turn off local APICs and the IO-APIC, so
+        * other OSs see a clean IRQ state.
         */
-       init_pic_mode();
+       smp_send_stop();
+       disable_IO_APIC();
 #endif
 
        if(!reboot_thru_bios) {
index 8e4ecd7f41776f4684e500f13a7a5680de5e824a..92113b559c01d76c09c35bf59ca76fcafe4c2df9 100644 (file)
@@ -439,9 +439,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
                if (down_trylock(&lock))
                        return -EBUSY;
 
-       if (call_data) // temporary debugging check
-               BUG();
-
        call_data = &data;
        data.func = func;
        data.info = info;
@@ -478,7 +475,8 @@ static void stop_this_cpu (void * dummy)
         * Remove this CPU:
         */
        clear_bit(smp_processor_id(), &cpu_online_map);
-
+       __cli();
+       disable_local_APIC();
        if (cpu_data[smp_processor_id()].hlt_works_ok)
                for(;;) __asm__("hlt");
        for (;;);
@@ -490,7 +488,14 @@ static void stop_this_cpu (void * dummy)
 
 void smp_send_stop(void)
 {
+       unsigned long flags;
+
+       __save_flags(flags);
+       __cli();
         smp_call_function(stop_this_cpu, NULL, 1, 0);
+       disable_local_APIC();
+       __restore_flags(flags);
+
 }
 
 /*
@@ -539,7 +544,7 @@ asmlinkage void smp_call_function_interrupt(void)
         */
        atomic_inc(&call_data->started);
        /*
-        * At this point the structure may be out of scope unless wait==1
+        * At this point the info structure may be out of scope unless wait==1
         */
        (*func)(info);
        if (wait)
@@ -575,8 +580,27 @@ asmlinkage void smp_error_interrupt(void)
        printk("... APIC ESR0: %08lx\n", v);
 
        apic_write(APIC_ESR, 0);
-       v = apic_read(APIC_ESR);
+       v |= apic_read(APIC_ESR);
        printk("... APIC ESR1: %08lx\n", v);
+       /*
+        * Be a bit more verbose. (multiple bits can be set)
+        */
+       if (v & 0x01)
+               printk("... bit 0: APIC Send CS Error (hw problem).\n");
+       if (v & 0x02)
+               printk("... bit 1: APIC Receive CS Error (hw problem).\n");
+       if (v & 0x04)
+               printk("... bit 2: APIC Send Accept Error.\n");
+       if (v & 0x08)
+               printk("... bit 3: APIC Receive Accept Error.\n");
+       if (v & 0x10)
+               printk("... bit 4: Reserved!.\n");
+       if (v & 0x20)
+               printk("... bit 5: Send Illegal Vector (kernel bug).\n");
+       if (v & 0x40)
+               printk("... bit 6: Received Illegal Vector.\n");
+       if (v & 0x80)
+               printk("... bit 7: Illegal Register Address.\n");
 
        ack_APIC_irq();
 
index 0f8a4060ab26b2961e80830286efe41098844cde..811f00f387e9768111ea46b8f6509050be6618a4 100644 (file)
@@ -708,7 +708,35 @@ int get_maxlvt(void)
        return maxlvt;
 }
 
-void __init setup_local_APIC(void)
+void disable_local_APIC (void)
+{
+       unsigned long value;
+        int maxlvt;
+
+       /*
+        * Disable APIC
+        */
+       value = apic_read(APIC_SPIV);
+       value &= ~(1<<8);
+       apic_write(APIC_SPIV,value);
+
+       /*
+        * Clean APIC state for other OSs:
+        */
+       value = apic_read(APIC_SPIV);
+       value &= ~(1<<8);
+       apic_write(APIC_SPIV,value);
+       maxlvt = get_maxlvt();
+       apic_write_around(APIC_LVTT, 0x00010000);
+       apic_write_around(APIC_LVT0, 0x00010000);
+       apic_write_around(APIC_LVT1, 0x00010000);
+       if (maxlvt >= 3)
+               apic_write_around(APIC_LVTERR, 0x00010000);
+       if (maxlvt >= 4)
+               apic_write_around(APIC_LVTPC, 0x00010000);
+}
+
+void __init setup_local_APIC (void)
 {
        unsigned long value, ver, maxlvt;
 
@@ -716,12 +744,25 @@ void __init setup_local_APIC(void)
                __error_in_io_apic_c();
 
        value = apic_read(APIC_SPIV);
-       value = 0xf;
        /*
         * Enable APIC
         */
        value |= (1<<8);
-#if 1
+
+       /*
+        * Some unknown Intel IO/APIC (or APIC) errata is biting us with
+        * certain networking cards. If high frequency interrupts are
+        * happening on a particular IOAPIC pin, plus the IOAPIC routing
+        * entry is masked/unmasked at a high rate as well then sooner or
+        * later IOAPIC line gets 'stuck', no more interrupts are received
+        * from the device. If focus CPU is disabled then the hang goes
+        * away, oh well :-(
+        *
+        * [ This bug can be reproduced easily with a level-triggered
+        *   PCI Ne2000 networking cards and PII/PIII processors, dual
+        *   BX chipset. ]
+        */
+#if 0
        /* Enable focus processor (bit==0) */
        value &= ~(1<<9);
 #else
index 6c767d0ebff8b1e512ed06e907b9dc4ce70ab31f..be80cd628f0918dedecea25941b3c1097aa30eef 100644 (file)
@@ -104,7 +104,7 @@ static struct hw_interrupt_type cobalt_irq_type = {
 /*
  * Not an __init, needed by the reboot code
  */
-void init_pic_mode(void)
+void disable_IO_APIC(void)
 {
        /* Nop on Cobalt */
 } 
index 11a303ed7b33f57de7ad4cd975e4c16093150e7f..bfcf5b39ffe083fd1ec3f216ddc162d1bb04eb40 100644 (file)
@@ -141,6 +141,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
    fi
    if [ "$CONFIG_PCI" != "n" ]; then
       dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
+       dep_tristate 'Zoran ZR36120/36125 support' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV
    fi
    dep_tristate '  GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
@@ -192,8 +193,9 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
    if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
       hex '    ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
    fi
-   dep_tristate '  Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV
+   dep_tristate '  Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI
    dep_tristate '    Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
+   dep_tristate '  Zoran ZR36120/36125 support' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI
 fi
 
 endmenu
index 4c3ed132ffea693bea4e83fdc0d23642680e2529..f85f22b51e107131b16227cbaf90be6ef08328fc 100644 (file)
@@ -348,6 +348,9 @@ else
   endif
 endif
 
+#
+# for external dependencies in arm/config.in and video/config.in
+#
 ifeq ($(CONFIG_BUS_I2C),y)
        L_I2C=y
 else
@@ -357,12 +360,28 @@ else
 endif
 
 ifeq ($(CONFIG_VIDEO_BT848),y)
-O_OBJS += bttv.o msp3400.o tuner.o
+O_OBJS += bttv.o msp3400.o
 L_I2C=y
+L_TUNERS=y
 else
   ifeq ($(CONFIG_VIDEO_BT848),m)
-    M_OBJS += bttv.o msp3400.o tuner.o
+    M_OBJS += bttv.o msp3400.o
+    M_I2C=y
+    M_TUNERS=y
+  endif
+endif
+
+ifeq ($(CONFIG_VIDEO_ZR36120),y)
+O_OBJS += zoran.o
+L_I2C=y
+L_TUNERS=y
+L_DECODERS=y
+else
+  ifeq ($(CONFIG_VIDEO_ZR36120),m)
+    M_OBJS += zoran.o
     M_I2C=y
+    M_TUNERS=y
+    M_DECODERS=y
   endif
 endif
 
@@ -404,9 +423,13 @@ endif
 
 ifeq ($(CONFIG_VIDEO_ZORAN),y)
 O_OBJS += buz.o
+L_I2C=y
+L_DECODERS=y
 else
   ifeq ($(CONFIG_VIDEO_ZORAN),m)
     M_OBJS += buz.o
+    M_I2C=y
+    M_DECODERS=y
   endif
 endif
 
@@ -418,14 +441,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_VIDEO_BUZ),y)
-O_OBJS += saa7111.o saa7185.o
-else
-  ifeq ($(CONFIG_VIDEO_BUZ),m)
-    M_OBJS += saa7111.o saa7185.o
-  endif
-endif
-
 ifeq ($(CONFIG_VIDEO_PMS),y)
 O_OBJS += pms.o
 else
@@ -578,11 +593,31 @@ else
   endif
 endif
 
+
+# set when a framegrabber supports external tuners
+ifeq ($(L_TUNERS),y)
+O_OBJS += tuner.o
+else
+  ifeq ($(M_TUNERS),y)
+    M_OBJS += tuner.o
+  endif
+endif
+
+# set when a framegrabber supports external decoders
+ifeq ($(L_DECODERS),y)
+O_OBJS += saa7110.o saa7111.o saa7185.o
+else
+  ifeq ($(M_DECODERS),y)
+    M_OBJS += saa7110.o saa7111.o saa7185.o
+  endif
+endif
+
+# set when a framegrabber implements i2c support
 ifeq ($(L_I2C),y)
 OX_OBJS += i2c.o
 else
 ifeq ($(M_I2C),y)
 MX_OBJS += i2c.o
+ ifeq ($(M_I2C),y)
+ MX_OBJS += i2c.o
   endif
 endif
 
@@ -615,3 +650,5 @@ consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h
 defkeymap.c: defkeymap.map
        loadkeys --mktable defkeymap.map > defkeymap.c
 
+zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o
+       $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o
index 91c131c567667ea5ca180736389c191b80e00c50..de688ae0b3402ac576e221804597b409a709ba64 100644 (file)
@@ -3035,7 +3035,7 @@ static struct video_device zoran_template =
        BUZ_NAME,
        VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
        VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
-       VID_HARDWARE_BT848,     /* Not true, but the buz is not yet in the list */
+       VID_HARDWARE_ZR36067,
        zoran_open,
        zoran_close,
        zoran_read,
index bf8d57e9ce715b50140029647eda2e635428cb17..5d907e300bed453a2838b0c8e985ee52e5281da8 100644 (file)
@@ -56,9 +56,6 @@ extern void adbdev_init(void);
 #ifdef CONFIG_USB
 extern void usb_init(void);
 #endif
-#ifdef CONFIG_PPDEV
-extern int pp_init(void);
-#endif
      
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
                            const char * buf, size_t count, loff_t *ppos)
@@ -675,9 +672,6 @@ int __init chr_dev_init(void)
 #endif
 #ifdef CONFIG_VIDEO_DEV
        videodev_init();
-#endif
-#ifdef CONFIG_PPDEV
-       pp_init();
 #endif
        return 0;
 }
index 5afcec0c9e633c66e3638c7f8a702767c3d92242..71bb3a18c4094352907be4974b46cc842d3acc4d 100644 (file)
@@ -43,6 +43,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ioctl.h>
 #include <linux/parport.h>
@@ -578,11 +579,7 @@ static struct file_operations pp_fops = {
        pp_release
 };
 
-#ifdef MODULE
-#define pp_init init_module
-#endif
-
-int pp_init (void)
+static int __init ppdev_init (void)
 {
        if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
                printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
@@ -594,10 +591,11 @@ int pp_init (void)
        return 0;
 }
 
-#ifdef MODULE
-void cleanup_module (void)
+static void __exit ppdev_cleanup (void)
 {
        /* Clean up all parport stuff */
        unregister_chrdev (PP_MAJOR, CHRDEV);
 }
-#endif /* MODULE */
+
+module_init(ppdev_init);
+module_exit(ppdev_cleanup);
diff --git a/drivers/char/saa7110.c b/drivers/char/saa7110.c
new file mode 100644 (file)
index 0000000..6a0402f
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+    saa7110 - Philips SAA7110(A) video decoder driver
+
+    Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include "linux/video_decoder.h"
+
+#define DEBUG(x...)    x               /* remove when no long debugging */
+
+#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        I2C_DELAY               10      /* 10 us or 100khz */
+
+struct saa7110 {
+       struct  i2c_bus *bus;
+       int             addr;
+       unsigned char   reg[36];
+
+       int             norm;
+       int             input;
+       int             enable;
+       int             bright;
+       int             contrast;
+       int             hue;
+       int             sat;
+};
+
+/* ----------------------------------------------------------------------- */
+/* I2C support functions                                                  */
+/* ----------------------------------------------------------------------- */
+static
+int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data)
+{
+       int ack;
+
+       LOCK_I2C_BUS(decoder->bus);
+       i2c_start(decoder->bus);
+       i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
+       i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY);
+       ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY);
+       i2c_stop(decoder->bus);
+       decoder->reg[subaddr] = data;
+       UNLOCK_I2C_BUS(decoder->bus);
+       return ack;
+}
+
+static
+int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len)
+{
+       unsigned subaddr = *data;
+
+       LOCK_I2C_BUS(decoder->bus);
+        i2c_start(decoder->bus);
+        i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY);
+       while (len-- > 0) {
+                if (i2c_sendbyte(decoder->bus,*data,0)) {
+                        i2c_stop(decoder->bus);
+                        return -EAGAIN;
+                }
+               decoder->reg[subaddr++] = *data++;
+        }
+       i2c_stop(decoder->bus);
+       UNLOCK_I2C_BUS(decoder->bus);
+
+       return 0;
+}
+
+static
+int saa7110_read(struct saa7110* decoder)
+{
+       int data;
+
+       LOCK_I2C_BUS(decoder->bus);
+       i2c_start(decoder->bus);
+       i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY);
+       i2c_start(decoder->bus);
+       i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY);
+       data = i2c_readbyte(decoder->bus, 1);
+       i2c_stop(decoder->bus);
+       UNLOCK_I2C_BUS(decoder->bus);
+       return data;
+}
+
+/* ----------------------------------------------------------------------- */
+/* SAA7110 functions                                                      */
+/* ----------------------------------------------------------------------- */
+static
+int saa7110_selmux(struct i2c_device *device, int chan)
+{
+static const unsigned char modes[9][8] = {
+/* mode 0 */   { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
+/* mode 1 */   { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 },
+/* mode 2 */   { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
+/* mode 3 */   { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 },
+/* mode 4 */   { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
+/* mode 5 */   { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 },
+/* mode 6 */   { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 },
+/* mode 7 */   { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 },
+/* mode 8 */   { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } };
+       struct saa7110* decoder = device->data;
+       const unsigned char* ptr = modes[chan];
+
+       saa7110_write(decoder,0x06,ptr[0]);     /* Luminance control    */
+       saa7110_write(decoder,0x20,ptr[1]);     /* Analog Control #1    */
+       saa7110_write(decoder,0x21,ptr[2]);     /* Analog Control #2    */
+       saa7110_write(decoder,0x22,ptr[3]);     /* Mixer Control #1     */
+       saa7110_write(decoder,0x2C,ptr[4]);     /* Mixer Control #2     */
+       saa7110_write(decoder,0x30,ptr[5]);     /* ADCs gain control    */
+       saa7110_write(decoder,0x31,ptr[6]);     /* Mixer Control #3     */
+       saa7110_write(decoder,0x21,ptr[7]);     /* Analog Control #2    */
+
+       return 0;
+}
+
+static
+int determine_norm(struct i2c_device* dev)
+{
+       struct  saa7110* decoder = dev->data;
+       int     status;
+
+       /* mode changed, start automatic detection */
+       status = saa7110_read(decoder);
+       if ((status & 3) == 0) {
+               saa7110_write(decoder,0x06,0x80);
+               if (status & 0x20) {
+                       DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name));
+                       saa7110_write(decoder,0x2E,0x81);
+                       return VIDEO_MODE_NTSC;
+               }
+               DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name));
+               saa7110_write(decoder,0x2E,0x9A);
+               return VIDEO_MODE_PAL;
+       }
+
+       saa7110_write(decoder,0x06,0x00);
+       if (status & 0x20) {    /* 60Hz */
+               DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name));
+               saa7110_write(decoder,0x0D,0x06);
+               saa7110_write(decoder,0x11,0x2C);
+               saa7110_write(decoder,0x2E,0x81);
+               return VIDEO_MODE_NTSC;
+       }
+
+       /* 50Hz -> PAL/SECAM */
+       saa7110_write(decoder,0x0D,0x06);
+       saa7110_write(decoder,0x11,0x59);
+       saa7110_write(decoder,0x2E,0x9A);
+
+       mdelay(150);    /* pause 150 ms */
+
+       status = saa7110_read(decoder);
+       if ((status & 0x03) == 0x01) {
+               DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name));
+               saa7110_write(decoder,0x0D,0x07);
+               return VIDEO_MODE_SECAM;
+       }
+       DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name));
+       return VIDEO_MODE_PAL;
+}
+
+static
+int saa7110_attach(struct i2c_device *device)
+{
+static const unsigned char initseq[] = {
+            0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00,
+               0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90,
+               0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
+               0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
+               0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03,
+               0x40, 0x75, 0x01, 0x8C, 0x03};
+       struct  saa7110*        decoder;
+       int                     rv;
+
+       device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL);
+       if (device->data == 0)
+               return -ENOMEM;
+
+       MOD_INC_USE_COUNT;
+
+       /* clear our private data */
+       memset(decoder, 0, sizeof(struct saa7110));
+       strcpy(device->name, "saa7110");
+       decoder->bus = device->bus;
+       decoder->addr = device->addr;
+       decoder->norm = VIDEO_MODE_PAL;
+       decoder->input = 0;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+
+       rv = saa7110_write_block(decoder, initseq, sizeof(initseq));
+       if (rv < 0)
+               printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv);
+       else {
+               saa7110_write(decoder,0x21,0x16);
+               saa7110_write(decoder,0x0D,0x04);
+               printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder));
+               saa7110_write(decoder,0x0D,0x06);
+       }
+
+       /* setup and implicit mode 0 select has been performed */
+       return 0;
+}
+
+static
+int saa7110_detach(struct i2c_device *device)
+{
+       struct saa7110* decoder = device->data;
+
+       DEBUG(printk(KERN_INFO "%s_detach\n",device->name));
+
+       /* stop further output */
+       saa7110_write(decoder,0x0E,0x00);
+
+       kfree(device->data);
+
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static
+int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg)
+{
+       struct saa7110* decoder = device->data;
+       int     v;
+
+       switch (cmd) {
+        case DECODER_GET_CAPABILITIES:
+               {
+                       struct video_decoder_capability *dc = arg;
+                       dc->flags = VIDEO_DECODER_PAL
+                                 | VIDEO_DECODER_NTSC
+                                 | VIDEO_DECODER_SECAM
+                                 | VIDEO_DECODER_AUTO
+                                 | VIDEO_DECODER_CCIR;
+                       dc->inputs = SAA7110_MAX_INPUT;
+                       dc->outputs = SAA7110_MAX_OUTPUT;
+               }
+               break;
+
+        case DECODER_GET_STATUS:
+               {
+                       struct saa7110* decoder = device->data;
+                       int status;
+                       int res = 0;
+
+                       status = i2c_read(device->bus,device->addr|1);
+                       if (status & 0x40)
+                               res |= DECODER_STATUS_GOOD;
+                       if (status & 0x03)
+                               res |= DECODER_STATUS_COLOR;
+
+                       switch (decoder->norm) {
+                        case VIDEO_MODE_NTSC:
+                               res |= DECODER_STATUS_NTSC;
+                               break;
+                        case VIDEO_MODE_PAL:
+                               res |= DECODER_STATUS_PAL;
+                               break;
+                        case VIDEO_MODE_SECAM:
+                               res |= DECODER_STATUS_SECAM;
+                               break;
+                       }
+                       *(int*)arg = res;
+               }
+               break;
+
+        case DECODER_SET_NORM:
+               v = *(int*)arg;
+               if (decoder->norm != v) {
+                       decoder->norm = v;
+                       saa7110_write(decoder, 0x06, 0x00);
+                       switch (v) {
+                        case VIDEO_MODE_NTSC:
+                               saa7110_write(decoder, 0x0D, 0x06);
+                               saa7110_write(decoder, 0x11, 0x2C);
+                               saa7110_write(decoder, 0x30, 0x81);
+saa7110_write(decoder, 0x2A, 0xDF);
+                               break;
+                        case VIDEO_MODE_PAL:
+                               saa7110_write(decoder, 0x0D, 0x06);
+                               saa7110_write(decoder, 0x11, 0x59);
+                               saa7110_write(decoder, 0x2E, 0x9A);
+                               break;
+                        case VIDEO_MODE_SECAM:
+                               saa7110_write(decoder, 0x0D, 0x07);
+                               saa7110_write(decoder, 0x11, 0x59);
+                               saa7110_write(decoder, 0x2E, 0x9A);
+                               break;
+                        case VIDEO_MODE_AUTO:
+                               *(int*)arg = determine_norm(device);
+                               break;
+                        default:
+                               return -EPERM;
+                       }
+               }
+               break;
+
+        case DECODER_SET_INPUT:
+               v = *(int*)arg;
+               if (v<0 || v>SAA7110_MAX_INPUT)
+                       return -EINVAL;
+               if (decoder->input != v) {
+                       decoder->input = v;
+                       saa7110_selmux(device, v);
+               }
+               break;
+
+        case DECODER_SET_OUTPUT:
+               v = *(int*)arg;
+               /* not much choice of outputs */
+               if (v != 0)
+                       return -EINVAL;
+               break;
+
+        case DECODER_ENABLE_OUTPUT:
+               v = *(int*)arg;
+               if (decoder->enable != v) {
+                       decoder->enable = v;
+                       saa7110_write(decoder,0x0E, v ? 0x18 : 0x00);
+               }
+               break;
+
+        case DECODER_SET_PICTURE:
+               {
+                       struct video_picture *pic = arg;
+
+                       if (decoder->bright != pic->brightness) {
+                               /* We want 0 to 255 we get 0-65535 */
+                               decoder->bright = pic->brightness;
+                               saa7110_write(decoder, 0x19, decoder->bright >> 8);
+                       }
+                       if (decoder->contrast != pic->contrast) {
+                               /* We want 0 to 127 we get 0-65535 */
+                               decoder->contrast = pic->contrast;
+                               saa7110_write(decoder, 0x13, decoder->contrast >> 9);
+                       }
+                       if (decoder->sat != pic->colour) {
+                               /* We want 0 to 127 we get 0-65535 */
+                               decoder->sat = pic->colour;
+                               saa7110_write(decoder, 0x12, decoder->sat >> 9);
+                       }
+                       if (decoder->hue != pic->hue) {
+                               /* We want -128 to 127 we get 0-65535 */
+                               decoder->hue = pic->hue;
+                               saa7110_write(decoder, 0x07, (decoder->hue>>8)-128);
+                       }
+               }
+               break;
+
+        case DECODER_DUMP:
+               for (v=0; v<34; v+=16) {
+                       int j;
+                       DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v));
+                       for (j=0; j<16; j++) {
+                               DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j]));
+                       }
+                       DEBUG(printk(KERN_INFO "\n"));
+               }
+               break;
+
+        default:
+               DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd));
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7110 =
+{
+       "saa7110",                      /* name */
+
+       I2C_DRIVERID_VIDEODECODER,      /* in i2c.h */
+       I2C_SAA7110, I2C_SAA7110+1,     /* Addr range */
+
+       saa7110_attach,
+       saa7110_detach,
+       saa7110_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+int saa7110_init(void)
+#endif
+{
+       return i2c_register_driver(&i2c_driver_saa7110);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       i2c_unregister_driver(&i2c_driver_saa7110);
+}
+#endif
index 05f2eeeeaeadc5ff3988cfcb81d0b7b6f27a009d..ab41407bf7605793dcbe4fe3461dfb65787d5fc5 100644 (file)
@@ -54,6 +54,9 @@ extern int init_planbs(struct video_init *);
 #ifdef CONFIG_VIDEO_ZORAN
 extern int init_zoran_cards(struct video_init *);
 #endif
+#ifdef CONFIG_VIDEO_ZR36120
+extern int init_zr36120_cards(struct video_init *);
+#endif
 
 static struct video_init video_init_list[]={
 #ifdef CONFIG_VIDEO_BT848
@@ -71,6 +74,9 @@ static struct video_init video_init_list[]={
 #endif
 #ifdef CONFIG_VIDEO_ZORAN
        {"zoran", init_zoran_cards},
+#endif 
+#ifdef CONFIG_VIDEO_ZR36120
+       {"zr36120", init_zr36120_cards},
 #endif 
        {"end", NULL}
 };
diff --git a/drivers/char/zr36120.c b/drivers/char/zr36120.c
new file mode 100644 (file)
index 0000000..f0cfc5a
--- /dev/null
@@ -0,0 +1,1608 @@
+/*
+    zr36120.c - Zoran 36120/36125 based framegrabbers
+
+    Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include "linux/video_decoder.h"
+#include "tuner.h"
+#include "zr36120.h"
+#include "zr36120_mem.h"
+
+/* sensible default */
+#ifndef CARDTYPE
+#define CARDTYPE 0
+#endif
+
+/* Anybody who uses more than four? */
+#define ZORAN_MAX 4
+
+static ulong irq1 = 0;
+
+       unsigned int triton1=0;                 /* triton1 chipset? */
+static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE };
+
+MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>");
+MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber");
+MODULE_PARM(triton1,"i");
+MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i");
+
+static int zoran_cards;
+static struct zoran zorans[ZORAN_MAX];
+
+/*
+ * the meaning of each element can be found in zr36120.h
+ * Determining the value of gpdir/gpval can be tricky. The
+ * best way is to run the card under the original software
+ * and read the values from the general purpose registers
+ * 0x28 and 0x2C. How you do that is left as an exercise
+ * to the impatient reader :)
+ */
+#define T 1    /* to seperate the bools from the ints */
+#define F 0
+static struct tvcard tvcards[] = {
+       /* reported working by <middelin@polyware.nl> */
+/*0*/  { "Trust Victor II",
+         2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
+       /* reported working by <Michael.Paxton@aihw.gov.au>  */
+/*1*/   { "Aitech WaveWatcher TV-PCI",
+         3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } },
+       /* reported working by ? */
+/*2*/  { "Genius Video Wonder PCI Video Capture Card",
+         2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
+       /* reported working by <Pascal.Gabriel@wanadoo.fr> */
+/*3*/  { "Guillemot Maxi-TV PCI",
+         2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
+       /* reported working by "Craig Whitmore <lennon@igrin.co.nz> */
+/*4*/  { "Quadrant Buster",
+         3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } },
+       /* a debug entry which has all inputs mapped */
+/*5*/  { "ZR36120 based framegrabber (all inputs enabled)",
+         6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } }
+};
+#undef T
+#undef F
+#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0]))
+
+static struct { const char name[8]; int mode; int bpp; } palette2fmt[] = {
+/* n/a     */  { "n/a",     0, 0 },
+/* GREY    */  { "GRAY",    0, 0 },
+/* HI240   */  { "HI240",   0, 0 },
+/* RGB565  */  { "RGB565",  ZORAN_VFEC_RGB_RGB565|ZORAN_VFEC_LE, 2 },
+/* RGB24   */  { "RGB24",   ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24, 3 },
+/* RGB32   */  { "RGB32",   ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE, 4 },
+/* RGB555  */  { "RGB555",  ZORAN_VFEC_RGB_RGB555|ZORAN_VFEC_LE, 2 },
+/* YUV422  */  { "YUV422",  ZORAN_VFEC_RGB_YUV422|ZORAN_VFEC_LE, 3 },
+/* YUYV    */  { "YUYV",    0, 0 },
+/* UYVY    */  { "UYVY",    0, 0 },
+/* YUV420  */  { "YUV420",  0, 0 },
+/* YUV411  */  { "YUV411",  0, 0 },
+/* RAW     */  { "RAW",     0, 0 },
+/* YUV422P */  { "YUV422P", 0, 0 },
+/* YUV411P */  { "YUV411P", 0, 0 }};
+#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0]))
+
+/* ----------------------------------------------------------------------- */
+/* ZORAN chipset detector                                                 */
+/* shamelessly stolen from bttv.c                                         */
+/* Reason for beeing here: we need to detect if we are running on a        */
+/* Triton based chipset, and if so, enable a certain bit                   */
+/* ----------------------------------------------------------------------- */
+
+void handle_chipset(void)
+{
+       struct pci_dev *dev = NULL;
+  
+       /* Just in case some nut set this to something dangerous */
+       if (triton1)
+               triton1 = ZORAN_VDC_TRICOM;
+       
+       while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) 
+       {
+               printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n");
+               triton1 = ZORAN_VDC_TRICOM;
+       }
+}
+
+/* ----------------------------------------------------------------------- */
+/* ZORAN functions                                                        */
+/* ----------------------------------------------------------------------- */
+
+static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i);
+
+static
+void zoran_dump(struct zoran *ztv)
+{
+       char    str[1024];
+       char    *p=str; /* shut up, gcc! */
+       int     i;
+
+       for (i=0; i<0x60; i+=4) {
+               if ((i % 16) == 0) {
+                       if (i) printk(/*KERN_DEBUG*/ "%s\n",str);
+                       p = str;
+                       p+= sprintf(str, "       %04x: ",i);
+               }
+               p += sprintf(p, "%08x ",zrread(i));
+       }
+}
+
+static
+void reap_states(struct zoran* ztv)
+{
+       irq1++;         /* debugging... */
+
+       /*
+        * GRABBING?
+        */
+       if ( test_bit(STATE_GRAB, &ztv->state) ) {
+               int i;
+
+               /* are we already grabbing? */
+               if (test_bit(STATE_GRAB, &ztv->prevstate)) {
+
+                       /* did we get a complete grab? */
+                       if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
+                               goto out;
+
+                       /* we are done with this buffer, tell everyone */
+                       ztv->grabinfo[ztv->lastframe].status = FBUFFER_DONE;
+                       wake_up_interruptible(&ztv->grabq);
+               }
+
+               /* locate a new frame to grab */
+               for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
+                       if (ztv->grabinfo[i].status == FBUFFER_GRABBING) {
+
+                               /* there is a buffer more to be grabbed... */
+                               ztv->lastframe = i;
+
+DEBUG(printk(KERN_DEBUG "irq(%ld): starting grab(%d)\n",irq1,i));
+
+                               /* loadup the frame settings */
+                               read_lock(&ztv->lock);
+                               zoran_set_geo(ztv,&ztv->grabinfo[i]);
+                               read_unlock(&ztv->lock);
+
+                               zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+                               zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
+                               zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
+                               zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
+
+                               /* start single-shot grab */
+                               zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
+                               goto out;
+                       }
+
+DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to grab\n",irq1));
+
+               /* turn grabbing off the next time around */
+               clear_bit(STATE_GRAB, &ztv->state);
+
+               /* force re-init of Read or Overlay settings */
+               clear_bit(STATE_READ, &ztv->prevstate);
+               clear_bit(STATE_OVERLAY, &ztv->prevstate);
+       }
+
+       /*
+        * READING?
+        */
+       if ( test_bit(STATE_READ, &ztv->state) ) {
+               /* are we already reading? */
+               if (!test_bit(STATE_READ, &ztv->prevstate)) {
+
+DEBUG(printk(KERN_DEBUG "irq(%ld): starting read\n",irq1));
+
+                       read_lock(&ztv->lock);
+                       zoran_set_geo(ztv,&ztv->readinfo);
+                       read_unlock(&ztv->lock);
+
+                       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+                       zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
+                       zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
+                       zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
+
+                       /* start single-shot grab */
+                       zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
+                       goto out;
+               }
+
+               /* did we get a complete grab? */
+               if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
+                       goto out;
+
+DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to read\n",irq1));
+
+               /* turn reading off the next time around */
+               clear_bit(STATE_READ, &ztv->state);
+               /* force re-init of Overlay settings */
+               clear_bit(STATE_OVERLAY, &ztv->prevstate);
+
+               /* we are done, tell everyone */
+               wake_up_interruptible(&ztv->readq);
+       }
+
+       /*
+        * OVERLAYING?
+        */
+       if ( test_bit(STATE_OVERLAY, &ztv->state) ) {
+               /* are we already overlaying? */
+               if (!test_bit(STATE_OVERLAY, &ztv->prevstate)) {
+
+DEBUG(printk(KERN_DEBUG "irq(%ld): starting overlay\n",irq1));
+
+                       read_lock(&ztv->lock);
+                       zoran_set_geo(ztv,&ztv->overinfo);
+                       read_unlock(&ztv->lock);
+
+                       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+                       zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
+                       zror(ZORAN_OCR_OVLEN, ZORAN_OCR);
+                       zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
+               }
+
+               /*
+                * leave overlaying on, but turn interrupts off.
+                */
+               zrand(~ZORAN_ICR_EN,ZORAN_ICR);
+               goto out;
+       }
+
+       /*
+        * THEN WE MUST BE IDLING
+        */
+DEBUG(printk(KERN_DEBUG "irq(%ld): turning off\n",irq1));
+       /* nothing further to do, disable DMA and further IRQs */
+       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+       zrand(~ZORAN_ICR_EN,ZORAN_ICR);
+out:
+       ztv->prevstate = ztv->state;
+}
+
+static
+void zoran_irq(int irq, void *dev_id, struct pt_regs * regs)
+{
+       u32 stat,estat;
+       int count = 0;
+       struct zoran *ztv = (struct zoran *)dev_id;
+
+       for (;;) {
+               /* get/clear interrupt status bits */
+               stat=zrread(ZORAN_ISR);
+               estat=stat & zrread(ZORAN_ICR);
+               if (!estat)
+                       return;
+               zrwrite(estat,ZORAN_ISR);
+               IDEBUG(printk(KERN_DEBUG "%s: estat %08x\n",CARD,estat));
+               IDEBUG(printk(KERN_DEBUG "%s:  stat %08x\n",CARD,stat));
+
+               if (estat & ZORAN_ISR_CODE)
+               {
+                       IDEBUG(printk(KERN_DEBUG "%s: CodReplIRQ\n",CARD));
+               }
+               if (estat & ZORAN_ISR_GIRQ0)
+               {
+                       IDEBUG(printk(KERN_DEBUG "%s: GIRQ0\n",CARD));
+                       if (!ztv->card->usegirq1)
+                               reap_states(ztv);
+               }
+               if (estat & ZORAN_ISR_GIRQ1)
+               {
+                       IDEBUG(printk(KERN_DEBUG "%s: GIRQ1\n",CARD));
+                       if (ztv->card->usegirq1)
+                               reap_states(ztv);
+               }
+
+               count++;
+               if (count > 10)
+                       printk(KERN_ERR "%s: irq loop %d (%x)\n",CARD,count,estat);
+               if (count > 20)
+               {
+                       zrwrite(0, ZORAN_ICR);
+                       printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n",CARD);
+               }
+       }
+}
+
+/*
+ *      Scan for a Zoran chip, request the irq and map the io memory
+ */
+static int find_zoran(void)
+{
+       unsigned char command, latency;
+       int result;
+       struct zoran *ztv;
+       struct pci_dev *dev;
+       int zoran_num=0;
+
+       if (!pcibios_present())
+       {
+               DEBUG(printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n"));
+               return 0;
+       }
+
+       for (dev = pci_devices; dev != NULL; dev = dev->next)
+       {
+               if (dev->vendor != PCI_VENDOR_ID_ZORAN)
+                       continue;
+               if (dev->device != PCI_DEVICE_ID_ZORAN_36120)
+                       continue;
+
+               /* Ok, ZR36120 found! */
+               ztv=&zorans[zoran_num];
+               ztv->dev=dev;
+               ztv->id=dev->device;
+               ztv->zoran_mem=NULL;
+
+               ztv->zoran_adr = ztv->dev->resource[0].start;
+               pci_read_config_byte(ztv->dev, PCI_CLASS_REVISION,
+                            &ztv->revision);
+               printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
+                       ztv->id, ztv->revision);
+               printk("bus: %d, devfn: %d, ",
+                       ztv->dev->bus->number, ztv->dev->devfn);
+               printk("irq: %d, ",ztv->dev->irq);
+               printk("memory: 0x%08x.\n", ztv->zoran_adr);
+
+               ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000);
+               DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
+
+               result = request_irq(ztv->dev->irq, zoran_irq,
+                       SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv);
+               if (result==-EINVAL)
+               {
+                       printk(KERN_ERR "zoran: Bad irq number or handler\n");
+                       return -EINVAL;
+               }
+               if (result==-EBUSY)
+               {
+                       printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",ztv->dev->irq);
+                       return result;
+               }
+               if (result < 0)
+                       return result;
+
+               /* Enable bus-mastering */
+               pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
+               command|=PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY;
+               pci_write_config_byte(ztv->dev, PCI_COMMAND, command);
+               pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
+               if (!(command&PCI_COMMAND_MASTER))
+               {
+                       printk(KERN_ERR "zoran: PCI bus-mastering could not be enabled\n");
+                       return -1;
+               }
+               pci_read_config_byte(ztv->dev, PCI_LATENCY_TIMER, &latency);
+               if (!latency)
+               {
+                       latency=32;
+                       pci_write_config_byte(ztv->dev, PCI_LATENCY_TIMER, latency);
+                       DEBUG(printk(KERN_INFO "zoran: latency set to %d\n",latency));
+               }
+               zoran_num++;
+       }
+       if(zoran_num)
+               printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num);
+       return zoran_num;
+}
+
+static
+int zoran_muxsel(struct zoran* ztv, int channel, int norm)
+{
+       int     rv;
+
+       /* set the new video norm */
+       rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
+       if (rv)
+               return rv;
+       ztv->norm = norm;
+
+       /* map the given channel to the cards decoder's channel */
+       channel = ztv->card->video_mux[channel] & CHANNEL_MASK;
+
+       /* set the new channel */
+       rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel);
+       return rv;
+}
+
+/* Tell the interrupt handler what to to.  */
+static
+void zoran_cap(struct zoran* ztv, int on)
+{
+       DEBUG(printk(KERN_DEBUG "       zoran_cap(%d) at %ld, state=%x\n",on,irq1,ztv->state));
+
+       if (on) {
+               ztv->running = 1;
+               /* 
+                * Clear the previous state flag. This way the irq
+                * handler will be forced to re-examine its current
+                * state from scratch, setting up the registers along
+                * the way.
+                */
+               clear_bit(STATE_OVERLAY, &ztv->prevstate);
+               /*
+                * turn interrupts back on. The DMA will be enabled
+                * inside the irq handler when it detects a restart.
+                */
+               zror(ZORAN_ICR_CODE|ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1,ZORAN_ICR);
+               zror(ZORAN_ICR_EN,ZORAN_ICR);
+       }
+       else {
+               ztv->running = 0;
+               /*
+                * turn interrupts and DMA both off
+                */
+               zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+               zrand(~ZORAN_ICR_EN,ZORAN_ICR);
+       }
+}
+
+static ulong dmask[] = {
+       0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8,
+       0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80,
+       0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800,
+       0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000,
+       0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000,
+       0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000,
+       0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000,
+       0xF0000000, 0xE0000000, 0xC0000000, 0x80000000
+};
+
+static
+void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp)
+{
+       ulong*  mtop;
+       int     ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */
+       int     mult = ztv->interlace;          /* double height? */
+       int     i;
+
+       DEBUG(printk(KERN_DEBUG "       overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count));
+       if (ztv->overinfo.overlay == 0) {
+               zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
+               return;
+       }
+
+for (i=0; i<count; i++) {
+       struct video_clip *vp = vcp+i;
+       DEBUG(printk(KERN_DEBUG "       %d: clip(%d,%d,%d,%d)\n",
+               i,vp->x,vp->y,vp->width,vp->height));
+}
+
+       /* clear entire blob */
+/*     memset(ztv->overinfo.overlay, 0, 1024*1024/8); */
+
+       /*
+        * activate the visible portion of the screen
+        * Note we take some shortcuts here, because we
+        * know the width can never be < 32. (I.e. a DWORD)
+        * We also assume the overlay starts somewhere in
+        * the FIRST dword.
+        */
+       {
+               int start = ztv->vidXshift;
+               ulong firstd = dmask[start];
+               ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31];
+               mtop = ztv->overinfo.overlay;
+               for (i=0; i<ztv->overinfo.h; i++) {
+                       int w = ztv->vidWidth;
+                       ulong* line = mtop;
+                       if (start & 31) {
+                               *line++ = firstd;
+                               w -= 32-(start&31);
+                       }
+                       memset(line, ~0, w/8);
+                       if (w & 31)
+                               line[w/32] = lastd;
+                       mtop += ystep;
+               }
+       }
+
+       /* process clipping regions */
+       for (i=0; i<count; i++) {
+               int h;
+               if (vcp->x < 0 || vcp->x > ztv->overinfo.w ||
+                   vcp->y < 0 || vcp->y > ztv->overinfo.h ||
+                   vcp->width < 0 || (vcp->x+vcp->width) > ztv->overinfo.w ||
+                   vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h)
+               {
+                       DEBUG(printk(KERN_DEBUG "%s: illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h));
+                       if (vcp->x < 0) vcp->x = 0;
+                       if (vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w;
+                       if (vcp->y < 0) vcp->y = 0;
+                       if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h;
+                       if (vcp->width < 0) vcp->width = 0;
+                       if (vcp->x+vcp->width > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x;
+                       if (vcp->height < 0) vcp->height = 0;
+                       if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y;
+//                     continue;
+               }
+
+               mtop = &ztv->overinfo.overlay[vcp->y*ystep];
+               for (h=0; h<=vcp->height; h++) {
+                       int w;
+                       int x = ztv->vidXshift + vcp->x;
+                       for (w=0; w<=vcp->width; w++) {
+                               clear_bit(x&31, &mtop[x/32]);
+                               x++;
+                       }
+                       mtop += ystep;
+               }
+               ++vcp;
+       }
+
+       mtop = ztv->overinfo.overlay;
+       zrwrite(virt_to_bus(mtop), ZORAN_MTOP);
+       zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT);
+       zraor((mult*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
+}
+
+struct tvnorm 
+{
+       u16 Wt, Wa, Ht, Ha, HStart, VStart;
+};
+
+static struct tvnorm tvnorms[] = {
+       /* PAL-BDGHI */
+/*     { 864, 720, 625, 576, 131, 21 },*/
+/*00*/ { 864, 768, 625, 576, 81, 17 },
+       /* NTSC */
+/*01*/ { 858, 720, 525, 480, 121, 10 },
+       /* SECAM */
+/*02*/ { 864, 720, 625, 576, 131, 21 },
+       /* BW50 */
+/*03*/ { 864, 720, 625, 576, 131, 21 },
+       /* BW60 */
+/*04*/ { 858, 720, 525, 480, 121, 10 }
+};
+#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
+
+static
+void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
+{
+       ulong   top, bot;
+       int     stride;
+       int     winWidth, winHeight;
+       int     maxWidth, maxHeight, maxXOffset, maxYOffset;
+       int     filter;
+
+       DEBUG(printk(KERN_DEBUG "       set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, vidadr=%lx, overlay=%p)\n", i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->vidadr,i->overlay));
+
+       /*
+        * make sure the DMA transfers are inhibited during our
+        * reprogramming of the chip
+        */
+       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+
+       maxWidth = tvnorms[ztv->norm].Wa;
+       maxHeight = tvnorms[ztv->norm].Ha;
+       maxXOffset = tvnorms[ztv->norm].HStart;
+       maxYOffset = tvnorms[ztv->norm].VStart;
+
+       /*
+        * Set top, bottom ptrs. Since these must be DWORD aligned,
+        * possible adjust the x and the width of the window.
+        * so the endposition stay the same. The vidXshift will make
+        * sure we are not writing pixels before the requested x.
+        */
+       ztv->vidXshift = 0;
+       winWidth = i->w;
+       top = i->vidadr + i->x*i->bpp + i->y*i->bpl;
+       if (top & 3) {
+               ztv->vidXshift = (top & 3) / i->bpp;
+               winWidth += ztv->vidXshift;
+               DEBUG(printk(KERN_DEBUG "       window-x shifted %d pixels left\n",ztv->vidXshift));
+               top &= ~3;
+       }
+
+       /*
+        * bottom points to next frame but in interleaved mode we want
+        * to 'mix' the 2 frames to one capture, so 'bot' points to one
+        * (physical) line below the top line.
+        */
+       bot = top + i->bpl;
+       zrwrite(top,ZORAN_VTOP);
+       zrwrite(bot,ZORAN_VBOT);
+
+       /*
+        * Make sure the winWidth is DWORD aligned too,
+        * thereby automaticly making sure the stride to the
+        * next line is DWORD aligned too (as required by spec).
+        */
+       if ((winWidth*i->bpp) & 3) {
+               DEBUG(printk(KERN_DEBUG "       window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3));
+               winWidth += (winWidth*i->bpp) & 3;
+       }
+
+       /* determine the DispMode and stride */
+       if (i->h <= maxHeight/2) {
+               /* single frame suffices for this height */
+               zror(ZORAN_VFEC_DISPMOD, ZORAN_VFEC);
+               ztv->interlace = 0;
+               winHeight = i->h;
+               if (winHeight < 0)      /* can happen for read's! */
+                       winHeight = -winHeight;
+               stride = i->bpl - (winWidth*i->bpp);
+       }
+       else {
+               /* interleaving needed for this height */
+               zrand(~ZORAN_VFEC_DISPMOD, ZORAN_VFEC);
+               ztv->interlace = 1;
+               winHeight = i->h/2;
+               stride = i->bpl*2 - (winWidth*i->bpp);
+       }
+       /* safety net, sometimes bpl is too short??? */
+       if (stride<0) {
+               DEBUG(printk(KERN_DEBUG "%s: WARNING stride = %d\n",CARD,stride));
+               stride = 0;
+       }
+
+       zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC);
+       zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR);
+
+       /* remember vidWidth, vidHeight for overlay calculations */
+       ztv->vidWidth = winWidth;
+       ztv->vidHeight = winHeight;
+DEBUG(printk(KERN_DEBUG "       top=%08lx, bottom=%08lx, winWidth=%d, winHeight=%d, maxWidth=%d, maxHeight=%d, stride=%d\n",top,bot,winWidth,winHeight,maxWidth,maxHeight,stride));
+
+       /* determine scales and crops */
+       if (1) {
+               int Wa, X, We, HorDcm, hcrop1, hcrop2, Hstart, Hend;
+
+A:             Wa = maxWidth;
+               X = (winWidth*64+Wa-1)/Wa;
+               We = winWidth*64/X;
+               HorDcm = 64-X;
+               hcrop1 = 2*(Wa-We)/4;
+               hcrop2 = Wa-We-hcrop1;
+               Hstart = maxXOffset + hcrop1;
+               Hend = maxXOffset + Wa-1-hcrop2;
+
+               /*
+                * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi> 
+                * found the solution to the color phase shift.
+                * See ChangeLog for the full explanation)
+                */
+               if (!(Hstart & 1)) {
+DEBUG(printk(KERN_DEBUG "       correcting horizontal start/end by one\n"));
+                       winWidth--;
+                       goto A;
+               }
+
+DEBUG(printk(KERN_DEBUG "       X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend));
+
+               zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
+               zraor((HorDcm<<14),~ZORAN_VFEC_HORDCM, ZORAN_VFEC);
+
+               filter = ZORAN_VFEC_HFILTER_1;
+               if (HorDcm >= 48)
+                       filter = ZORAN_VFEC_HFILTER_5; /* 5 tap filter */
+               else if (HorDcm >= 32)
+                       filter = ZORAN_VFEC_HFILTER_4; /* 4 tap filter */
+               else if (HorDcm >= 16)
+                       filter = ZORAN_VFEC_HFILTER_3; /* 3 tap filter */
+               zraor(filter, ~ZORAN_VFEC_HFILTER, ZORAN_VFEC);
+       }
+       /* when height is negative, we want to read from line 0 */
+       if (i->h < 0) {
+               int Vstart = 0;
+               int Vend = Vstart + winHeight;
+               int VerDcm = 0;
+DEBUG(printk(KERN_DEBUG "       Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
+               zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
+               zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC);
+       }
+       else {
+               int Ha = maxHeight/2;
+               int Y = (winHeight*64+Ha-1)/Ha;
+               int He = winHeight*64/Y;
+               int VerDcm = 64-Y;
+               int vcrop1 = 2*(Ha-He)/4;
+               int vcrop2 = Ha-He-vcrop1;
+               int Vstart = maxYOffset + vcrop1;
+               int Vend = maxYOffset + Ha-1-vcrop2;
+
+DEBUG(printk(KERN_DEBUG "       Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
+               zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
+               zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC);
+       }
+
+DEBUG(printk(KERN_DEBUG "       F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name));
+       /* setup the requested format */
+       zraor(palette2fmt[i->format].mode, ~(ZORAN_VFEC_RGB|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24), ZORAN_VFEC);
+}
+
+#if LINUX_VERSION_CODE >= 0x020100
+static
+unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait)
+{
+       struct zoran *ztv = (struct zoran *)dev;
+
+       poll_wait(file, &ztv->readq, wait);
+
+       return (POLLIN | POLLRDNORM);
+}
+#endif
+
+/*
+ * Open a zoran card. Right now the flags are just a hack
+ */
+static int zoran_open(struct video_device *dev, int flags)
+{
+       struct zoran *ztv = (struct zoran*)dev;
+       int     i;
+
+       DEBUG(printk(KERN_DEBUG "%s: open(dev,%d)\n",CARD,flags));
+
+       switch (flags) {
+        case 0:
+               /* already active? */
+               if (ztv->user)
+                       return -EBUSY;
+               ztv->user++;
+
+               /* unmute audio */
+               /* /what/ audio? */
+
+/******************************************
+ We really should be doing lazy allocing...
+ ******************************************/
+               /* allocate a frame buffer */
+               if (!ztv->fbuffer)
+                       ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE);
+               if (!ztv->fbuffer) {
+                       /* could not get a buffer, bail out */
+                       ztv->user--;
+                       return -ENOBUFS;
+               }
+               /* at this time we _always_ have a framebuffer */
+               memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE);
+
+               if (!ztv->overinfo.overlay)
+                       ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL);
+               if (!ztv->overinfo.overlay) {
+                       /* could not get an overlay buffer, bail out */
+                       ztv->user--;
+                       bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
+                       return -ENOBUFS;
+               }
+               /* at this time we _always_ have a overlay */
+
+               /* clear buffer status */
+               for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
+                       ztv->grabinfo[i].status = FBUFFER_UNUSED;
+               ztv->state = 0;
+               ztv->prevstate = 0;
+               ztv->lastframe = -1;
+
+               /* setup the encoder to the initial values */
+               i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture);
+
+               /* default to the compisite input since my camera is there */
+               zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);
+               break;
+        case 1:
+               break;
+       }
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static
+void zoran_close(struct video_device* dev)
+{
+       struct zoran *ztv = (struct zoran*)dev;
+
+       DEBUG(printk(KERN_DEBUG "%s: close(dev)\n",CARD));
+
+       /* we are no longer active, goodbye */
+       ztv->user--;
+
+       /* mute audio */
+       /* stop the chip */
+       zoran_cap(ztv, 0);
+
+       /* free the allocated framebuffer */
+       if (ztv->fbuffer)
+               bfree( ztv->fbuffer, ZORAN_MAX_FBUFSIZE );
+       ztv->fbuffer = 0;
+       if (ztv->overinfo.overlay)
+               kfree( ztv->overinfo.overlay );
+       ztv->overinfo.overlay = 0;
+
+       MOD_DEC_USE_COUNT;
+}
+
+static
+long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock)
+{
+       DEBUG(printk(KERN_DEBUG "zoran_write\n"));
+       return -EINVAL;
+}
+
+static
+long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
+{
+       struct zoran *ztv = (struct zoran*)dev;
+       int     max;
+
+       DEBUG(printk(KERN_DEBUG "zoran_read(%p,%ld,%d)\n",buf,count,nonblock));
+
+       /* tell the state machine we want in too */
+       write_lock_irq(&ztv->lock);
+       ztv->readinfo.vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer));
+       set_bit(STATE_READ, &ztv->state);
+       write_unlock_irq(&ztv->lock);
+       zoran_cap(ztv, 1);
+
+       /* wait for data to arrive */
+       interruptible_sleep_on(&ztv->readq);
+
+       /* see if a signal did it */
+       if (signal_pending(current))
+               return -ERESTARTSYS;
+
+       /* give the user what he requested */
+       max = ztv->readinfo.w*ztv->readinfo.bpp - ztv->readinfo.h*ztv->readinfo.bpl;
+       if (count > max)
+               count = max;
+       if (copy_to_user((void*)buf, (void*)ztv->fbuffer, count))
+               return -EFAULT;
+
+       /* goodbye */
+       return count;
+}
+
+/* append a new clipregion to the vector of video_clips */
+static
+void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h)
+{
+       vcp[vw->clipcount].x = x;
+       vcp[vw->clipcount].y = y;
+       vcp[vw->clipcount].width = w;
+       vcp[vw->clipcount].height = h;
+       vw->clipcount++;
+}
+
+static
+int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
+{
+       struct zoran* ztv = (struct zoran*)dev;
+
+       switch (cmd) {
+        case VIDIOCGCAP:
+        {      /* get video capabilities */
+               struct video_capability c;
+               struct video_decoder_capability dc;
+               int rv;
+               DEBUG(printk(KERN_DEBUG "%s: GetCapabilities\n",CARD));
+
+               /* fetch the capabilites of the decoder */
+               dc.flags = 0;
+               dc.inputs = -1;
+               dc.outputs = -1;
+               rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc);
+               if (rv)
+                       return rv;
+               DEBUG(printk(KERN_DEBUG "%s: capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs));
+
+               strcpy(c.name,ztv->video_dev.name);
+               c.type = VID_TYPE_CAPTURE|
+                        VID_TYPE_OVERLAY|
+                        VID_TYPE_CLIPPING|
+                        VID_TYPE_FRAMERAM|
+                        VID_TYPE_SCALES;
+               c.channels = ztv->card->video_inputs;
+               c.audios = ztv->card->audio_inputs;
+               c.maxwidth = 768;
+               c.maxheight = 576;
+               c.minwidth = 32;
+               c.minheight = 32;
+               if (copy_to_user(arg,&c,sizeof(c)))
+                       return -EFAULT;
+               return 0;
+        }
+
+        case VIDIOCGCHAN:
+        {
+               struct video_channel v;
+               int mux;
+
+               if (copy_from_user(&v, arg,sizeof(v)))
+                       return -EFAULT;
+               DEBUG(printk(KERN_DEBUG "%s: GetChannel(%d)\n",CARD,v.channel));
+               v.flags=VIDEO_VC_AUDIO
+#ifdef VIDEO_VC_NORM
+                       |VIDEO_VC_NORM
+#endif
+                       ;
+               v.tuners=0;
+               v.type=VIDEO_TYPE_CAMERA;
+#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API
+               v.norm=VIDEO_MODE_PAL|
+                      VIDEO_MODE_NTSC|
+                      VIDEO_MODE_SECAM;
+#else
+               v.norm=VIDEO_MODE_PAL;
+#endif
+               /* too many inputs? */
+               if (v.channel >= ztv->card->video_inputs)
+                       return -EINVAL;
+
+               /* now determine the name of the channel */
+               mux = ztv->card->video_mux[v.channel];
+               if (mux & IS_TUNER) {
+                       /* lets assume only one tuner, yes? */
+                       strcpy(v.name,"Television");
+                       v.type = VIDEO_TYPE_TV;
+                       if (ztv->have_tuner) {
+                               v.flags |= VIDEO_VC_TUNER;
+                               v.tuners = 1;
+                       }
+               }
+               else if (mux & IS_SVHS)
+                       sprintf(v.name,"S-Video-%d",v.channel);
+               else
+                       sprintf(v.name,"CVBS-%d",v.channel);
+
+               if (copy_to_user(arg,&v,sizeof(v)))
+                       return -EFAULT;
+               return 0;
+        }
+        case VIDIOCSCHAN:
+        {      /* set video channel */
+               struct video_channel v;
+               if (copy_from_user(&v, arg,sizeof(v)))
+                       return -EFAULT;
+               DEBUG(printk(KERN_DEBUG "%s: SetChannel(%d,%d)\n",CARD,v.channel,v.norm));
+               if (v.channel >= ztv->card->video_inputs)
+                       return -EINVAL;
+
+               if (v.norm != VIDEO_MODE_PAL &&
+                   v.norm != VIDEO_MODE_NTSC &&
+                   v.norm != VIDEO_MODE_SECAM &&
+                   v.norm != VIDEO_MODE_AUTO)
+                       return -EOPNOTSUPP;
+
+               /* make it happen, nr1! */
+               return zoran_muxsel(ztv,v.channel,v.norm);
+        }
+
+        case VIDIOCGTUNER:
+        {
+               struct video_tuner v;
+               if (copy_from_user(&v, arg,sizeof(v)))
+                       return -EFAULT;
+
+               /* Only one tuner for now */
+               if (!ztv->have_tuner && v.tuner)
+                       return -EINVAL;
+
+               strcpy(v.name,"Television");
+               v.rangelow  = 0;
+               v.rangehigh = ~0;
+               v.flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
+               v.mode      = ztv->norm;
+               v.signal    = 0xFFFF; /* unknown */
+
+               if (copy_to_user(arg,&v,sizeof(v)))
+                       return -EFAULT;
+               return 0;
+        }
+
+        case VIDIOCSTUNER:
+        {
+               struct video_tuner v;
+               if (copy_from_user(&v, arg, sizeof(v)))
+                       return -EFAULT;
+
+               /* Only one tuner for now */
+               if (!ztv->have_tuner && v.tuner)
+                       return -EINVAL;
+
+               /* and it only has certain valid modes */
+               if( v.mode != VIDEO_MODE_PAL &&
+                   v.mode != VIDEO_MODE_NTSC &&
+                   v.mode != VIDEO_MODE_SECAM)
+                       return -EOPNOTSUPP;
+
+               /* engage! */
+               return zoran_muxsel(ztv,v.tuner,v.mode);
+        }
+
+        case VIDIOCGPICT:
+        {
+               struct video_picture p = ztv->picture;
+               DEBUG(printk(KERN_DEBUG "%s: GetPicture\n",CARD));
+               p.depth = ztv->depth;
+               switch (p.depth) {
+                case  8: p.palette=VIDEO_PALETTE_YUV422;
+                         break;
+                case 15: p.palette=VIDEO_PALETTE_RGB555;
+                         break;
+                case 16: p.palette=VIDEO_PALETTE_RGB565;
+                         break;
+                case 24: p.palette=VIDEO_PALETTE_RGB24;
+                         break;
+                case 32: p.palette=VIDEO_PALETTE_RGB32;
+                         break;
+               }
+               if (copy_to_user(arg, &p, sizeof(p)))
+                       return -EFAULT;
+               return 0;
+        }
+        case VIDIOCSPICT:
+        {
+               struct video_picture p;
+               DEBUG(printk(KERN_DEBUG "%s: SetPicture\n",CARD));
+               if (copy_from_user(&p, arg,sizeof(p)))
+                       return -EFAULT;
+
+               /* depth must match with framebuffer */
+               if (p.depth != ztv->depth)
+                       return -EINVAL;
+
+               /* check if palette matches this bpp */
+               if (p.palette<1 || p.palette>NRPALETTES ||
+                   palette2fmt[p.palette].bpp != ztv->overinfo.bpp)
+                       return -EINVAL;
+
+               write_lock_irq(&ztv->lock);
+               ztv->overinfo.format = p.palette;
+               ztv->picture = p;
+               write_unlock_irq(&ztv->lock);
+
+               /* tell the decoder */
+               i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
+               return 0;
+        }
+
+        case VIDIOCGWIN:
+        {
+               struct video_window vw;
+               DEBUG(printk(KERN_DEBUG "%s: GetWindow\n",CARD));
+               read_lock(&ztv->lock);
+               vw.x      = ztv->overinfo.x;
+               vw.y      = ztv->overinfo.y;
+               vw.width  = ztv->overinfo.w;
+               vw.height = ztv->overinfo.h;
+               vw.chromakey= 0;
+               vw.flags  = 0;
+               if (ztv->interlace)
+                       vw.flags|=VIDEO_WINDOW_INTERLACE;
+               read_unlock(&ztv->lock);
+               if (copy_to_user(arg,&vw,sizeof(vw)))
+                       return -EFAULT;
+               return 0;
+        }
+        case VIDIOCSWIN:
+        {
+               struct video_window vw;
+               struct video_clip *vcp;
+               int on;
+
+               if (copy_from_user(&vw,arg,sizeof(vw)))
+                       return -EFAULT;
+
+               DEBUG(printk(KERN_DEBUG "%s: SetWindow(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
+
+               if (vw.flags)
+                       return -EINVAL;
+
+               if (vw.clipcount>256)
+                       return -EDOM;   /* Too many! */
+
+               /*
+                *      Do any clips.
+                */
+               vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4));
+               if (vcp==NULL)
+                       return -ENOMEM;
+               if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount))
+                       return -EFAULT;
+
+               on = ztv->running;
+               if (on)
+                       zoran_cap(ztv, 0);
+
+               /* by now we are committed to the new data... */
+               write_lock_irq(&ztv->lock);
+               ztv->overinfo.x = vw.x;
+               ztv->overinfo.y = vw.y;
+               ztv->overinfo.w = vw.width;
+               ztv->overinfo.h = vw.height;
+               write_unlock_irq(&ztv->lock);
+
+               /*
+                *      Impose display clips
+                */
+               if (vw.x<0)
+                       new_clip(&vw, vcp, 0, 0, -vw.x, vw.height-1);
+               if (vw.y<0)
+                       new_clip(&vw, vcp, 0, 0, vw.width-1,-vw.y);
+               if (vw.x+vw.width > ztv->swidth)
+                       new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1);
+               if (vw.y+vw.height > ztv->sheight)
+                       new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1);
+
+               /* built the requested clipping zones */
+               zoran_set_geo(ztv, &ztv->overinfo);
+               zoran_built_overlay(ztv, vw.clipcount, vcp);
+               vfree(vcp);
+
+               /* if we were on, restart the video engine */
+               if (on) zoran_cap(ztv, on);
+               return 0;
+        }
+        case VIDIOCCAPTURE:
+        {
+               int v;
+               get_user_ret(v,(int*)arg, -EFAULT);
+               DEBUG(printk(KERN_DEBUG "%s: Capture(%d)\n",CARD,v));
+
+               if (v==0) {
+                       zoran_cap(ztv, 0);
+                       clear_bit(STATE_OVERLAY, &ztv->state);
+               }
+               else {
+                       /* is VIDIOCSFBUF, VIDIOCSWIN done? */
+                       if (ztv->overinfo.vidadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
+                               return -EINVAL;
+
+                       set_bit(STATE_OVERLAY, &ztv->state);
+                       zoran_cap(ztv, 1);
+               }
+               return 0;
+        }
+
+        case VIDIOCGFBUF:
+        {
+               struct video_buffer v;
+               DEBUG(printk(KERN_DEBUG "%s: GetFramebuffer\n",CARD));
+               read_lock(&ztv->lock);
+               v.base   = (void *)ztv->overinfo.vidadr;
+               v.height = ztv->sheight;
+               v.width  = ztv->swidth;
+               v.depth  = ztv->depth;
+               v.bytesperline = ztv->overinfo.bpl;
+               read_unlock(&ztv->lock);
+               if(copy_to_user(arg, &v,sizeof(v)))
+                       return -EFAULT;
+               return 0;
+        }
+        case VIDIOCSFBUF:
+        {
+               struct video_buffer v;
+#if LINUX_VERSION_CODE >= 0x020100
+                       if(!capable(CAP_SYS_ADMIN))
+#else
+                       if(!suser())
+#endif
+                       return -EPERM;
+               if (copy_from_user(&v, arg,sizeof(v)))
+                       return -EFAULT;
+               if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
+                       return -EINVAL;
+               if (v.bytesperline<1)
+                       return -EINVAL;
+               if (ztv->running)
+                       return -EBUSY;
+               write_lock_irq(&ztv->lock);
+               ztv->overinfo.vidadr  = (unsigned long)v.base;
+               ztv->sheight      = v.height;
+               ztv->swidth       = v.width;
+               ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
+               ztv->depth        = v.depth;            /* bits per pixel */
+               ztv->overinfo.bpl = v.bytesperline;
+               write_unlock_irq(&ztv->lock);
+
+               DEBUG(printk(KERN_DEBUG "%s: SetFrameBuffer(%p,%dx%d, bpp %d, bpl %d)\n",CARD,v.base, v.width,v.height, ztv->overinfo.bpp, ztv->overinfo.bpl));
+               return 0;
+        }
+
+        case VIDIOCSYNC:
+        {
+               int i;
+               get_user_ret(i,(int*)arg, -EFAULT);
+               DEBUG(printk(KERN_DEBUG "%s: VIDEOCSYNC(%d)\n",CARD,i));
+               if (i<0 || i>ZORAN_MAX_FBUFFERS)
+                       return -EINVAL;
+               switch (ztv->grabinfo[i].status) {
+                case FBUFFER_UNUSED:
+                       return -EINVAL;
+                case FBUFFER_GRABBING:
+                       /* wait till this buffer gets grabbed */
+                       while (ztv->grabinfo[i].status == FBUFFER_GRABBING) {
+                               interruptible_sleep_on(&ztv->grabq);
+                               /* see if a signal did it */
+                               if (signal_pending(current))
+                                       return -ERESTARTSYS;
+                       }
+                       /* fall through */
+                case FBUFFER_DONE:
+                       ztv->grabinfo[i].status = FBUFFER_UNUSED;
+                       break;
+               }
+               return 0;
+        }
+
+        case VIDIOCKEY:
+        {
+               /* Will be handled higher up .. */
+               return 0;
+        }
+
+        case VIDIOCMCAPTURE:
+        {
+               struct video_mmap vm;
+               struct vidinfo* frame;
+               if (copy_from_user(&vm,arg,sizeof(vm)))
+                       return -EFAULT;
+               if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS ||
+                   vm.width<32 || vm.width>768 ||
+                   vm.height<32 || vm.height>576 ||
+                   vm.format<0 || vm.format>NRPALETTES ||
+                   palette2fmt[vm.format].mode == 0)
+                       return -EINVAL;
+
+               DEBUG(printk(KERN_DEBUG "%s: Mcapture(%d,(%d,%d),%d=%s)\n",CARD,vm.frame,vm.width,vm.height,vm.format,palette2fmt[vm.format].name));
+               frame = &ztv->grabinfo[vm.frame];
+               if (frame->status == FBUFFER_GRABBING)
+                       return -EBUSY;
+
+               /* setup the other parameters if they are given */
+               write_lock_irq(&ztv->lock);
+               if (vm.width)
+                       frame->w = vm.width;
+               if (vm.height)
+                       frame->h = vm.height;
+               if (vm.format)
+                       frame->format = vm.format;
+               frame->bpp = palette2fmt[frame->format].bpp;
+               frame->bpl = frame->w*frame->bpp;
+               frame->vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer+vm.frame*ZORAN_MAX_FBUFFER));
+               frame->status = FBUFFER_GRABBING;
+               set_bit(STATE_GRAB, &ztv->state);
+               write_unlock_irq(&ztv->lock);
+
+               zoran_cap(ztv, 1);
+               return 0;
+        }
+
+        case VIDIOCGMBUF:
+        {
+               struct video_mbuf mb;
+               int i;
+               DEBUG(printk(KERN_DEBUG "%s: GetMemoryBuffer\n",CARD));
+               mb.size = ZORAN_MAX_FBUFSIZE;
+               mb.frames = ZORAN_MAX_FBUFFERS;
+               for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
+                       mb.offsets[i] = i*ZORAN_MAX_FBUFFER;
+               if(copy_to_user(arg, &mb,sizeof(mb)))
+                       return -EFAULT;
+               return 0;
+        }
+
+        case VIDIOCGUNIT:
+        {
+               struct video_unit vu;
+               DEBUG(printk(KERN_DEBUG "%s: GetUnit\n",CARD));
+               vu.video = ztv->video_dev.minor;
+               vu.vbi = VIDEO_NO_UNIT;
+               vu.radio = VIDEO_NO_UNIT;
+               vu.audio = VIDEO_NO_UNIT;
+               vu.teletext = VIDEO_NO_UNIT;
+               if(copy_to_user(arg, &vu,sizeof(vu)))
+                       return -EFAULT;
+               return 0;
+        }
+
+        case VIDIOCGFREQ:
+        {
+               unsigned long v = ztv->tuner_freq;
+               if (copy_to_user(arg,&v,sizeof(v)))
+                       return -EFAULT;
+               return 0;
+        }
+
+        case VIDIOCSFREQ:
+        {
+               unsigned long v;
+               if (copy_from_user(&v, arg, sizeof(v)))
+                       return -EFAULT;
+
+               if (ztv->have_tuner) {
+                       int fixme = v;
+                       if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0)
+                               return -EAGAIN;
+               }
+               ztv->tuner_freq = v;
+               return 0;
+        }
+
+        case VIDIOCGAUDIO:
+        case VIDIOCSAUDIO:
+        case VIDIOCGCAPTURE:
+        case VIDIOCSCAPTURE:
+               DEBUG(printk(KERN_DEBUG "%s: unhandled video ioctl(%x)\n",CARD,cmd));
+               return -EINVAL;
+
+        default:
+               DEBUG(printk(KERN_DEBUG "%s: bad ioctl(%x)\n",CARD,cmd));
+       }
+       return -EPERM;
+}
+
+static
+int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size)
+{
+       struct zoran* ztv = (struct zoran*)dev;
+       unsigned long start = (unsigned long)adr;
+       unsigned long pos;
+
+       DEBUG(printk(KERN_DEBUG "zoran_mmap(0x%p,%ld)\n",adr,size));
+
+       /* sanity checks */
+       if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer)
+               return -EINVAL;
+
+       /* start mapping the whole shabang to user memory */
+       pos = (unsigned long)ztv->fbuffer;
+       while (size>0) {
+#ifdef CONFIG_BIGPHYS_AREA
+               unsigned long page = virt_to_phys((void*)pos);
+#else
+               unsigned long page = kvirt_to_phys(pos);
+#endif
+               if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       return 0;
+}
+
+static struct video_device zoran_template=
+{
+       "UNSET",
+       VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
+       VID_HARDWARE_ZR36120,
+
+       zoran_open,
+       zoran_close,
+       zoran_read,
+       zoran_write,
+#if LINUX_VERSION_CODE >= 0x020100
+       zoran_poll,             /* poll */
+#endif
+       zoran_ioctl,
+       zoran_mmap,
+       NULL,                   /* initialize */
+       NULL,
+       0,
+       -1
+};
+
+static
+int init_zoran(int card)
+{
+       struct zoran *ztv = &zorans[card];
+       int     i;
+
+       /* if the given cardtype valid? */
+       if (cardtype[card]<0 || cardtype[card]>=NRTVCARDS) {
+               printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]);
+               return -1;
+       }
+
+       /* reset the zoran */
+       zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI);
+       udelay(10);
+       zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
+       udelay(10);
+
+       /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
+
+       /* framegrabber details */
+       ztv->swidth=800;
+       ztv->sheight=600;
+       ztv->depth=16;
+
+       /* channel details */
+       ztv->norm=0;                            /* PAL */
+       ztv->card=tvcards+cardtype[card];       /* point to the selected card */
+       ztv->tuner_freq = 0;
+
+       ztv->overinfo.status = FBUFFER_UNUSED;
+       ztv->overinfo.x = 0;
+       ztv->overinfo.y = 0;
+       ztv->overinfo.w = 768; /* 640 */
+       ztv->overinfo.h = 576; /* 480 */
+       ztv->overinfo.format = VIDEO_PALETTE_RGB565;
+       ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp;
+       ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth;
+       ztv->overinfo.vidadr = 0;
+       ztv->overinfo.overlay = 0;
+
+       ztv->readinfo = ztv->overinfo;
+       ztv->readinfo.w = 768;
+       ztv->readinfo.h = -22;
+       ztv->readinfo.format = VIDEO_PALETTE_YUV422;
+       ztv->readinfo.bpp = palette2fmt[ztv->readinfo.format].bpp;
+       ztv->readinfo.bpl = ztv->readinfo.w*ztv->readinfo.bpp;
+
+       /* grabbing details */
+       for (i=0; i<ZORAN_MAX_FBUFFERS; i++) {
+               ztv->grabinfo[i] = ztv->overinfo;
+               ztv->grabinfo[i].format = VIDEO_PALETTE_RGB24;
+       }
+
+       /* maintenance data */
+       ztv->fbuffer = NULL;
+       ztv->user = 0;
+       ztv->have_decoder = 0;
+       ztv->have_tuner = 0;
+       ztv->running = 0;
+       init_waitqueue_head(&ztv->grabq);
+       init_waitqueue_head(&ztv->readq);
+       ztv->lock = RW_LOCK_UNLOCKED;
+       ztv->state = 0;
+       ztv->prevstate = 0;
+       ztv->lastframe = -1;
+
+       /* picture details */
+       ztv->picture.colour=254<<7;
+       ztv->picture.brightness=128<<8;
+       ztv->picture.hue=128<<8;
+       ztv->picture.contrast=216<<7;
+
+       if (triton1)
+               zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC);
+
+       /* external FL determines TOP frame */
+       zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); 
+
+       /* set HSpol */
+       if (ztv->card->hsync_pos)
+               zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH);
+       /* set VSpol */
+       if (ztv->card->vsync_pos)
+               zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV);
+
+       /* Set the proper General Purpuse register bits */
+       /* implicit: no softreset, 0 waitstates */
+       zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI);
+       /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */
+       zrwrite(ztv->card->gpval<<24,ZORAN_GUEST);
+       
+       /* clear interrupt status */
+       zrwrite(~0, ZORAN_ISR);
+
+       /*
+        * i2c template
+        */
+       ztv->i2c = zoran_i2c_bus_template;
+       sprintf(ztv->i2c.name,"zoran-%d",card);
+       ztv->i2c.data = ztv;
+
+       /*
+        * Now add the template and register the device unit
+        */
+       ztv->video_dev = zoran_template;
+       strcpy(ztv->video_dev.name, ztv->i2c.name);
+       if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0)
+               return -1;
+       i2c_register_bus(&ztv->i2c);
+
+       /* set interrupt mask - the PIN enable will be set later */
+       zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR);
+
+       printk(KERN_INFO "%s: installed %s\n",CARD,ztv->card->name);
+       return 0;
+}
+
+static
+void release_zoran(int max)
+{
+       u8 command;
+       struct zoran *ztv;
+       int i;
+
+       for (i=0;i<max; i++) 
+       {
+               ztv=&zorans[i];
+
+               /* turn off all capturing, DMA and IRQs */
+               /* reset the zoran */
+               zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI);
+               udelay(10);
+               zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
+               udelay(10);
+
+               /* first disable interrupts before unmapping the memory! */
+               zrwrite(0, ZORAN_ICR);
+               zrwrite(0xffffffffUL,ZORAN_ISR);
+
+               /* free it */
+               free_irq(ztv->dev->irq,ztv);
+               /* unregister i2c_bus */
+               i2c_unregister_bus((&ztv->i2c));
+
+               /* disable PCI bus-mastering */
+               pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
+               command&=PCI_COMMAND_MASTER;
+               pci_write_config_byte(ztv->dev, PCI_COMMAND, command);
+    
+               /* unmap and free memory */
+               if (ztv->zoran_mem)
+                       iounmap(ztv->zoran_mem);
+
+               video_unregister_device(&ztv->video_dev);
+       }
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       release_zoran(zoran_cards);
+}
+
+int init_module(void)
+{
+#else
+int init_zr36120_cards(struct video_init *unused)
+{
+#endif
+       int     card;
+       handle_chipset();
+       zoran_cards = find_zoran();
+       if (zoran_cards<0)
+               /* no cards found, no need for a driver */
+               return -EIO;
+
+       /* initialize Zorans */
+       for (card=0; card<zoran_cards; card++) {
+               if (init_zoran(card)<0) {
+                       /* only release the zorans we have registered */
+                       release_zoran(card);
+                       return -EIO;
+               } 
+       }
+       return 0;
+}
diff --git a/drivers/char/zr36120.h b/drivers/char/zr36120.h
new file mode 100644 (file)
index 0000000..8cfd190
--- /dev/null
@@ -0,0 +1,272 @@
+/* 
+    zr36120.h - Zoran 36120/36125 based framegrabbers
+
+    Copyright (C) 1998-1999 Pauline Middelink (middelin@polyware.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _ZR36120_H
+#define _ZR36120_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+
+#include <asm/io.h>
+
+/*
+ * Debug macro's, place an x behind the ) for actual debug-compilation
+ * E.g. #define DEBUG(x...)    x
+ */
+#define DEBUG(x...)                    /* Debug driver */
+#define IDEBUG(x...)                   /* Debug interrupt handler */
+#define PDEBUG         0               /* Debug PCI writes */
+
+/* defined in zr36120_i2c */
+extern struct i2c_bus zoran_i2c_bus_template;
+
+#define        ZORAN_MAX_FBUFFERS      2
+#define ZORAN_MAX_FBUFFER      0x0A2000
+#define ZORAN_MAX_FBUFSIZE     (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER)
+
+/* external declarations */
+extern unsigned long zoran_alloc_memory(void);
+extern void zoran_free_memory(void);
+
+struct tvcard {
+       char*   name;           /* name of the cardtype */
+       int     video_inputs;   /* number of channels defined in video_mux */
+       int     audio_inputs;   /* number of channels defined in audio_mux */
+       __u32   swapi2c:1,      /* need to swap i2c wires SDA/SCL? */
+               usegirq1:1,     /* VSYNC at GIRQ1 instead of GIRQ0? */
+               vsync_pos:1,    /* positive VSYNC signal? */
+               hsync_pos:1,    /* positive HSYNC signal? */
+               gpdir:8,        /* General Purpose Direction register */
+               gpval:8;        /* General Purpose Value register */
+       int     video_mux[6];   /* mapping channel number to physical input */
+#define                IS_TUNER        0x80
+#define                IS_SVHS         0x40
+#define                CHANNEL_MASK    0x3F
+       int     audio_mux[6];   /* mapping channel number to physical input */
+};
+#define        TUNER(x)        ((x)|IS_TUNER)
+#define        SVHS(x)         ((x)|IS_SVHS)
+
+struct vidinfo {
+       int     status;
+#define FBUFFER_UNUSED       0
+#define FBUFFER_GRABBING     1
+#define FBUFFER_DONE         2
+       int     x,y;
+       int     w,h;
+       int     bpl;
+       int     bpp;            /* should be calculated */
+       int     format;
+       ulong   vidadr;         /* physical video address */
+       ulong*  overlay;
+};
+
+struct zoran 
+{
+       struct video_device video_dev;
+#define CARD   ztv->video_dev.name
+       struct i2c_bus  i2c;
+       struct video_picture picture;   /* Current picture params */
+       struct video_audio audio_dev;   /* Current audio params */
+
+       /* zoran chip specific details */
+       struct pci_dev* dev;            /* ptr to PCI device */
+       ushort          id;             /* chip id */
+       unsigned char   revision;       /* chip revision */
+       int             zoran_adr;      /* bus address of IO memory */
+       char*           zoran_mem;      /* pointer to mapped IO memory */
+  
+       /* videocard details */
+       int             swidth;         /* screen width */
+       int             sheight;        /* screen height */
+       int             depth;          /* depth in bits */
+
+       /* channel details */
+       int             norm;           /* 0=PAL, 1=NTSC, 2=SECAM */
+       struct tvcard*  card;           /* the cardtype */
+       int             tuner_freq;     /* in Hz */
+
+       /* State details */
+       struct vidinfo  overinfo;       /* overlay data */
+       struct vidinfo  grabinfo[ZORAN_MAX_FBUFFERS];   /* grabbing data */
+       struct vidinfo  readinfo;       /* reading data */
+
+       /* maintenance data */
+       char*           fbuffer;        /* framebuffers for mmap */
+       int             user;           /* # users */
+       int             have_decoder;   /* did we detect a mux? */
+       int             have_tuner;     /* did we detect a tuner? */
+       int             tuner_type;     /* tuner type, when found */
+       int             running;
+       wait_queue_head_t grabq;        /* waiting capturers */
+       wait_queue_head_t readq;        /* waiting readers */
+       rwlock_t        lock;
+       int             state;          /* what is requested of us? */
+#define STATE_READ     0
+#define STATE_GRAB     1
+#define STATE_OVERLAY  2
+       int             prevstate;
+       int             lastframe;
+
+       int             interlace;      /* calculated */
+       int             vidXshift;      /* calculated */
+       int             vidWidth;       /* calculated */
+       int             vidHeight;      /* calculated */
+};
+
+#define zrwrite(dat,adr)    writel((dat),(char *) (ztv->zoran_mem+(adr)))
+#define zrread(adr)         readl(ztv->zoran_mem+(adr))
+
+#if !defined(PDEBUG) || (PDEBUG == 0)
+#define zrand(dat,adr)      zrwrite((dat) & zrread(adr), adr)
+#define zror(dat,adr)       zrwrite((dat) | zrread(adr), adr)
+#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr)
+#else
+#define zrand(dat, adr) \
+do { \
+       ulong data = (dat) & zrread((adr)); \
+       zrwrite(data, (adr)); \
+       if (0 != (~(dat) & zrread((adr)))) \
+               printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \
+} while(0)
+
+#define zror(dat, adr) \
+do { \
+       ulong data = (dat) | zrread((adr)); \
+       zrwrite(data, (adr)); \
+       if ((dat) != ((dat) & zrread(adr))) \
+               printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \
+} while(0)
+
+#define zraor(dat, mask, adr) \
+do { \
+       ulong data; \
+       if ((dat) & (mask)) \
+               printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \
+       data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \
+       zrwrite(data,(adr)); \
+       if ( (dat) != (~(mask) & zrread((adr))) ) \
+               printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \
+} while(0)
+#endif
+
+#endif
+
+/* zoran PCI address space */
+#define ZORAN_VFEH             0x000   /* Video Front End Horizontal Conf. */
+#define        ZORAN_VFEH_HSPOL        (1<<30)
+#define        ZORAN_VFEH_HSTART       (0x3FF<<10)
+#define        ZORAN_VFEH_HEND         (0x3FF<<0)
+
+#define ZORAN_VFEV             0x004   /* Video Front End Vertical Conf. */
+#define        ZORAN_VFEV_VSPOL        (1<<30)
+#define        ZORAN_VFEV_VSTART       (0x3FF<<10)
+#define        ZORAN_VFEV_VEND         (0x3FF<<0)
+
+#define        ZORAN_VFEC              0x008   /* Video Front End Scaler and Pixel */
+#define ZORAN_VFEC_EXTFL       (1<<26)
+#define        ZORAN_VFEC_TOPFIELD     (1<<25)
+#define        ZORAN_VFEC_VCLKPOL      (1<<24)
+#define        ZORAN_VFEC_HFILTER      (7<<21)
+#define        ZORAN_VFEC_HFILTER_1    (0<<21) /* no lumi,    3-tap chromo */
+#define        ZORAN_VFEC_HFILTER_2    (1<<21) /* 3-tap lumi, 3-tap chromo */
+#define        ZORAN_VFEC_HFILTER_3    (2<<21) /* 4-tap lumi, 4-tap chromo */
+#define        ZORAN_VFEC_HFILTER_4    (3<<21) /* 5-tap lumi, 4-tap chromo */
+#define        ZORAN_VFEC_HFILTER_5    (4<<21) /* 4-tap lumi, 4-tap chromo */
+#define        ZORAN_VFEC_DUPFLD       (1<<20)
+#define        ZORAN_VFEC_HORDCM       (63<<14)
+#define        ZORAN_VFEC_VERDCM       (63<<8)
+#define        ZORAN_VFEC_DISPMOD      (1<<6)
+#define        ZORAN_VFEC_RGB          (3<<3)
+#define        ZORAN_VFEC_RGB_YUV422   (0<<3)
+#define        ZORAN_VFEC_RGB_RGB888   (1<<3)
+#define        ZORAN_VFEC_RGB_RGB565   (2<<3)
+#define        ZORAN_VFEC_RGB_RGB555   (3<<3)
+#define        ZORAN_VFEC_ERRDIF       (1<<2)
+#define        ZORAN_VFEC_PACK24       (1<<1)
+#define        ZORAN_VFEC_LE           (1<<0)
+
+#define        ZORAN_VTOP              0x00C   /* Video Display "Top" */
+
+#define        ZORAN_VBOT              0x010   /* Video Display "Bottom" */
+
+#define        ZORAN_VSTR              0x014   /* Video Display Stride */
+#define        ZORAN_VSTR_DISPSTRIDE   (0xFFFF<<16)
+#define        ZORAN_VSTR_VIDOVF       (1<<8)
+#define        ZORAN_VSTR_SNAPSHOT     (1<<1)
+#define        ZORAN_VSTR_GRAB         (1<<0)
+
+#define        ZORAN_VDC               0x018   /* Video Display Conf. */
+#define        ZORAN_VDC_VIDEN         (1<<31)
+#define        ZORAN_VDC_MINPIX        (0x1F<<25)
+#define        ZORAN_VDC_TRICOM        (1<<24)
+#define        ZORAN_VDC_VIDWINHT      (0x3FF<<12)
+#define        ZORAN_VDC_VIDWINWID     (0x3FF<<0)
+
+#define        ZORAN_MTOP              0x01C   /* Masking Map "Top" */
+
+#define        ZORAN_MBOT              0x020   /* Masking Map "Bottom" */
+
+#define        ZORAN_OCR               0x024   /* Overlay Control */
+#define        ZORAN_OCR_OVLEN         (1<<15)
+#define        ZORAN_OCR_MASKSTRIDE    (0xFF<<0)
+
+#define        ZORAN_PCI               0x028   /* System, PCI and GPP Control */
+#define        ZORAN_PCI_SOFTRESET     (1<<24)
+#define        ZORAN_PCI_WAITSTATE     (3<<16)
+#define        ZORAN_PCI_GENPURDIR     (0xFF<<0)
+
+#define        ZORAN_GUEST             0x02C   /* GuestBus Control */
+
+#define        ZORAN_CSOURCE           0x030   /* Code Source Address */
+
+#define        ZORAN_CTRANS            0x034   /* Code Transfer Control */
+
+#define        ZORAN_CMEM              0x038   /* Code Memory Pointer */
+
+#define        ZORAN_ISR               0x03C   /* Interrupt Status Register */
+#define        ZORAN_ISR_CODE          (1<<28)
+#define        ZORAN_ISR_GIRQ0         (1<<29)
+#define        ZORAN_ISR_GIRQ1         (1<<30)
+
+#define        ZORAN_ICR               0x040   /* Interrupt Control Register */
+#define        ZORAN_ICR_EN            (1<<24)
+#define        ZORAN_ICR_CODE          (1<<28)
+#define        ZORAN_ICR_GIRQ0         (1<<29)
+#define        ZORAN_ICR_GIRQ1         (1<<30)
+
+#define        ZORAN_I2C               0x044   /* I2C-Bus */
+#define ZORAN_I2C_SCL          (1<<1)
+#define ZORAN_I2C_SDA          (1<<0)
+
+#define        ZORAN_POST              0x48    /* PostOffice */
+#define        ZORAN_POST_PEN          (1<<25)
+#define        ZORAN_POST_TIME         (1<<24)
+#define        ZORAN_POST_DIR          (1<<23)
+#define        ZORAN_POST_GUESTID      (3<<20)
+#define        ZORAN_POST_GUEST        (7<<16)
+#define        ZORAN_POST_DATA         (0xFF<<0)
+
+#endif
diff --git a/drivers/char/zr36120_i2c.c b/drivers/char/zr36120_i2c.c
new file mode 100644 (file)
index 0000000..8eb618b
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+    zr36120_i2c.c - Zoran 36120/36125 based framegrabbers
+
+    Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include "linux/video_decoder.h"
+#include "tuner.h"
+#include "zr36120.h"
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions                                                          */
+/* ----------------------------------------------------------------------- */
+
+/* software I2C functions */
+
+#define I2C_DELAY   10
+
+static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data)
+{
+       struct zoran *ztv = (struct zoran*)bus->data;
+       unsigned int b = 0;
+       if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA;
+       if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL;
+       zrwrite(b, ZORAN_I2C);
+       udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+       struct zoran *ztv = (struct zoran*)bus->data;
+       if (ztv->card->swapi2c)
+               return zrread(ZORAN_I2C) & ZORAN_I2C_SCL;
+       return zrread(ZORAN_I2C) & ZORAN_I2C_SDA;
+}
+
+static
+void attach_inform(struct i2c_bus *bus, int id)
+{
+       struct zoran *ztv = (struct zoran*)bus->data;
+
+       switch (id) {
+        case I2C_DRIVERID_VIDEODECODER:
+               ztv->have_decoder = 1;
+               DEBUG(printk(KERN_INFO "%s: decoder attached\n",CARD));
+               break;
+        case I2C_DRIVERID_TUNER:
+               ztv->have_tuner = 1;
+               DEBUG(printk(KERN_INFO "%s: tuner attached\n",CARD));
+               if (ztv->tuner_type >= 0)
+               {
+                       if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0)
+                       DEBUG(printk(KERN_INFO "%s: attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type));
+               }
+               break;
+        default:
+               DEBUG(printk(KERN_INFO "%s: attach_inform; unknown device id=%d\n",CARD,id));
+               break;
+       }
+}
+
+static
+void detach_inform(struct i2c_bus *bus, int id)
+{
+       struct zoran *ztv = (struct zoran*)bus->data;
+
+       switch (id) {
+        case I2C_DRIVERID_VIDEODECODER:
+               ztv->have_decoder = 0;
+               DEBUG(printk(KERN_INFO "%s: decoder detached\n",CARD));
+               break;
+        case I2C_DRIVERID_TUNER:
+               ztv->have_tuner = 0;
+               DEBUG(printk(KERN_INFO "%s: tuner detached\n",CARD));
+               break;
+        default:
+               DEBUG(printk(KERN_INFO "%s: detach_inform; unknown device id=%d\n",CARD,id));
+               break;
+       }
+}
+
+struct i2c_bus zoran_i2c_bus_template =
+{
+       "ZR36120",
+       I2C_BUSID_ZORAN,
+       NULL,
+
+       SPIN_LOCK_UNLOCKED,
+
+       attach_inform,
+       detach_inform,
+
+       i2c_setlines,
+       i2c_getdataline,
+       NULL,
+       NULL
+};
diff --git a/drivers/char/zr36120_mem.c b/drivers/char/zr36120_mem.c
new file mode 100644 (file)
index 0000000..18f83f6
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+    zr36120_mem.c - Zoran 36120/36125 based framegrabbers
+
+    Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/wrapper.h>
+#include <asm/io.h>
+#ifdef CONFIG_BIGPHYS_AREA
+#include <linux/bigphysarea.h>
+#endif
+
+#include "zr36120.h"
+#include "zr36120_mem.h"
+
+/* ----------------------------------------------------------------------- */
+/* Memory functions                                                       */
+/* shamelessly stolen and adapted from bttv.c                             */
+/* ----------------------------------------------------------------------- */
+
+/*
+ * convert virtual user memory address to physical address
+ * (virt_to_phys only works for kmalloced kernel memory)
+ */
+inline unsigned long uvirt_to_phys(unsigned long adr)
+{
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *ptep, pte;
+
+       pgd = pgd_offset(current->mm, adr);
+       if (pgd_none(*pgd))
+               return 0;
+       pmd = pmd_offset(pgd, adr);
+       if (pmd_none(*pmd))
+               return 0;
+       ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
+       pte = *ptep;
+       /* Note; page_address will panic for us if the page is high */
+        if(pte_present(pte))
+               return page_address(pte_page(pte))|(adr&(PAGE_SIZE-1));
+       return 0;
+}
+
+/*
+ * vmalloced address to physical address
+ */
+inline unsigned long kvirt_to_phys(unsigned long adr)
+{
+       return uvirt_to_phys(VMALLOC_VMADDR(adr));
+}
+
+/*
+ * vmalloced address to bus address
+ */
+inline unsigned long kvirt_to_bus(unsigned long adr)
+{
+       return virt_to_bus(phys_to_virt(kvirt_to_phys(adr)));
+}
+
+inline int order(unsigned long size)
+{
+       int ordr = 0;
+       size = (size+PAGE_SIZE-1)/PAGE_SIZE;
+       while (size) {
+               size /= 2;
+               ordr++;
+       }
+       return ordr;
+}
+
+void* bmalloc(unsigned long size)
+{
+       void* mem;
+#ifdef CONFIG_BIGPHYS_AREA
+       mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL);
+#else
+       /*
+        * The following function got a lot of memory at boottime,
+        * so we know its always there...
+        */
+       mem = (void*)__get_free_pages(GFP_USER,order(size));
+#endif
+       if (mem) {
+               unsigned long adr = (unsigned long)mem;
+               while (size > 0) {
+                       mem_map_reserve(MAP_NR(phys_to_virt(adr)));
+                       adr += PAGE_SIZE;
+                       size -= PAGE_SIZE;
+               }
+       }
+       return mem;
+}
+
+void bfree(void* mem, unsigned long size)
+{
+       if (mem) {
+               unsigned long adr = (unsigned long)mem;
+               unsigned long siz = size;
+               while (siz > 0) {
+                       mem_map_unreserve(MAP_NR(phys_to_virt(adr)));
+                       adr += PAGE_SIZE;
+                       siz -= PAGE_SIZE;
+               }
+#ifdef CONFIG_BIGPHYS_AREA
+               bigphysarea_free_pages(mem);
+#else
+               free_pages((unsigned long)mem,order(size));
+#endif
+       }
+}
diff --git a/drivers/char/zr36120_mem.h b/drivers/char/zr36120_mem.h
new file mode 100644 (file)
index 0000000..609f0a1
--- /dev/null
@@ -0,0 +1,17 @@
+extern inline unsigned long uvirt_to_phys(unsigned long adr);
+
+/* vmalloced address to physical address */
+extern inline unsigned long kvirt_to_phys(unsigned long adr)
+{ return uvirt_to_phys(VMALLOC_VMADDR(adr)); }
+
+/* vmalloced address to bus address */
+extern inline unsigned long kvirt_to_bus(unsigned long adr)
+{ return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); }
+
+/* always vmalloced memory - not always continuous! */
+void*  rvmalloc(unsigned long size);
+void   rvfree(void* mem, unsigned long size);
+
+/* either kmalloc() or bigphysarea() alloced memory - continuous */
+void*  bmalloc(unsigned long size);
+void   bfree(void* mem, unsigned long size);
index 37eb785f9fafd6e5f8e259bc4c3191f4267bebc8..1371c31abf82cf883f434637a7a076ea4b4cfd46 100644 (file)
@@ -120,7 +120,7 @@ struct cardinfo_table  cardinfo[] = {
     "SK NET TR 4/16 ISA"},
   { TMS_PCI, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, 
     "Compaq 4/16 TR PCI"},
-  { TMS_PCI, PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_TR, 
+  { TMS_PCI, PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, 
     "SK NET TR 4/16 PCI"},
   { TMS_PCI, PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING,
     "Thomas-Conrad TC4048 PCI 4/16"},
index 2dd4eaa120020a5b6477e8654e637a1dd5daa86f..73771fc96ce1189351d07bf5c50e30a225285f42 100644 (file)
@@ -1910,18 +1910,18 @@ wavelan_ioctl(struct net_device *       dev,    /* device on which the ioctl is applied *
 
     case SIOCSIWNWID:
       /* Set NWID in WaveLAN. */
-      if(wrq->u.nwid.on)
+      if(!wrq->u.nwid.disabled)
        {
-         /* Set NWID in psa. */
-         psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
-         psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
+         /* Set NWID in psa */
+         psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
+         psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
          psa.psa_nwid_select = 0x01;
          psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
                    (unsigned char *)psa.psa_nwid, 3);
 
          /* Set NWID in mmc. */
-         m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF;
-         m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8;
+         m.w.mmw_netw_id_l = psa.psa_nwid[1];
+         m.w.mmw_netw_id_h = psa.psa_nwid[0];
          mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
                    (unsigned char *)&m.w.mmw_netw_id_l, 2);
          mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
@@ -1945,8 +1945,9 @@ wavelan_ioctl(struct net_device * dev,    /* device on which the ioctl is applied *
       /* Read the NWID. */
       psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
               (unsigned char *)psa.psa_nwid, 3);
-      wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
-      wrq->u.nwid.on = psa.psa_nwid_select;
+      wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+      wrq->u.nwid.fixed = 1;   /* Superfluous */
       break;
 
     case SIOCSIWFREQ:
@@ -2006,83 +2007,96 @@ wavelan_ioctl(struct net_device *       dev,    /* device on which the ioctl is applied *
       wrq->u.sens.fixed = 1;
       break;
 
-     case SIOCSIWENCODE:
-       /* Set encryption key. */
-       if(!mmc_encr(ioaddr))
-        {
-          ret = -EOPNOTSUPP;
-          break;
-        }
-
-       if(wrq->u.encoding.method)
-        {      /* Enable encryption. */
-          int          i;
-          long long    key = wrq->u.encoding.code;
-
-          for(i = 7; i >= 0; i--)
-            {
-              psa.psa_encryption_key[i] = key & 0xFF;
-              key >>= 8;
-            }
-           psa.psa_encryption_select = 1;
-          psa_write(ioaddr, lp->hacr,
-                    (char *) &psa.psa_encryption_select - (char *) &psa,
-                    (unsigned char *) &psa.psa_encryption_select, 8+1);
-
-           mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
-                  MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
-           mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
-                    (unsigned char *) &psa.psa_encryption_key, 8);
-        }
-       else
-        {      /* Disable encryption. */
-          psa.psa_encryption_select = 0;
-          psa_write(ioaddr, lp->hacr,
-                    (char *) &psa.psa_encryption_select - (char *) &psa,
-                    (unsigned char *) &psa.psa_encryption_select, 1);
-
-          mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
-        }
-       /* update the Wavelan checksum */
-       update_psa_checksum(dev, ioaddr, lp->hacr);
-       break;
-
-     case SIOCGIWENCODE:
-       /* Read the encryption key. */
-       if(!mmc_encr(ioaddr))
-        {
-          ret = -EOPNOTSUPP;
-          break;
-        }
-
-       /* Only super-user can see encryption key. */
-       if(!suser())
-        {
-          ret = -EPERM;
-          break;
-        }
-       else
-        {
-          int          i;
-          long long    key = 0;
-
-          psa_read(ioaddr, lp->hacr,
+    case SIOCSIWENCODE:
+      /* Set encryption key */
+      if(!mmc_encr(ioaddr))
+       {
+         ret = -EOPNOTSUPP;
+         break;
+       }
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+       {
+         /* Check the size of the key */
+         if(wrq->u.encoding.length != 8)
+           {
+             ret = -EINVAL;
+             break;
+           }
+
+         /* Copy the key in the driver */
+         if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
+                           wrq->u.encoding.length))
+           {
+             ret = -EFAULT;
+             break;
+           }
+
+         psa.psa_encryption_select = 1;
+         psa_write(ioaddr, lp->hacr,
+                   (char *) &psa.psa_encryption_select - (char *) &psa,
+                   (unsigned char *) &psa.psa_encryption_select, 8+1);
+
+         mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
+                 MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+         mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
+                   (unsigned char *) &psa.psa_encryption_key, 8);
+       }
+
+      if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
+       {       /* disable encryption */
+         psa.psa_encryption_select = 0;
+         psa_write(ioaddr, lp->hacr,
                    (char *) &psa.psa_encryption_select - (char *) &psa,
-                   (unsigned char *) &psa.psa_encryption_select, 1+8);
-          for(i = 0; i < 8; i++)
-            {
-              key <<= 8;
-              key += psa.psa_encryption_key[i];
-            }
-          wrq->u.encoding.code = key;
-
-          /* encryption is enabled */
-          if(psa.psa_encryption_select)
-            wrq->u.encoding.method = mmc_encr(ioaddr);
-          else
-            wrq->u.encoding.method = 0;
-        }
-       break;
+                   (unsigned char *) &psa.psa_encryption_select, 1);
+
+         mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
+       }
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev, ioaddr, lp->hacr);
+      break;
+
+    case SIOCGIWENCODE:
+      /* Read the encryption key */
+      if(!mmc_encr(ioaddr))
+       {
+         ret = -EOPNOTSUPP;
+         break;
+       }
+
+      /* only super-user can see encryption key */
+      if(!suser())
+       {
+         ret = -EPERM;
+         break;
+       }
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+       {
+         /* Verify the user buffer */
+         ret = verify_area(VERIFY_WRITE, wrq->u.encoding.pointer, 8);
+         if(ret)
+           break;
+
+         psa_read(ioaddr, lp->hacr,
+                  (char *) &psa.psa_encryption_select - (char *) &psa,
+                  (unsigned char *) &psa.psa_encryption_select, 1+8);
+
+         /* encryption is enabled ? */
+         if(psa.psa_encryption_select)
+           wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+         else
+           wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+         wrq->u.encoding.flags |= mmc_encr(ioaddr);
+
+         /* Copy the key to the user buffer */
+         wrq->u.encoding.length = 8;
+         if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
+           ret = -EFAULT;
+       }
+      break;
 
     case SIOCGIWRANGE:
       /* basic checking */
@@ -2117,6 +2131,19 @@ wavelan_ioctl(struct net_device *        dev,    /* device on which the ioctl is applied *
          range.num_bitrates = 1;
          range.bitrate[0] = 2000000;   /* 2 Mb/s */
 
+         /* Encryption supported ? */
+         if(mmc_encr(ioaddr))
+           {
+             range.encoding_size[0] = 8;       /* DES = 64 bits key */
+             range.num_encoding_sizes = 1;
+             range.max_encoding_tokens = 1;    /* Only one key possible */
+           }
+         else
+           {
+             range.num_encoding_sizes = 0;
+             range.max_encoding_tokens = 0;
+           }
+
          /* Copy structure to the user buffer. */
          if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
                ret = -EFAULT;
index fc43ce3037711451ad724f0acab46a91d29b4af3..e4b722cf137352727bafed22bb855600877480f4 100644 (file)
  *     - Add the (short) list of bit-rates in range
  *     - Developp a new sensitivity... (sens.value & sens.fixed)
  *
+ * Changes made for release in 2.2.14 & 2.3.23 :
+ * -------------------------------------------
+ *     - Fix check for root permission (break instead of exit)
+ *     - New nwid & encoding setting (Wireless Extension 9)
+ *
  * Wishes & dreams:
  * ----------------
  *     - roaming (see Pcmcia driver)
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char      *version        = "wavelan.c : v20 (wireless extensions) 29/7/99\n";
+static const char      *version        = "wavelan.c : v21 (wireless extensions) 16/10/99\n";
 #endif
 
 /* Watchdog temporisation */
index 6c3835089a10912827681dfaf9f355fca7b20f9d..240453144db60d0a3fc0b17fbca8d405b1e41b6b 100644 (file)
@@ -1247,7 +1247,7 @@ static int sd_init_onedisk(int i)
                        SCpnt->sense_buffer[2] = 0;
 
                        sd_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
-                               512, sd_init_done,  SD_TIMEOUT, MAX_RETRIES);
+                               0/*512*/, sd_init_done,  SD_TIMEOUT, MAX_RETRIES);
 
                        the_result = SCpnt->result;
                        retries++;
index e3218180279accb89b3aae07efe05a6dba6d00c2..8610c17e052c39817a992c1fbe7ad22f00f39541 100644 (file)
 
 dep_tristate '  C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND
 if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
-   bool '    Enable legacy FM' CONFIG_SOUND_CMPCI_FM
-   bool '    Enable legacy MPU-401' CONFIG_SOUND_CMPCI_MIDI
+    bool '    Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP
+    bool '    Enable 4 channel mode for CMI8738' CONFIG_SOUND_CMPCI_4CH
+    if [ "$CONFIG_SOUND_CMPCI_4CH" = "y" ]; then
+        bool '    Separate rear out jack' CONFIG_SOUND_CMPCI_REAR
+    fi
 fi
 dep_tristate '  Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
 dep_tristate '  Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
index 81663c8db13c119d051b3aac563517e484e9073a..fc2083e3485d788aa76da5549ba8295decfa0bb5 100644 (file)
@@ -21,7 +21,7 @@
  *      along with this program; if not, write to the Free Software
  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Special thanks to David C. Niemi
+ * Special thanks to David C. Niemi, Jan Pfeifer
  *
  *
  * Module command line parameters:
  *                     read/write cannot be executed
  *    20 09 99   0.13  merged the generic changes in sonicvibes since this
  *                    diverged.
+ *    18.08.99   1.5   Only deallocate DMA buffer when unloading.
+ *    02.09.99   1.6   Enable SPDIF LOOP
+ *                     Change the mixer read back
+ *    21.09.99   2.33  Use RCS version aas driver version.
+ *                     Add support for modem, S/PDIF loop and 4 channels.
+ *                     (8738 only)
+ *                     Fix bug cause x11amp cannot play.
+ *    $Log: cmpci.c,v $
+ *    Revision 2.41  1999/10/27 02:00:05  cltien
+ *    Now the fragsize for modem is activated by parameter.
+ *
+ *    Revision 2.40  1999/10/26 23:38:26  cltien
+ *    Remove debugging message in cm_write which may cause module counter not 0.
+ *
+ *    Revision 2.39  1999/10/26 21:52:50  cltien
+ *    I forgor too adjust mic recording volume, as it should be moved to 5MUTEMONO.
+ *    Change the DYNAMIC macro to FIXEDDMA, which means static DMA buffer.
+ *
+ *    Revision 2.38  1999/10/08 21:59:03  cltien
+ *    Set FLINKON and reset FLINKOFF for modem.
+ *
+ *    Revision 2.37  1999/09/28 02:57:04  cltien
+ *    Add set_bus_master() to make sure bus master enabled.
+ *
+ *    Revision 2.36  1999/09/22 14:15:03  cltien
+ *    Use open_sem to avoid multiple access to open_mode.
+ *    Use wakeup in IntrClose to activate process in waiting queue.
+ *
+ *    Revision 2.35  1999/09/22 13:20:53  cltien
+ *    Use open_mode to check if DAC in used. Also more check in IntrWrite and IntrClose. Now the modem can access DAC safely.
+ *
+ *    Revision 2.34  1999/09/22 03:29:57  cltien
+ *    Use module count to decide which one to access the dac.
+ *
+ *
  */
-
 /*****************************************************************************/
       
 #include <linux/config.h>
@@ -252,6 +287,7 @@ struct cm_state {
                unsigned fragsize;
                unsigned dmasize;
                unsigned fragsamples;
+               unsigned dmasamples;
                /* OSS stuff */
                unsigned mapped:1;
                unsigned ready:1;
@@ -276,6 +312,7 @@ struct cm_state {
 /* --------------------------------------------------------------------- */
 
 static struct cm_state *devs = NULL;
+static struct cm_state *devaudio = NULL;
 static unsigned long wavetable_mem = 0;
 
 /* --------------------------------------------------------------------- */
@@ -331,7 +368,7 @@ static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count
        outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
        outw(count, s->iobase + CODEC_CMI_CH0_FRAME2);
        outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) & ~1, s->iobase + CODEC_CMI_FUNCTRL0);
-       outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+//     outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 }
 
 static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
@@ -340,13 +377,16 @@ static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count
        outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);
        outw(count, s->iobase + CODEC_CMI_CH1_FRAME2);
        outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) | 2, s->iobase + CODEC_CMI_FUNCTRL0);
-       outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+//     outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 }
 
 extern __inline__ unsigned get_dmadac(struct cm_state *s)
 {
        unsigned int curr_addr;
 
+       if (!s->dma_dac.dmasize || !(s->enable & CM_CENABLE_PE))
+               return 0;
+
        curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
        curr_addr -= virt_to_bus(s->dma_dac.rawbuf);
        curr_addr = s->dma_dac.dmasize - curr_addr;
@@ -358,6 +398,9 @@ extern __inline__ unsigned get_dmaadc(struct cm_state *s)
 {
        unsigned int curr_addr;
 
+       if (!s->dma_adc.dmasize || !(s->enable & CM_CENABLE_RE))
+               return 0;
+
        curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
        curr_addr -= virt_to_bus(s->dma_adc.rawbuf);
        curr_addr = s->dma_adc.dmasize - curr_addr;
@@ -421,7 +464,7 @@ static struct {
        { 22050,        (16000 + 22050) / 2,    (22050 + 32000) / 2,    2 },
        { 32000,        (22050 + 32000) / 2,    (32000 + 44100) / 2,    6 },
        { 44100,        (32000 + 44100) / 2,    (44100 + 48000) / 2,    3 },
-       { 48000,        48000,                  48000,                  7 }
+       { 48000,        (44100 + 48000) /2,     48000,                  7 }
 };
 
 static void set_dac_rate(struct cm_state *s, unsigned rate)
@@ -485,10 +528,12 @@ extern inline void stop_adc(struct cm_state *s)
        unsigned long flags;
 
        spin_lock_irqsave(&s->lock, flags);
+       /* disable channel */
+       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
        s->enable &= ~CM_CENABLE_RE;
        /* disable interrupt */
        outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       /* disable channel and reset */
+       /* reset */
        outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
        udelay(10);
        outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
@@ -500,10 +545,12 @@ extern inline void stop_dac(struct cm_state *s)
        unsigned long flags;
 
        spin_lock_irqsave(&s->lock, flags);
+       /* disable channel */
        s->enable &= ~CM_CENABLE_PE;
+       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
        /* disable interrupt */
        outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       /* disable channel and reset */
+       /* reset */
        outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
        udelay(10);
        outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
@@ -516,10 +563,10 @@ static void start_dac(struct cm_state *s)
 
        spin_lock_irqsave(&s->lock, flags);
        if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
+               outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
                s->enable |= CM_CENABLE_PE;
                outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
        }
-       outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
        spin_unlock_irqrestore(&s->lock, flags);
 }      
 
@@ -530,10 +577,10 @@ static void start_adc(struct cm_state *s)
        spin_lock_irqsave(&s->lock, flags);
        if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
            && s->dma_adc.ready) {
+               outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
                s->enable |= CM_CENABLE_RE;
                outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
        }
-       outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
        spin_unlock_irqrestore(&s->lock, flags);
 }      
 
@@ -593,10 +640,10 @@ static int prog_dmabuf(struct cm_state *s, unsigned rec)
                        return -ENOMEM;
                db->buforder = order;
                if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
-                       printk(KERN_DEBUG "cm: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
+                       printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
                               virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
                if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
-                       printk(KERN_DEBUG "cm: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
+                       printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
                               virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
                /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
                mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
@@ -623,17 +670,21 @@ static int prog_dmabuf(struct cm_state *s, unsigned rec)
        db->fragsize = 1 << db->fragshift;
        if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
                db->numfrag = db->ossmaxfrags;
-#if 1
-       /* to make fragsize >= 4096 */
-       while (db->fragsize < 4096 && db->numfrag >= 4)
-       {
-               db->fragsize *= 2;
-               db->fragshift++;
-               db->numfrag /= 2;
+       /* to make fragsize >= 4096 */
+#if 0  
+       if(s->modem)
+       {
+               while (db->fragsize < 4096 && db->numfrag >= 4)
+               {
+                       db->fragsize *= 2;
+                       db->fragshift++;
+                       db->numfrag /= 2;
+               }
        }
-#endif
+#endif 
        db->fragsamples = db->fragsize >> sample_shift[fmt];
        db->dmasize = db->numfrag << db->fragshift;
+       db->dmasamples = db->dmasize >> sample_shift[fmt];
        memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
        spin_lock_irqsave(&s->lock, flags);
        if (rec) {
@@ -665,6 +716,7 @@ extern __inline__ void clear_advance(struct cm_state *s)
                len -= x;
        }
        memset(buf + bptr, c, len);
+       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 }
 
 /* call with spinlock held! */
@@ -752,25 +804,26 @@ static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        unsigned int intsrc, intstat;
        
        /* fastpath out, to ease interrupt sharing */
-       intsrc = inb(s->iobase + CODEC_CMI_INT_STATUS);
-       if (!(intsrc & (CM_INT_CH0 | CM_INT_CH1)))
+       intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
+       if (!(intsrc & 0x80000000))
                return;
        spin_lock(&s->lock);
        intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       /* disable interrupt */
+       /* acknowledge interrupt */
        if (intsrc & CM_INT_CH0)
+       {
                outb(intstat & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+               udelay(10);
+               outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+       }
        if (intsrc & CM_INT_CH1)
+       {
                outb(intstat & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+               udelay(10);
+               outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+       }
        cm_update_ptr(s);
-#ifdef SOUND_CONFIG_CMPCI_MIDI
        cm_handle_midi(s);
-#endif
-       /* enable interrupt */
-       if (intsrc & CM_INT_CH0)
-               outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       if (intsrc & CM_INT_CH1)
-               outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
        spin_unlock(&s->lock);
 }
 
@@ -788,7 +841,7 @@ static void cm_midi_timer(unsigned long data)
 
 /* --------------------------------------------------------------------- */
 
-static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n";
+static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
 
 #ifdef CONFIG_SOUND_CMPCI      /* support multiple chips */
 #define VALIDATE_STATE(s)
@@ -808,6 +861,7 @@ static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n";
 #define MT_5MUTE      2
 #define MT_4MUTEMONO  3
 #define MT_6MUTE      4
+#define MT_5MUTEMONO  5
 
 static const struct {
        unsigned left;
@@ -818,7 +872,7 @@ static const struct {
 } mixtable[SOUND_MIXER_NRDEVICES] = {
        [SOUND_MIXER_CD]     = { DSP_MIX_CDVOLIDX_L,     DSP_MIX_CDVOLIDX_R,     MT_5MUTE,     0x04, 0x02 },
        [SOUND_MIXER_LINE]   = { DSP_MIX_LINEVOLIDX_L,   DSP_MIX_LINEVOLIDX_R,   MT_5MUTE,     0x10, 0x08 },
-       [SOUND_MIXER_MIC]    = { DSP_MIX_MICVOLIDX,      CODEC_CMI_MIXER2,       MT_4MUTEMONO, 0x01, 0x01 },
+       [SOUND_MIXER_MIC]    = { DSP_MIX_MICVOLIDX,      DSP_MIX_MICVOLIDX,      MT_5MUTEMONO, 0x01, 0x01 },
        [SOUND_MIXER_SYNTH]  = { DSP_MIX_FMVOLIDX_L,     DSP_MIX_FMVOLIDX_R,     MT_5MUTE,     0x40, 0x00 },
        [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE,     0x00, 0x00 },
        [SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 }
@@ -851,10 +905,16 @@ static int return_mixval(struct cm_state *s, unsigned i, int *arg)
                r = l;
                break;
 
+       case MT_5MUTEMONO:
+               r = l;
+               rl = 100 - 3 * ((l >> 3) & 31);
+               rr = rl;
+               break;
+                               
        case MT_5MUTE:
        default:
-               rl = 100 - 3 * (l & 31);
-               rr = 100 - 3 * (r & 31);
+               rl = 100 - 3 * ((l >> 3) & 31);
+               rr = 100 - 3 * ((r >> 3) & 31);
                break;
                                
        case MT_6MUTE:
@@ -992,7 +1052,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
                }
                spin_lock_irqsave(&s->lock, flags);
                wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);
-               wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | j>>1);
+               wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1));
                spin_unlock_irqrestore(&s->lock, flags);
                return 0;
 
@@ -1041,6 +1101,14 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
                        outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
                        break;
                        
+               case MT_5MUTEMONO:
+                       r = l;
+                       rl = l < 4 ? 0 : (l - 5) / 3;
+                       rr = rl >> 2;
+                       wrmixer(s, mixtable[i].left, rl<<3);
+                       outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+                       break;
+                               
                case MT_5MUTE:
                        rl = l < 4 ? 0 : (l - 5) / 3;
                        rr = r < 4 ? 0 : (r - 5) / 3;
@@ -1154,10 +1222,10 @@ static int drain_dac(struct cm_state *s, int nonblock)
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-               tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
+               tmo = (count * HZ) / s->ratedac;
                tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
-               if (!schedule_timeout(tmo + 1))
-                       printk(KERN_DEBUG "cm: dma timed out??\n");
+               if (!schedule_timeout(tmo ? : 1) && tmo)
+                       printk(KERN_DEBUG "cmpci: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1204,7 +1272,18 @@ static ssize_t cm_read(struct file *file, char *buffer, size_t count, loff_t *pp
                        start_adc(s);
                        if (file->f_flags & O_NONBLOCK)
                                return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->dma_adc.wait);
+                       if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
+                               printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+                                      s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
+                                      s->dma_adc.hwptr, s->dma_adc.swptr);
+                               stop_adc(s);
+                               spin_lock_irqsave(&s->lock, flags);
+                               set_dmaadc(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.dmasamples);
+                               /* program sample counts */
+                               outw(s->dma_adc.fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+                               s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+                               spin_unlock_irqrestore(&s->lock, flags);
+                       }
                        if (signal_pending(current))
                                return ret ? ret : -ERESTARTSYS;
                        continue;
@@ -1264,7 +1343,18 @@ static ssize_t cm_write(struct file *file, const char *buffer, size_t count, lof
                        start_dac(s);
                        if (file->f_flags & O_NONBLOCK)
                                return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->dma_dac.wait);
+                       if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
+                               printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+                                      s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
+                                      s->dma_dac.hwptr, s->dma_dac.swptr);
+                               stop_dac(s);
+                               spin_lock_irqsave(&s->lock, flags);
+                               set_dmadac(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.dmasamples);
+                               /* program sample counts */
+                               outw(s->dma_dac.fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+                               s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+                               spin_unlock_irqrestore(&s->lock, flags);
+                       }
                        if (signal_pending(current))
                                return ret ? ret : -ERESTARTSYS;
                        continue;
@@ -1730,7 +1820,6 @@ static /*const*/ struct file_operations cm_audio_fops = {
        NULL,  /* lock */
 };
 
-#ifdef CONFIG_SOUND_CMPCI_MIDI
 /* --------------------------------------------------------------------- */
 
 static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
@@ -1971,7 +2060,7 @@ static int cm_midi_release(struct inode *inode, struct file *file)
                        }
                        tmo = (count * HZ) / 3100;
                        if (!schedule_timeout(tmo ? : 1) && tmo)
-                               printk(KERN_DEBUG "cm: midi timed out??\n");
+                               printk(KERN_DEBUG "cmpci: midi timed out??\n");
                }
                remove_wait_queue(&s->midi.owait, &wait);
                set_current_state(TASK_RUNNING);
@@ -2011,11 +2100,9 @@ static /*const*/ struct file_operations cm_midi_fops = {
        NULL,  /* revalidate */
        NULL,  /* lock */
 };
-#endif
 
 /* --------------------------------------------------------------------- */
 
-#ifdef CONFIG_SOUND_CMPCI_FM
 static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
        static const unsigned char op_offset[18] = {
@@ -2187,7 +2274,6 @@ static /*const*/ struct file_operations cm_dmfm_fops = {
        NULL,  /* revalidate */
        NULL,  /* lock */
 };
-#endif /* CONFIG_SOUND_CMPCI_FM */
 
 /* --------------------------------------------------------------------- */
 
@@ -2215,8 +2301,31 @@ static struct initvol {
 };
 
 #ifdef MODULE
-int __init init_module(void)
+static int     spdif_loop = 0;
+static int     four_ch = 0;
+static int     rear_out = 0;
+MODULE_PARM(spdif_loop, "i");
+MODULE_PARM(four_ch, "i");
+MODULE_PARM(rear_out, "i");
+
+int  __init init_module(void)
+#else
+#ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP
+static int     spdif_loop = 1;
 #else
+static int     spdif_loop = 0;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_4CH
+static int     four_ch = 1;
+#else
+static int     four_ch = 0;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_REAR
+static int     rear_out = 1;
+#else
+static int     read_out = 0;
+#endif
+
 int __init init_cmpci(void)
 #endif
 {
@@ -2224,6 +2333,7 @@ int __init init_cmpci(void)
        struct pci_dev *pcidev = NULL;
        mm_segment_t fs;
        int i, val, index = 0;
+       
        struct {
                unsigned short  deviceid;
                char            *devicename;
@@ -2239,10 +2349,10 @@ int __init init_cmpci(void)
        if (!pci_present())   /* No PCI bus in this machine! */
 #endif
                return -ENODEV;
-       printk(KERN_INFO "cm: version v1.1 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "cmpci: version v2.41-nomodem time " __TIME__ " " __DATE__ "\n");
 #if 0
        if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
-               printk(KERN_INFO "cm: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
+               printk(KERN_INFO "cmpci: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
 #endif
        while (index < NR_DEVICE && pcidev == NULL && (
               (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)) ||
@@ -2251,7 +2361,7 @@ int __init init_cmpci(void)
                if (pcidev->irq == 0)
                        continue;
                if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) {
-                       printk(KERN_WARNING "cm: out of memory\n");
+                       printk(KERN_WARNING "cmpci: out of memory\n");
                        continue;
                }
                /* search device name */
@@ -2272,65 +2382,60 @@ int __init init_cmpci(void)
                init_MUTEX(&s->open_sem);
                s->magic = CM_MAGIC;
                s->iobase = pcidev->resource[0].start;
-#ifdef CONFIG_SOUND_CMPCI_FM
                s->iosynth = 0x388;
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
                s->iomidi = 0x330;
-#endif
                if (s->iobase == 0)
                        continue;
                s->irq = pcidev->irq;
 
                if (check_region(s->iobase, CM_EXTENT_CODEC)) {
-                       printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
+                       printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
                        goto err_region5;
                }
                request_region(s->iobase, CM_EXTENT_CODEC, "cmpci");
-#ifdef CONFIG_SOUND_CMPCI_MIDI
                if (check_region(s->iomidi, CM_EXTENT_MIDI)) {
-                       printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
-                       goto err_region4;
+                       printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, midi disabled.\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
+                       s->iomidi = 0;
+               }
+               else
+               {
+                       request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi");
+                       /* set IO based at 0x330 */
+                       outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
                }
-               request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi");
-               /* set IO based at 0x330 */
-               outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
                if (check_region(s->iosynth, CM_EXTENT_SYNTH)) {
-                       printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
-                       goto err_region1;
+                       printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, synth disabled.\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
+                       s->iosynth = 0;
+               }
+               else
+               {
+                       request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM");
+                       /* enable FM */
+                       outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL);
                }
-               request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM");
-               /* enable FM */
-               outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL);
-#endif
                /* initialize codec registers */
                outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
-               outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* reset channels */
+               outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
                /* reset mixer */
                wrmixer(s, DSP_MIX_DATARESETIDX, 0);
 
                /* request irq */
                if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) {
-                       printk(KERN_ERR "cm: irq %u in use\n", s->irq);
+                       printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
                        goto err_irq;
                }
-               printk(KERN_INFO "cm: found %s adapter at io %#06x irq %u\n",
+               printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n",
                       devicename, s->iobase, s->irq);
                /* register devices */
                if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0)
                        goto err_dev1;
                if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0)
                        goto err_dev2;
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-               if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
+               if (s->iomidi && (s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
                        goto err_dev3;
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
-               if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
+               if (s->iosynth && (s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
                        goto err_dev4;
-#endif
+               pci_set_master(pcidev);
                /* initialize the chips */
                fs = get_fs();
                set_fs(KERNEL_DS);
@@ -2344,6 +2449,38 @@ int __init init_cmpci(void)
                        mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
                }
                set_fs(fs);
+               if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738)
+               {
+                       /* enable SPDIF loop */
+                       if (spdif_loop)
+                       {
+                               /* turn on spdif-in to spdif-out */
+                               outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 0x80, s->iobase + CODEC_CMI_FUNCTRL1);
+                               printk(KERN_INFO "cmpci: Enable SPDIF loop\n");
+                       }
+                       else
+                               outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~0x80, s->iobase + CODEC_CMI_FUNCTRL1);
+                       /* enable 4 channels mode */
+                       if (four_ch)
+                       {
+                               /* 4 channel mode (analog duplicate) */
+                               outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) | 0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
+                               printk(KERN_INFO "cmpci: Enable 4 channels mode\n");
+                               /* has separate rear-out jack ? */
+                               if (rear_out)
+                               {
+                                       /* has separate rear out jack */
+                                       outb(inb(s->iobase + CODEC_CMI_MIXER1) & ~0x20, s->iobase + CODEC_CMI_MIXER1);
+                               }
+                               else
+                               {
+                                       outb(inb(s->iobase + CODEC_CMI_MIXER1) | 0x20, s->iobase + CODEC_CMI_MIXER1);
+                                       printk(KERN_INFO "cmpci: line-in routed as rear-out\n");
+                               }
+                       }
+                       else
+                               outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) & ~0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
+               }
                /* queue it for later freeing */
                s->next = devs;
                devs = s;
@@ -2357,16 +2494,14 @@ int __init init_cmpci(void)
        err_dev2:
                unregister_sound_dsp(s->dev_audio);
        err_dev1:
-               printk(KERN_ERR "cm: cannot register misc device\n");
+               printk(KERN_ERR "cmpci: cannot register misc device\n");
                free_irq(s->irq, s);
        err_irq:
-#ifdef CONFIG_SOUND_CMPCI_FM
-               release_region(s->iosynth, CM_EXTENT_SYNTH);
+               if(s->iosynth)
+                       release_region(s->iosynth, CM_EXTENT_SYNTH);
        err_region1:
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-               release_region(s->iomidi, CM_EXTENT_MIDI);
-#endif
+               if(s->iomidi)
+                       release_region(s->iomidi, CM_EXTENT_MIDI);
        err_region4:
                release_region(s->iobase, CM_EXTENT_CODEC);
        err_region5:
@@ -2395,32 +2530,30 @@ void cleanup_module(void)
                devs = devs->next;
                outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
                synchronize_irq();
-               outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* reset channels */
+               outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
                free_irq(s->irq, s);
 
                /* reset mixer */
                wrmixer(s, DSP_MIX_DATARESETIDX, 0);
 
                release_region(s->iobase, CM_EXTENT_CODEC);
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-               release_region(s->iomidi, CM_EXTENT_MIDI);
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
-               release_region(s->iosynth, CM_EXTENT_SYNTH);
-#endif
+               if(s->iomidi)
+               {
+                       release_region(s->iomidi, CM_EXTENT_MIDI);
+                       unregister_sound_midi(s->dev_midi);
+               }
+               if(s->iosynth)
+               {
+                       release_region(s->iosynth, CM_EXTENT_SYNTH);
+                       unregister_sound_special(s->dev_dmfm);
+               }
                unregister_sound_dsp(s->dev_audio);
                unregister_sound_mixer(s->dev_mixer);
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-               unregister_sound_midi(s->dev_midi);
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
-               unregister_sound_special(s->dev_dmfm);
-#endif
                kfree_s(s, sizeof(struct cm_state));
        }
        if (wavetable_mem)
                free_pages(wavetable_mem, 20-PAGE_SHIFT);
-       printk(KERN_INFO "cm: unloading\n");
+       printk(KERN_INFO "cmpci: unloading\n");
 }
 
 #endif /* MODULE */
index e9ab31ccb49fb7060ca799b01fae9cac1473cc7f..cfd80db9e74f68c2869e42a94eca0e61ee464ec7 100644 (file)
@@ -14,7 +14,7 @@ if [ "$CONFIG_FB" = "y" ]; then
          bool '  nVidia Riva support (EXPERIMENTAL)' CONFIG_FB_RIVA
       fi
       if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-        tristate '  Cirrus Logic suport (EXPERIMENTAL)' CONFIG_FB_CLGEN
+        tristate '  Cirrus Logic support (EXPERIMENTAL)' CONFIG_FB_CLGEN
         tristate '  Permedia2 support (EXPERIMENTAL)' CONFIG_FB_PM2
         if [ "$CONFIG_FB_PM2" = "y" ]; then
            if [ "$CONFIG_PCI" = "y" ]; then
index d96f7edecb1fad0af5820bc78859f1ea67528260..ede497bed3a3245595fb813855574f0e7e6aeca0 100644 (file)
@@ -15,6 +15,7 @@
  *  1997-08-09 removed extension stripping, locking cleanup
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
index ea30675483aaac65f36ceceae6d355caf7c8339c..17c61130aa9ce625ed5aeb3b72e1edfaf13e0639 100644 (file)
@@ -106,16 +106,7 @@ typedef unsigned long pgprot_t;
 
 #endif /* STRICT_MM_TYPECHECKS */
 
-#if 0
 #define BUG()          __asm__ __volatile__("call_pal 129 # bugchk")
-#else
-/* hack to see the BUG() information in the early boot stage */
-#define BUG()                                                          \
-do {                                                                   \
-       SRM_printf("kernel BUG at %s:%d!\n", __FILE__, __LINE__);       \
-       halt();                                                         \
-} while(0)
-#endif
 #define PAGE_BUG(page) BUG()
 
 #endif /* !ASSEMBLY */
index 22fe23868d67a14439bf7d7afb6efa53703949cd..880f0f4bb0c7fc06378df3138d75f72b88aa5369 100644 (file)
@@ -363,17 +363,6 @@ __xchg(unsigned long x, volatile void * ptr, int size)
   ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 #define tas(ptr) (xchg((ptr),1))
 
-/* Very dirty but nevertheless very fun hack ;). I recall the aboot printf()
-   that will in turn use the SRM  console to do the debugging of the boot
-   process. As there's no runtime symbol table, the address of printf()
-   is hardwired and is in function of the bootlx binary you have in /boot...
-   1999 Andrea Arcangeli <andrea@suse.de> */
-#if 0
-#define SRM_printf(args...) ({ int (*__SRM_printf)(const char *fmt, ...) = (int (*)(const char *fmt, ...)) 0x20000aa0; __SRM_printf(args); })
-#else
-#define SRM_printf(args...)
-#endif
-
 #endif /* __ASSEMBLY__ */
 
 #endif
index 12240d8d6b81a745222ffd9c789cfa130909fa86..567d53973fd8820841f102769f33cce050fb3b3b 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #define acornfb_valid_pixrate(rate) (rate >= 39325 && rate <= 40119)
 
 static inline void
index 864d3b47f5b3c684ef34be46bc76cc6204c68fcd..f22867eecb1959401e14a7818cd27fa67e8776b8 100644 (file)
@@ -4,8 +4,6 @@
 #ifndef _ASMARM_PGTABLE_H
 #define _ASMARM_PGTABLE_H
 
-#include <linux/config.h>
-
 #include <asm/arch/memory.h>
 #include <asm/proc-fns.h>
 #include <asm/system.h>
index f2e258e81293234edbd2aee6713dc106f4c88edf..ce080d4adcd3a536ffe1b6bdbe05629235bb2121 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef __ASM_ARM_PROCESSOR_H
 #define __ASM_ARM_PROCESSOR_H
 
-#include <linux/config.h>
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
index 3b0f4c55b6c639fee98228ae974b2d32ce673424..12f25731f11d2ee03409cd4ac09519c349007212 100644 (file)
@@ -20,6 +20,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/kmap_types.h>
index 894055a7df92bb1f97f4f72d2f0b86022302734d..0a2e01c3617e670d39e7de2b5231aa772329f4b2 100644 (file)
@@ -79,10 +79,10 @@ extern void init_8259A(int aeoi);
 extern void FASTCALL(send_IPI_self(int vector));
 extern void init_VISWS_APIC_irqs(void);
 extern void setup_IO_APIC(void);
+extern void disable_IO_APIC(void);
+extern void print_IO_APIC(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
 extern void send_IPI(int dest, int vector);
-extern void init_pic_mode(void);
-extern void print_IO_APIC(void);
 
 extern unsigned long io_apic_irqs;
 extern volatile unsigned long irq_err_count;
index 2aa6aec4e4e4d64a12060c092ac126f33e9914e7..3425c2cd1834f8220e7fe31bcc506663f2b6550d 100644 (file)
@@ -174,6 +174,7 @@ extern volatile unsigned long smp_invalidate_needed;
 extern int pic_mode;
 extern void smp_flush_tlb(void);
 extern int get_maxlvt(void);
+extern void disable_local_APIC (void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_send_reschedule(int cpu);
 extern void smp_invalidate_rcv(void);          /* Process an NMI */
index a10ed9c5c5d84b26022f8c65dd8c209e85450f57..cf66557f943a0d8ba9fd36af7b52321d5dfc3096 100644 (file)
@@ -36,7 +36,7 @@ typedef struct { unsigned long a[100]; } __dummy_lock_t;
        ".previous"
 
 #define spin_unlock_string \
-       "lock ; btrl $0,%0"
+       "movb $0,%0"
 
 #define spin_lock(lock) \
 __asm__ __volatile__( \
index 65dc6864785b7dae78048d91b19aea4396399dfd..96dbd7a54b9c5446996c8147e36f4f88b6cbdc51 100644 (file)
@@ -12,6 +12,7 @@
 
 extern unsigned long max_low_pfn;
 
+extern unsigned long __init bootmem_bootmap_pages (unsigned long);
 extern unsigned long __init init_bootmem (unsigned long addr, unsigned long memend);
 extern void __init reserve_bootmem (unsigned long addr, unsigned long size);
 extern void __init free_bootmem (unsigned long addr, unsigned long size);
index 7091d50870a46f13ff85368e94de9d79a09051d3..d9cedda121faf18839e5f8a903b496d832b297f9 100644 (file)
@@ -354,6 +354,8 @@ struct video_code
 #define VID_HARDWARE_TRUST     22      /* Trust FM Radio */
 #define VID_HARDWARE_TERRATEC  23      /* TerraTec ActiveRadio */
 #define VID_HARDWARE_CPIA      24
+#define VID_HARDWARE_ZR36120   25      /* Zoran ZR36120/ZR36125 */
+#define VID_HARDWARE_ZR36067   26      /* Zoran ZR36067/36060 */
 
 /*
  *     Initialiser list
index acc0619eb5e575c446611822f1a2d9a6fcc459d8..868f812acbfbd49c09d9bcfcb647770869f405a6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :   8       28.7.99
+ * Version :   9       16.10.99
  *
  * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  */
@@ -63,7 +63,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT   8
+#define WIRELESS_EXT   9
 
 /*
  * Changes :
  *     - Changed my e-mail address
  *     - More 802.11 support (nickname, rate, rts, frag)
  *     - List index in frequencies
+ *
+ * V8 to V9
+ * --------
+ *     - Support for 'mode of operation' (ad-hoc, managed...)
+ *     - Support for unicast and multicast power saving
+ *     - Change encoding to support larger tokens (>64 bits)
+ *     - Updated iw_params (disable, flags) and use it for NWID
+ *     - Extracted iw_point from iwreq for clarity
  */
 
 /* -------------------------- IOCTL LIST -------------------------- */
 /* Basic operations */
 #define SIOCSIWNAME    0x8B00          /* Unused ??? */
 #define SIOCGIWNAME    0x8B01          /* get name */
-#define SIOCSIWNWID    0x8B02          /* set network id */
+#define SIOCSIWNWID    0x8B02          /* set network id (the cell) */
 #define SIOCGIWNWID    0x8B03          /* get network id */
 #define SIOCSIWFREQ    0x8B04          /* set channel/frequency */
 #define SIOCGIWFREQ    0x8B05          /* get channel/frequency */
-#define SIOCSIWENCODE  0x8B06          /* set encoding info */
-#define SIOCGIWENCODE  0x8B07          /* get encoding info */
+#define SIOCSIWMODE    0x8B06          /* set operation mode */
+#define SIOCGIWMODE    0x8B07          /* get operation mode */
 #define SIOCSIWSENS    0x8B08          /* set sensitivity */
 #define SIOCGIWSENS    0x8B09          /* get sensitivity */
 
 #define SIOCSIWFRAG    0x8B24          /* set fragmentation thr (bytes) */
 #define SIOCGIWFRAG    0x8B25          /* get fragmentation thr (bytes) */
 
+/* Encoding stuff (scrambling, hardware security, WEP...) */
+#define SIOCSIWENCODE  0x8B2A          /* set encoding token & mode */
+#define SIOCGIWENCODE  0x8B2B          /* get encoding token & mode */
+/* Power saving stuff (power management, unicast and multicast) */
+#define SIOCSIWPOWER   0x8B2C          /* set Power Management settings */
+#define SIOCGIWPOWER   0x8B2D          /* get Power Management settings */
+
 /* ------------------------- IOCTL STUFF ------------------------- */
 
 /* The first and the last (range) */
 #define SIOCIWFIRST    0x8B00
-#define SIOCIWLAST     0x8B25
+#define SIOCIWLAST     0x8B30
 
 /* Even : get (world access), odd : set (root access) */
 #define IW_IS_SET(cmd) (!((cmd) & 0x1))
 /* Maximum size of the ESSID and NICKN strings */
 #define IW_ESSID_MAX_SIZE      32
 
+/* Modes of operation */
+#define IW_MODE_AUTO   0       /* Let the driver decides */
+#define IW_MODE_ADHOC  1       /* Single cell network */
+#define IW_MODE_INFRA  2       /* Multi cell network, roaming, ... */
+#define IW_MODE_MASTER 3       /* Synchronisation master or Access Point */
+#define IW_MODE_REPEAT 4       /* Wireless Repeater (forwarder) */
+#define IW_MODE_SECOND 5       /* Secondary master/repeater (backup) */
+
+/* Maximum number of size of encoding token available
+ * they are listed in the range structure */
+#define IW_MAX_ENCODING_SIZES  8
+
+/* Maximum size of the encoding token in bytes */
+#define IW_ENCODING_TOKEN_MAX  32      /* 256 bits (for now) */
+
+/* Flags for encoding (along with the token) */
+#define IW_ENCODE_INDEX                0x00FF  /* Token index (if needed) */
+#define IW_ENCODE_FLAGS                0xF000  /* Flags defined below */
+#define IW_ENCODE_DISABLED     0x8000  /* Encoding disabled */
+#define IW_ENCODE_ENABLED      0x0000  /* Encoding enabled */
+#define IW_ENCODE_RESTRICTED   0x4000  /* Refuse non-encoded packets */
+#define IW_ENCODE_OPEN         0x2000  /* Accept non-encoded packets */
+
+/* Power management flags available (along with the value, if any) */
+#define IW_POWER_ON            0x0000  /* No details... */
+#define IW_POWER_TYPE          0xF000  /* Type of parameter */
+#define IW_POWER_PERIOD                0x1000  /* Value is a period/duration of  */
+#define IW_POWER_TIMEOUT       0x2000  /* Value is a timeout (to go asleep) */
+#define IW_POWER_MODE          0x0F00  /* Power Management mode */
+#define IW_POWER_UNICAST_R     0x0100  /* Receive only unicast messages */
+#define IW_POWER_MULTICAST_R   0x0200  /* Receive only multicast messages */
+#define IW_POWER_ALL_R         0x0300  /* Receive all messages though PM */
+#define IW_POWER_FORCE_S       0x0400  /* Force PM procedure for sending unicast */
+#define IW_POWER_REPEATER      0x0800  /* Repeat broadcast messages in PM period */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
+/*
+ *     Generic format for most parameters that fit in an int
+ */
+struct iw_param
+{
+  __s32                value;          /* The value of the parameter itself */
+  __u8         fixed;          /* Hardware should not use auto select */
+  __u8         disabled;       /* Disable the feature */
+  __u16                flags;          /* Various specifc flags (if any) */
+};
+
+/*
+ *     For all data larger than 16 octets, we need to use a
+ *     pointer to memory alocated in user space.
+ */
+struct iw_point
+{
+  caddr_t      pointer;        /* Pointer to the data  (in user space) */
+  __u16                length;         /* number of fields or size in bytes */
+  __u16                flags;          /* Optional params */
+};
+
 /*
  *     A frequency
  *     For numbers lower than 10^9, we encode the number in 'm' and
@@ -223,7 +295,7 @@ struct      iw_freq
  */
 struct iw_quality
 {
-       __u8            qual;           /* link quality (SNR or better...) */
+       __u8            qual;           /* link quality (%retries, SNR or better...) */
        __u8            level;          /* signal level */
        __u8            noise;          /* noise level */
        __u8            updated;        /* Flags to know if updated */
@@ -240,33 +312,13 @@ struct    iw_discarded
        __u32           misc;           /* Others cases */
 };
 
-/*
- *     Encoding information (setting and so on)
- *     Encoding might be hardware encryption, scrambing or others
- */
-struct iw_encoding
-{
-  __u8 method;                 /* Algorithm number / key used */
-  __u64        code;                   /* Data/key used for algorithm */
-};
-
-/*
- *     Generic format for parameters
- */
-struct iw_param
-{
-  __s32                value;          /* The value of the parameter itself */
-  __u8         fixed;          /* Hardware should not use auto select */
-};
-
-
 /* ------------------------ WIRELESS STATS ------------------------ */
 /*
  * Wireless statistics (used for /proc/net/wireless)
  */
 struct iw_statistics
 {
-       __u           status;         /* Status
+       __u16           status;         /* Status
                                         * - device dependent for now */
 
        struct iw_quality       qual;           /* Quality of the link
@@ -295,37 +347,28 @@ struct    iwreq
        union
        {
                /* Config - generic */
-               char    name[IFNAMSIZ];
+               char            name[IFNAMSIZ];
                /* Name : used to verify the presence of  wireless extensions.
                 * Name of the protocol/provider... */
 
-               struct          /* network id (or domain) : used to to */
-               {               /* create logical channels on the air */
-                       __u32   nwid;           /* value */
-                       __u8    on;             /* active/unactive nwid */
-               }       nwid;
-
+               struct iw_point essid;  /* Extended network name */
+               struct iw_param nwid;   /* network id (or domain - the cell) */
                struct iw_freq  freq;   /* frequency or channel :
                                         * 0-1000 = channel
                                         * > 1000 = frequency in Hz */
 
-               struct iw_encoding      encoding;       /* Encoding stuff */
-
-               __u32   sensitivity;            /* Obsolete, but compatible */
                struct iw_param sens;           /* signal level threshold */
                struct iw_param bitrate;        /* default bit rate */
                struct iw_param rts;            /* RTS threshold threshold */
                struct iw_param frag;           /* Fragmentation threshold */
+               __u32           mode;           /* Operation mode */
+
+               struct iw_point encoding;       /* Encoding stuff : tokens */
+               struct iw_param power;          /* PM duration/timeout */
 
                struct sockaddr ap_addr;        /* Access point address */
 
-               struct          /* For all data bigger than 16 octets */
-               {
-                       caddr_t pointer;        /* Pointer to the data
-                                                * (in user space) */
-                       __u16   length;         /* fields or byte size */
-                       __u16   flags;          /* Optional params */
-               }       data;
+               struct iw_point data;           /* Other large parameters */
        }       u;
 };
 
@@ -366,9 +409,6 @@ struct      iw_range
        /* Quality of link & SNR stuff */
        struct iw_quality       max_qual;       /* Quality of the link */
 
-       /* Encoder stuff */
-       struct iw_encoding      max_encoding;   /* Encoding max range */
-
        /* Rates */
        __u8            num_bitrates;   /* Number of entries in the list */
        __s32           bitrate[IW_MAX_BITRATES];       /* list, in bps */
@@ -380,6 +420,17 @@ struct     iw_range
        /* Frag threshold */
        __s32           min_frag;       /* Minimal frag threshold */
        __s32           max_frag;       /* Maximal frag threshold */
+
+       /* Power Management duration & timeout */
+       __s32           min_pmd;        /* Minimal PM duration */
+       __s32           max_pmd;        /* Maximal PM duration */
+       __s32           min_pmt;        /* Minimal PM timeout */
+       __s32           max_pmt;        /* Maximal PM timeout */
+
+       /* Encoder stuff */
+       __u16   encoding_size[IW_MAX_ENCODING_SIZES];   /* Different token sizes */
+       __u8    num_encoding_sizes;     /* Number of entry in the list */
+       __u8    max_encoding_tokens;    /* Max number of tokens */
 };
 
 /*
index 3f13728d6c57ae99400cda74f39c5085526ed53e..e4980ecbcffa7e456c5a179d48d28ce9f731984f 100644 (file)
@@ -254,10 +254,11 @@ static inline void reschedule_idle(struct task_struct * p, unsigned long flags)
         * wakeup, the frequent rescheduler will likely chose this
         * task during it's next schedule():
         */
-       tsk = cpu_curr(best_cpu);
-       if ((p->avg_slice < cacheflush_time) &&
-                       (tsk->avg_slice < cacheflush_time))
-               goto out_no_target;
+       if (p->policy == SCHED_OTHER) {
+               tsk = cpu_curr(best_cpu);
+               if (p->avg_slice + tsk->avg_slice < cacheflush_time)
+                       goto out_no_target;
+       }
 
        /*
         * We know that the preferred CPU has a cache-affine current
index 270dfc8c99da7d18b3dacab9609c18e305f00475..e0ab193dac9629c4f0cd1c42a6654ad4e3986cf7 100644 (file)
@@ -28,6 +28,18 @@ unsigned long max_low_pfn;
 
 static void * bootmem_map = NULL;
 
+/* return the number of _pages_ that will be allocated for the boot bitmap */
+unsigned long __init bootmem_bootmap_pages (unsigned long pages)
+{
+       unsigned long mapsize;
+
+       mapsize = (pages+7)/8;
+       mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
+       mapsize >>= PAGE_SHIFT;
+
+       return mapsize;
+}
+
 /*
  * Called once to set up the allocator itself.
  */
index c97a61ece40723462292abcf9d1f461e3942a9ed..e40eba4b587b9e3c76e2d059f5d20d6d7a28444e 100644 (file)
@@ -16,7 +16,6 @@
  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  */
 
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>