]> git.neil.brown.name Git - history.git/commitdiff
- pre5: 2.4.0-test11pre5
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:03 +0000 (15:40 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:03 +0000 (15:40 -0500)
   - Rasmus Andersen: add proper "<linux/init.h>" for sound drivers
   - David Miller: sparc64 and networking updates
   - David Trcka: MOXA numbering starts from 0, not 1.
   - Jeff Garzik: sysctl.h standalone
   - Dag Brattli: IrDA finishing touches
   - Randy Dunlap: USB fixes
   - Gerd Knorr: big bttv update
   - Peter Anvin: x86 capabilities cleanup
   - Stephen Rothwell: apm initcall fix - smp poweroff should work
   - Andrew Morton: setscheduler() spinlock ordering fix
   - Stephen Rothwell: directory notification documentation
   - Petr Vandrovec: ncpfs capabilities check cleanup
   - David Woodhouse: fix jffs to use generic isxxxx() library
   - Chris Swiedler: oom_kill selection fix
   - Jens Axboe: re-merge after sleeping in ll_rw_block.
   - Randy Dunlap: USB updates (pegasus and ftdi_sio)
   - Kai Germaschewski: ISDN ppp header compression fixed

146 files changed:
CREDITS
Documentation/00-INDEX
Documentation/dnotify.txt [new file with mode: 0644]
Documentation/usb/hotplug.txt [new file with mode: 0644]
Documentation/usb/ov511.txt
Documentation/video4linux/bttv/CARDLIST
Documentation/video4linux/bttv/Insmod-options
Documentation/video4linux/bttv/README
Documentation/video4linux/bttv/Sound-FAQ
Documentation/video4linux/bttv/Specs [new file with mode: 0644]
Makefile
arch/i386/defconfig
arch/i386/kernel/apm.c
arch/i386/kernel/bluesmoke.c
arch/i386/kernel/mpparse.c
arch/i386/kernel/msr.c
arch/i386/kernel/mtrr.c
arch/i386/kernel/setup.c
arch/sparc/config.in
arch/sparc/mm/init.c
arch/sparc64/kernel/dtlb_base.S
arch/sparc64/kernel/dtlb_prot.S
arch/sparc64/kernel/itlb_base.S
arch/sparc64/kernel/sys_sparc32.c
drivers/atm/nicstar.c
drivers/block/ll_rw_blk.c
drivers/char/drm/ffb_drv.c
drivers/char/generic_serial.c
drivers/char/joystick/analog.c
drivers/char/mem.c
drivers/char/mxser.c
drivers/char/random.c
drivers/isdn/isdn_ppp.c
drivers/md/md.c
drivers/media/video/Makefile
drivers/media/video/audiochip.h
drivers/media/video/bttv-cards.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv-if.c
drivers/media/video/bttv.h
drivers/media/video/bttvp.h [new file with mode: 0644]
drivers/media/video/id.h [new file with mode: 0644]
drivers/media/video/msp3400.c
drivers/media/video/tda7432.c
drivers/media/video/tda8425.c [deleted file]
drivers/media/video/tda985x.c [deleted file]
drivers/media/video/tda9875.c
drivers/media/video/tea6300.c [deleted file]
drivers/media/video/tea6420.c [deleted file]
drivers/media/video/tuner.c
drivers/media/video/tuner.h
drivers/media/video/tvaudio.c [new file with mode: 0644]
drivers/media/video/tvaudio.h [new file with mode: 0644]
drivers/media/video/tvmixer.c
drivers/mtd/docprobe.c
drivers/net/3c501.c
drivers/net/3c503.c
drivers/net/3c505.c
drivers/net/3c507.c
drivers/net/3c509.c
drivers/net/3c515.c
drivers/net/3c523.c
drivers/net/3c527.c
drivers/net/3c59x.c
drivers/net/82596.c
drivers/net/Config.in
drivers/net/a2065.c
drivers/net/ac3200.c
drivers/net/cs89x0.c
drivers/net/irda/irport.c
drivers/net/irda/smc-ircc.c
drivers/net/irda/toshoboe.c
drivers/net/sunhme.c
drivers/net/sunhme.h
drivers/scsi/AM53C974.c
drivers/scsi/st.c
drivers/sound/cs4281.c
drivers/sound/gus_midi.c
drivers/sound/gus_wave.c
drivers/sound/ics2101.c
drivers/sound/pas2_midi.c
drivers/sound/pas2_mixer.c
drivers/sound/pas2_pcm.c
drivers/sound/yss225.c
drivers/usb/dc2xx.c
drivers/usb/devio.c
drivers/usb/ov511.c
drivers/usb/pegasus.c
drivers/usb/pegasus.h [new file with mode: 0644]
drivers/usb/pegasus_devs.h [deleted file]
drivers/usb/printer.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/usb.c
drivers/video/riva/fbdev.c
drivers/video/sis/sis_300.c
drivers/video/sis/sis_300.h
drivers/video/sis/sis_301.c
drivers/video/sis/sis_301.h
drivers/video/sis/sis_main.c
fs/jffs/intrep.c
fs/ncpfs/ioctl.c
fs/ncpfs/ncplib_kernel.c
fs/proc/array.c
include/asm-alpha/semaphore.h
include/asm-i386/bugs.h
include/asm-i386/cpufeature.h [new file with mode: 0644]
include/asm-i386/elf.h
include/asm-i386/processor.h
include/linux/divert.h
include/linux/dn.h
include/linux/ethtool.h
include/linux/init.h
include/linux/netfilter_decnet.h
include/linux/netlink.h
include/linux/raid/md.h
include/linux/raid/md_compatible.h
include/linux/raid/md_k.h
include/linux/raid/md_p.h
include/linux/raid/md_u.h
include/linux/rtnetlink.h
include/linux/sunrpc/debug.h
include/linux/sysctl.h
include/net/dn_nsp.h
include/net/x25.h
kernel/sched.c
mm/oom_kill.c
net/ax25/sysctl_net_ax25.c
net/core/dev.c
net/decnet/Config.in
net/decnet/TODO
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_nsp_in.c
net/decnet/dn_nsp_out.c
net/decnet/dn_route.c
net/decnet/sysctl_net_decnet.c
net/irda/ircomm/ircomm_tty.c
net/irda/irnet/irnet_irda.c
net/irda/irnet/irnet_irda.h
net/irda/irsyms.c
net/irda/timer.c
net/x25/af_x25.c
net/x25/x25_dev.c
net/x25/x25_in.c
net/x25/x25_out.c

diff --git a/CREDITS b/CREDITS
index 4053679e63559b86311a39fad626034b864427be..73025b2fb90fbb60b3ed0fc2dc1d4d358af77d25 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2635,17 +2635,14 @@ S: Rockville, Maryland 20853
 S: USA
 
 N: Stephen Tweedie
-E: sct@dcs.ed.ac.uk
+E: sct@redhat.com
 P: 1024/E7A417AD E2 FE A4 20 34 EC ED FC 7D 7E 67 8D E0 31 D1 69
+P: 1024D/43BE7544 D2A4 8556 08E6 90E7 076C  BA3F 243F 20A4 43BE 7544
 D: Second extended file system developer
 D: General filesystem hacker
 D: kswap vm management code
-S: Dept. of Computer Science
-S: University of Edinburgh
-S: JCMB, The King's Buildings
-S: Mayfield Road
-S: Edinburgh 
-S: EH9 3JZ
+S: 44 Campbell Park Crescent
+S: Edinburgh EH13 0HT
 S: United Kingdom
 
 N: Thomas Uhl
index 93386cb2e756473d8768de32531a22b334df70b6..a7bca2f14312e6e66fc77ae570a78b7cb703c432 100644 (file)
@@ -43,6 +43,8 @@ digiboard.txt
        - info on the Digiboard PC/X{i,e,eve} multiport boards.
 digiepca.txt
        - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
+dnotify.txt
+       - info about directory notification in Linux.
 exception.txt
        - how Linux v2.2 handles exceptions without verify_area etc.
 fb/
diff --git a/Documentation/dnotify.txt b/Documentation/dnotify.txt
new file mode 100644 (file)
index 0000000..9f86118
--- /dev/null
@@ -0,0 +1,92 @@
+               Linux Directory Notification
+               ============================
+
+          Stephen Rothwell <sfr@linuxcare.com.au>
+
+The intention of directory notification is to allow user applications
+to be notified when a directory, or any of the files in it, are changed.
+The basic mechanism involves the application registering for notification
+on a directory using a fcntl(2) call and the notifications themselves
+being delivered using signals.
+
+The application decides which "events" it wants to be notified about.
+The currently defined events are:
+
+       DN_ACCESS       A file in the directory was accessed (read)
+       DN_MODIFY       A file in the directory was modified (write,truncate)
+       DN_CREATE       A file was created in the directory
+       DN_DELETE       A file was unlinked from directory
+       DN_RENAME       A file in the directory was renamed
+       DN_ATTRIB       A file in the directory had its attributes
+                       changed (chmod,chown)
+
+Usually, the application must reregister after each notification, but
+if DN_MULTISHOT is or'ed with the event mask, then the registration will
+remain until explicitly removed (by registering for no events).
+
+By default, SIGIO will be delivered to the process and no other useful
+information.  However, if the F_SETSIG fcntl(2) call is used to let the
+kernel know which signal to deliver, a siginfo structure will be passed to
+the signal handler and the si_fd member of that structure will contain the
+file descriptor associated with the direcory in which the event occured.
+
+Preferably the application will choose one of the real time signals
+(SIGRTMIN + <n>) so that the notifications may be queued.  This is
+especially important if DN_MULTISHOT is specified.
+
+Implementation expectations (features and bugs :-))
+---------------------------
+
+The notification should work for any local access to files even if the
+actual file system is on a remote server.  This implies that remote
+access to files served by local user mode servers should be notified.
+Also, remote accesses to files served by a local kernel NFS server should
+be notified.
+
+In order to make the impact on the file system code as small as possible,
+the problem of hard links to files has been ignored.  So if a file (x)
+exists in two directories (a and b) then a change to the file using the
+name "a/x" should be notified to a program expecting notifications on
+directory "a", but will not be notified to one expecting notifications on
+directory "b".
+
+Also, files that are unlinked, will still cause notifications in the
+last directory that they were linked to.
+
+Example
+-------
+
+       #define _GNU_SOURCE     /* needed to get the defines */
+       #include <fcntl.h>      /* in glibc 2.2 this has the needed
+                                          values defined */
+       #include <signal.h>
+       #include <stdio.h>
+       #include <unistd.h>
+       
+       static volatile int event_fd;
+       
+       static void handler(int sig, siginfo_t *si, void *data)
+       {
+               event_fd = si->si_fd;
+       }
+       
+       int main(void)
+       {
+               struct sigaction act;
+               int fd;
+               
+               act.sa_sigaction = handler;
+               sigemptyset(&act.sa_mask);
+               act.sa_flags = SA_SIGINFO;
+               sigaction(SIGRTMIN, &act, NULL);
+               
+               fd = open(".", O_RDONLY);
+               fcntl(fd, F_SETSIG, SIGRTMIN);
+               fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
+               /* we will now be notified if any of the files
+                  in "." is modified or new files are created */
+               while (1) {
+                       pause();
+                       printf("Got event on fd=%d\n", event_fd);
+               }
+       }
diff --git a/Documentation/usb/hotplug.txt b/Documentation/usb/hotplug.txt
new file mode 100644 (file)
index 0000000..a526ffc
--- /dev/null
@@ -0,0 +1,124 @@
+USB HOTPLUGGING
+
+In hotpluggable busses like USB (and Cardbus PCI), end-users plug devices
+into the bus with power on.  In most cases, users expect the devices to become
+immediately usable.  That means the system must do many things, including:
+
+    - Find a driver that can handle the device.  That may involve
+      loading a kernel module; newer drivers can use modutils to
+      publish their device (and class) support to user utilities.
+
+    - Bind a driver to that device.  That's done using the USB
+      device driver's probe() routine.
+    
+    - Tell other subsystems to configure the new device.  Print
+      queues may need to be enabled, networks brought up, disk
+      partitions mounted, and so on.  In some cases these will
+      be driver-specific actions.
+
+This involves a mix of kernel mode and user mode actions.  Making devices
+be immediately usable means that any user mode actions can't wait for an
+administrator to do them:  the kernel must trigger them, either passively
+(triggering some monitoring daemon to invoke a helper program) or
+actively (calling such a user mode helper program directly).
+
+Those triggered actions must support a system's administrative policies;
+such programs are called "policy agents" here.  Typically they involve
+shell scripts that dispatch to more familiar administration tools.
+
+
+KERNEL HOTPLUG HELPER (/sbin/hotplug)
+
+When you compile with CONFIG_HOTPLUG, you get a new kernel parameter:
+/proc/sys/kernel/hotplug, which normally holds the pathname "/sbin/hotplug".
+That parameter names a program which the kernel may invoke at various times.
+
+The /sbin/hotplug program can be invoked by any subsystem as part of its
+reaction to a configuration change, from a thread in that subsystem.
+Only one parameter is required: the name of a subsystem being notified of
+some kernel event.  That name is used as the first key for further event
+dispatch; any other argument and environment parameters are specified by
+the subsystem making that invocation.
+
+A reference implementation of a /sbin/hotplug script is available at the
+http://www.linux-usb.org website, which works USB for but also knows how to
+delegate to any /etc/hotplug/$TYPE.agent policy agent present.
+
+
+USB POLICY AGENT
+
+The USB subsystem currently invokes /sbin/hotplug when USB devices
+are added or removed from system.  The invocation is done by the kernel
+hub daemon thread [khubd], or else as part of root hub initialization
+(done by init, modprobe, kapmd, etc).  Its single command line parameter
+is the string "usb", and it passes these environment variables:
+
+    ACTION ... "add", "remove"
+    PRODUCT ... USB vendor, product, and version codes (hex)
+    TYPE ... device class codes (decimal)
+    INTERFACE ... interface 0 class codes (decimal)
+
+If "usbdevfs" is configured, DEVICE and DEVFS are also passed.  DEVICE is
+the pathname of the device, and is useful for devices with multiple and/or
+alternate interfaces that complicate driver selection.
+
+Currently available policy agent implementations can load drivers for
+modules, and can invoke driver-specific setup scripts.  The newest ones
+leverage USB modutils support.  Later agents might unload drivers.
+
+
+USB MODUTILS SUPPORT
+
+Current versions of modutils will create a "modules.usbmap" file which
+contains the entries from each driver's MODULE_DEVICE_TABLE.  Such files
+can be used by various user mode policy agents to make sure all the right
+driver modules get loaded, either at boot time or later. 
+
+See <linux/usb.h> for full information about such table entries; or look
+at existing drivers.  Each table entry describes one or more criteria to
+be used when matching a driver to a device or class of devices.
+
+A short example, for a driver that supports several specific USB devices
+and their quirks, might have a MODULE_DEVICE_TABLE like this:
+
+    static const struct usb_device_id mydriver_id_table = {
+       { idVendor: 0x9999, idProduct 0xaaaa, driver_info: QUIRK_X },
+       { idVendor: 0xbbbb, idProduct 0x8888, driver_info: QUIRK_Y|QUIRK_Z },
+       ...
+       { } /* end with an all-zeroes entry */
+    }
+    MODULE_DEVICE_TABLE (usb, mydriver_id_table);
+
+Most USB device drivers should pass these tables to the USB subsystem as
+well as to the module management subsystem.  Not all, though: some driver
+frameworks connect using interfaces layered over USB, and so they won't
+need such a "struct usb_driver".
+
+Drivers that connect directly to the USB subsystem should be declared
+something like this:
+
+    static struct usb_driver mydriver = {
+       name:           "mydriver",
+       id_table:       mydriver_id_table,
+       probe:          my_probe,
+       disconnect:     my_disconnect,
+
+       /*
+       if using the usb chardev framework:
+           minor:              MY_USB_MINOR_START,
+           fops:               my_file_ops,
+       if exposing any operations through usbdevfs:
+           ioctl:              my_ioctl,
+       */
+    }
+
+When the USB subsystem knows about a driver's device ID table, it's used when
+choosing drivers to probe().  The thread doing new device processing checks
+drivers' device ID entries from the MODULE_DEVICE_TABLE against interface and
+device descriptors for the device.  It will only call probe() if there is a
+match, and the third argument to probe() will be the entry that matched.
+
+If you don't provide an id_table for your driver, then your driver may get
+probed for each new device; the third parameter to probe() will be null.
+
+
index 304a1ec9051b9dced72c9692266a2961aa63ae0b..bc9cad2abb54d7922a3961b29db30965be73e9f4 100644 (file)
@@ -5,22 +5,17 @@ Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
 Author: Mark McClelland
 Homepage: http://alpha.dyndns.org/ov511
 
-NEW IN THIS VERSION:
- o Stability improvements
- o Support for hue control
- o 160x120 mostly working
- o OV6620 color problems fixed
- o More WebCam 3 detection improvements
-
 INTRODUCTION:
 
 This is a driver for the OV511, a USB-only chip used in many "webcam" devices.
 Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It 
 supports streaming and capture of color or monochrome video via the Video4Linux
-API. Most V4L apps are compatible with it, but a few videoconferencing programs
+API. Most V4L apps are compatible with it, but a few video-conferencing programs
 do not work yet. The following resolutions are supported: 640x480, 448x336,
 384x288, 352x288, and 320x240.
 
+If you need more information, please visit the OV511 homepage at the above URL.
+
 WHAT YOU NEED:
 
 - If you want to help with the development, get the chip's specification docs at
@@ -81,29 +76,6 @@ Now you should be able to run xawtv. Right click for the options dialog. If
 you get a scrambled image it is likely that you made a mistake in Xawtv.ad.
 Try setting the size to 320x240 if all else fails.
 
-FAQ:
-Q: "Why does the picture have noise and look grainy"
-A: This is a problem at low light levels, and may be also due to subtle bugs in
-   the code. The cause is most likely the OV7610 settings we are currently
-   using. I am looking into this problem.
-
-Q: "The driver sometimes says `Failed to read OV7610 ID.' What is the deal?"
-A: The I2C code that allows the OV511 to communicate with the camera chip is a
-   bit flaky right now. This message means that the I2C bus never got
-   initialized properly, and the camera will most likely not work even if you
-   disable this warning. Try unloading/reloading the driver or unplugging/re-
-   plugging the camera if this happens. Also try increasing the i2c_detect_tries
-   parameter (see below).
-
-Q: "Why do you bother with this phony camera detection crap? It doesn't do
-    anything useful!"
-A: The main purpose of only supporting known camera models is to force people
-   with new camera models to tell me about them, so I can assemble the list
-   above, and so the code can know what CCD chip you have. Right now, nearly all
-   of the cameras use the OV7610 and consequently I have not put support for
-   other ones in, so the value of the detection code is questionable. Eventually
-   though, new CCDs might appear and we will be fortunate to have the detection.
-
 MODULE PARAMETERS:
 
   You can set these with:  insmod ov511 NAME=VALUE
@@ -136,7 +108,7 @@ MODULE PARAMETERS:
         or so lines higher than the red component. This is only apparent in 
         images with white objects on black backgrounds at 640x480. Setting this
         to 1 will realign the color planes correctly. NOTE: This is still
-        experimental and very buggy. You will likely need a fast (500 Mhz) CPU.
+        experimental and very buggy. You will likely need a fast (500 MHz) CPU.
 
   NAME: snapshot
   TYPE: integer (boolean)
@@ -203,15 +175,21 @@ MODULE PARAMETERS:
   DESC: Prevent apps from timing out if frame is not done in time. This is
         useful if you are having problems with Xawtv getting "stuck" on a frame
         when your system is under heavy load.
+
+  NAME: sensor_gbr
+  TYPE: boolean
+  DEFAULT: 0
+  DESC: This makes the sensor output GBR422 instead of YUV420. This saves the
+        driver the trouble of converting YUV to RGB, but it currently does not
+        work very well (the colors are not quite right)
+
 WORKING FEATURES:
- o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, 320x240, and
-   160x120
- o RGB24, YUV420, YUV422, YUYV, and YUV422P color
+ o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, and 320x240
+ o RGB24, RGB565, YUV420, YUV422, YUYV, and YUV422P color
  o Monochrome
  o Setting/getting of saturation, contrast, brightness, and hue (only some of
    them work the OV7620 and OV7620AE)
- o proc status reporting
+ o /proc status reporting
 
 EXPERIMENTAL FEATURES:
  o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
@@ -219,6 +197,7 @@ EXPERIMENTAL FEATURES:
  o Snapshot mode (only works with some read() based apps; see below for more)
  o OV6620 sensor support
  o GBR422 parsing
+ o 160x120
 
 TODO:
  o Fix the noise / grainy image problem.
@@ -227,18 +206,19 @@ TODO:
    so we can't really work on that yet. Please kindly inform OmniVision that you
    would like them to release their specifications to the Linux community.
  o YUV422
- o Get snapshot mode working with mmap().
  o Fix fixFrameRGBoffset(). It is not stable yet with streaming video.
- o Get autoadjust disable working
  o V4L2 support (Probably not until it goes into the kernel)
- o Creative WebCam III has problems initializing its sensor. This should be
-   fixed now, but if you still have problems let me know.
  o Get rid of the memory management functions (put them in videodev.c??)
  o Setting of contrast and brightness not working with 7620/7620AE
  o Driver/camera state save/restore for when USB supports suspend/resume
  o Unstable on SMP systems
  o OV7620/OV6620 experience frame corruption with moving objects
  o OV6620 is too dark
+ o 176x144 support
+ o Driver sometimes hangs upon close() with OHCI
+ o The image should always be written properly to the mmap'ed buffer as long as
+   the requested image size is at least the minimum size. This will likely
+   require a rewrite of all the parsing code.
 
 HOW TO CONTACT ME:
 
index 0d36761d1ffaad925685f136ff28a23560e9fb69..f513ebb484368242b0fe24284d270d3cc162a799 100644 (file)
@@ -48,6 +48,11 @@ bttv.o
   card=46 - Zoltrix Genie TV
   card=47 - Terratec TV/Radio+
   card=48 - Dynalink Magic TView 
+  card=49 - GV-BCTV3
+  card=50 - Prolink PV-BT878P+4E (PixelView PlayTV PAK)
+  card=51 - Eagle Wireless Capricorn2 (bt878A)
+  card=52 - Pinnacle Studio PCTV Pro
+  card=53 - Typhoon TView RDS
 
 tuner.o
   type=0 - Temic PAL
@@ -65,3 +70,4 @@ tuner.o
   type=12 - Alps TSBE5
   type=13 - Alps TSBC5
   type=14 - Temic 4006FH5
+  type=15 - Alps TSCH6
index 68818a5327947df3c26a550f4ba31f5f4cfa85d3..4cb55586dda30b357904e981d3306c67af1b3846 100644 (file)
@@ -23,11 +23,19 @@ bttv.o
                                at the hardware).  default is 1.
                bttv_debug=0/1  debug messages (for capture).
                                default is 0 (off).
+               irq_debug=0/1   irq handler debug messages.
+                               default is 0 (off).
                gbuffers=2-64   number of capture buffers for mmap'ed capture.
                                default is 2.
                gbufsize=       size of capture buffers. default and
                                maximum value is 0x208000 (~2MB)
 
+               bttv_gpio=0/1
+               gpiomask=
+               audioall=
+               audiomux=
+                               See Sound-FAQ for a detailed description.
+
        remap, card, radio and pll accept up to four comma-separated arguments
        (for multiple boards).
 
@@ -54,6 +62,19 @@ tvaudio.o
        new, experimental module which is supported to provide a single
        driver for all simple i2c audio control chips (tda/tea*).
 
+       insmod args:
+               tda8425  = 1    enable/disable the support for the
+               tda9840  = 1    various chips.
+               tda9850  = 1    The tea6300 can't be autodetected and is
+               tda9855  = 1    therefore off by default, if you have
+               tda9873  = 1    this one on your card (STB uses these)
+               tea6300  = 0    you have to enable it explicitly.
+               tea6420  = 1    The two tda985x chips use the same i2c
+               pic16c54 = 1    address and can't be disturgished from
+                               each other, you might have to disable
+                               the wrong one.
+               debug = 1       print debug messages
+
 msp3400.o
        The driver for the msp34xx sound processor chips. If you have a
        stereo card, you probably want to insmod this one.
@@ -72,7 +93,7 @@ msp3400.o
                                should improve things for french people, the
                                carrier autoscan seems to work with FM only...
 
-tea6300.o
+tea6300.o - OBSOLETE (use tvaudio instead)
        The driver for the tea6300 fader chip.  If you have a stereo
        card and the msp3400.o doesn't work, you might want to try this
        one.  This chip is seen on most STB TV/FM cards (usually from
@@ -81,7 +102,7 @@ tea6300.o
        insmod args:
                debug=1         print some debug info to the syslog.
 
-tda8425.o
+tda8425.o - OBSOLETE (use tvaudio instead)
        The driver for the tda8425 fader chip.  This driver used to be
        part of bttv.c, so if your sound used to work but does not
        anymore, try loading this module.
@@ -89,7 +110,7 @@ tda8425.o
        insmod args:
                debug=1         print some debug info to the syslog.
 
-tda985x.o
+tda985x.o - OBSOLETE (use tvaudio instead)
        The driver for the tda9850/55 audio chips.
 
        insmod args:
index 868feedb997ceec3916fa76f15073b80b11341d3..bce7e55eef08114035a39b61074a11d228351c8c 100644 (file)
@@ -1,4 +1,8 @@
 
+IMPORTANT:  Don't send me mails with images attached unless I ask you
+to do so.  Mails with images attached will go to /dev/null unseen.
+
+
 Release notes for bttv-0.7.x
 ============================
 
@@ -17,7 +21,7 @@ CONFIG_I2C=m
 CONFIG_I2C_ALGOBIT=m
 
 The latest bttv version is available here:
-       http://me.in-berlin.de/~kraxel/bttv.html
+       http://www.strusel007.de/linux/bttv/
 
 You'll find Ralphs original (mostly outdated) documentation in the
 ralphs-doc subdirectory.
@@ -38,6 +42,8 @@ kernel at least once, you probably don't have do worry about this.  If
 not, go to /usr/src/linux and run at least "make config".  Even
 better, compile your own kernel, you'll never become a real hacker
 else ;-)
+Note that you have to turn on video4linux support (CONFIG_VIDEO_DEV)
+in the kernel to get the videodev.o module which is required by bttv.
 
 
 Make bttv work with your card
@@ -66,7 +72,8 @@ correct card type.  If you get video but no sound you've very likely
 specified the wrong (or no) card type.  A list of supported cards is
 in CARDLIST.
 
-If your card isn't listed in CARDLIST, you should read the Sound-FAQ.
+If your card isn't listed in CARDLIST or if you have trouble making
+audio work, you should read the Sound-FAQ.
 
 
 Still doesn't work?
index ce8895700c64c559d31e059c9f3d9bacd5df5de9..64611f497f165ffe21fdd65fe8614ad17885c128 100644 (file)
@@ -8,12 +8,12 @@ completely by the bt8xx chip, which is common on all boards.  But
 sound is handled in slightly different ways on each board.
 
 To handle the grabber boards correctly, there is a array tvcards[] in
-bttv.c, which holds the informations required for each board.  Sound
-will work only, if the correct entry is used (for video it often makes
-no difference).  The bttv driver prints a line to the kernel log,
-telling which card type is used.  Like this one:
+bttv-cards.c, which holds the informations required for each board.
+Sound will work only, if the correct entry is used (for video it often
+makes no difference).  The bttv driver prints a line to the kernel
+log, telling which card type is used.  Like this one:
 
-       bttv0: model: BT848(Hauppauge old)
+       bttv0: model: BT848(Hauppauge old) [autodetected]
 
 You should verify this is correct.  If it is'nt, you have to pass the
 correct board type as insmod argument, "insmod bttv card=2" for
@@ -32,7 +32,7 @@ you might want to check the video4linux mailing list archive first...
 
 Of course you need a correctly installed soundcard unless you have the
 speakers connected directly to the grabber board.  Hint: check the
-mixer settings too...
+mixer settings too.  ALSA for example has everything muted by default.
 
 
 How sound works in detail
@@ -48,42 +48,64 @@ bt848 chip.  Another one is the data register (BT848_GPIO_DATA), where
 you can get/set the status if these pins.  They can be used for input
 and output.
 
-All grabber board vendors use these pins to control an external chip
+Most grabber board vendors use these pins to control an external chip
 which does the sound routing.  But every board is a little different.
 These pins are also used by some companies to drive remote control
-receiver chips.
+receiver chips.  Some boards use the i2c bus instead of the gpio pins
+to connect the mux chip.
 
 As mentioned above, there is a array which holds the required
 informations for each known board.  You basically have to create a new
-line for your board.  What is in there:
+line for your board.  The important fields are these two:
 
 struct tvcard
 {
-        char *name;
-        int inputs;       /* number of video inputs */
-        int tuner;        /*   which of them is the tuner */
-        int svhs;         /*   which of them is the svhs input */
+       [ ... ]
         u32 gpiomask;
-        u32 muxsel[8];    /* video mux */
-        u32 audiomux[6];  /* audio mux: Tuner, Radio, external, internal, mute, stereo */
-        u32 gpiomask2;    /* GPIO MUX mask (this is video) */
+        u32 audiomux[5];  /* audio mux: tuner, radio, external, internal, mute */
 };
 
-gpiomask has all bits set which are used to control the audio mux.
-This value basically goes to the gpio output enable register.  It is
-also used to mask bits when switching the audio mux (which is done by
-read-modify-write on the gpio data register).
+gpiomask specifies which pins are used to control the audio mux chip.
+The corresponding bits in the output enable register
+(BT848_GPIO_OUT_EN) will be set as these pins must be driven by the
+bt848 chip.
+
+The audiomux[] array holds the data values for the different inputs
+(i.e. which pins must be high/low for tuner/mute/...).  This will be
+written to the data register (BT848_GPIO_DATA) to switch the audio
+mux.
+
 
 What you have to do is figure out the correct values for gpiomask and
 the audiomux array.  If you have Windows and the drivers four your
 card installed, you might to check out if you can read these registers
 values used by the windows driver.  A tool to do this is available
-from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil.  There is
-some #ifdef'ed code in bttv.c (search for "new card") which prints
-these values before board initialization, this might help too: boot
-win, start tv app, softboot (loadlin) into linux and load bttv with
-this enabled.  If you hav'nt Windows installed, this is a trial and
-error game...
+from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil (doesn't
+work with bt878 boards according to some reports I received).  You
+might also dig around in the *.ini files of the Windows applications.
+You can have a look at the board to see which of the gpio pins are
+connected at all and then start trial-and-error ...
+
+
+Starting with release 0.7.41 bttv has a number of insmod options to
+make the gpio debugging easier:
+
+bttv_gpio=0/1          enable/disable gpio debug messages
+gpiomask=n             set the gpiomask value
+audiomux=i,j,...       set the values of the audiomux array
+audioall=a             set the values of the audiomux array (one
+                       value for all array elements, useful to check
+                       out which effect the particular value has).
+
+The messages printed with bttv_gpio=1 look like this:
+
+       bttv0: gpio: en=00000027, out=00000024 in=00ffffd8 [audio: off]
+
+en  =  output _en_able register (BT848_GPIO_OUT_EN)
+out =  _out_put bits of the data register (BT848_GPIO_DATA),
+       i.e. BT848_GPIO_DATA & BT848_GPIO_OUT_EN
+in  =  _in_put bits of the data register,
+       i.e. BT848_GPIO_DATA & ~BT848_GPIO_OUT_EN
 
 Good luck,
 
diff --git a/Documentation/video4linux/bttv/Specs b/Documentation/video4linux/bttv/Specs
new file mode 100644 (file)
index 0000000..79b9e57
--- /dev/null
@@ -0,0 +1,3 @@
+Philips                http://www.Semiconductors.COM/pip/
+Conexant       http://www.conexant.com/techinfo/default.asp
+Micronas       http://www.micronas.de/pages/product_documentation/index.html
index 8b4b7d0af9c4d1d0935f1f6f656f7cd8adde9f78..e87bfc0cc0651c88340993fb693623964b7a22fa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -180,6 +180,52 @@ DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
 
 DRIVERS += $(DRIVERS-y)
 
+
+# files removed with 'make clean'
+CLEAN_FILES = \
+       kernel/ksyms.lst include/linux/compile.h \
+       vmlinux System.map \
+       .tmp* \
+       drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \
+       drivers/char/conmakehash \
+       drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist \
+       drivers/zorro/devlist.h drivers/zorro/gen-devlist \
+       drivers/sound/bin2hex drivers/sound/hex2hex \
+       drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \
+       net/khttpd/make_times_h \
+       net/khttpd/times.h \
+       submenu*
+# directories removed with 'make clean'
+CLEAN_DIRS = \
+       modules
+
+# files removed with 'make mrproper'
+MRPROPER_FILES = \
+       include/linux/autoconf.h include/linux/version.h \
+       drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \
+       drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \
+       drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \
+       drivers/net/hamradio/soundmodem/gentbl \
+       drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h \
+       drivers/sound/*_boot.h drivers/sound/.*.boot \
+       drivers/sound/msndinit.c \
+       drivers/sound/msndperm.c \
+       drivers/sound/pndsperm.c \
+       drivers/sound/pndspini.c \
+       drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \
+       .version .config* config.in config.old \
+       scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \
+       scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
+       .menuconfig.log \
+       include/asm \
+       .hdepend scripts/mkdep scripts/split-include scripts/docproc \
+       $(TOPDIR)/include/linux/modversions.h
+# directories removed with 'make mrproper'
+MRPROPER_DIRS = \
+       include/config \
+       $(TOPDIR)/include/linux/modules
+
+
 include arch/$(ARCH)/Makefile
 
 export CPPFLAGS CFLAGS AFLAGS
@@ -355,47 +401,18 @@ modules modules_install: dummy
 endif
 
 clean: archclean
-       rm -f kernel/ksyms.lst include/linux/compile.h
        find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -print \
                | grep -v lxdialog/ | xargs rm -f
-       rm -f vmlinux System.map
-       rm -f .tmp*
-       rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c
-       rm -f drivers/char/conmakehash
-       rm -f drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist
-       rm -f drivers/zorro/devlist.h drivers/zorro/gen-devlist
-       rm -f drivers/sound/bin2hex drivers/sound/hex2hex
-       rm -f drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2}
-       rm -f net/khttpd/make_times_h
-       rm -f net/khttpd/times.h
-       rm -f submenu*
-       rm -rf modules
+       rm -f $(CLEAN_FILES)
+       rm -rf $(CLEAN_DIRS)
        $(MAKE) -C Documentation/DocBook clean
 
 mrproper: clean archmrproper
-       rm -f include/linux/autoconf.h include/linux/version.h
-       rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h
-       rm -f drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h
-       rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h
-       rm -f drivers/net/hamradio/soundmodem/gentbl
-       rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h
-       rm -f drivers/sound/*_boot.h drivers/sound/.*.boot
-       rm -f drivers/sound/msndinit.c
-       rm -f drivers/sound/msndperm.c
-       rm -f drivers/sound/pndsperm.c
-       rm -f drivers/sound/pndspini.c
-       rm -f drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw
-       rm -f .version .config* config.in config.old
-       rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
-       rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
-       rm -f .menuconfig.log
-       rm -f include/asm
-       rm -rf include/config
        find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
-       rm -f .hdepend scripts/mkdep scripts/split-include scripts/docproc
-       rm -f $(TOPDIR)/include/linux/modversions.h
-       rm -rf $(TOPDIR)/include/linux/modules
+       rm -f $(MRPROPER_FILES)
+       rm -rf $(MRPROPER_DIRS)
        $(MAKE) -C Documentation/DocBook mrproper
+
 distclean: mrproper
        rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
                -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
index 4d34dfee39fc5692174053babbb4bd2ee6b2c644..2971c8908e3e0e2f3036cf84e2c88e7c958e1883 100644 (file)
@@ -361,21 +361,29 @@ CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DE4X5 is not set
 # CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PM is not set
+# CONFIG_LNE390 is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
 # CONFIG_8139TOO is not set
+# CONFIG_RTL8129 is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
 # CONFIG_NET_POCKET is not set
 
 #
index 24bf2be750eac58d20bbd3f48ddf49a53ba8184c..b7abf6af4c7e6ff8444365555130bbea6e583b29 100644 (file)
@@ -1571,8 +1571,6 @@ static struct miscdevice apm_device = {
        &apm_bios_fops
 };
 
-#define APM_INIT_ERROR_RETURN  return -1
-
 /*
  * Just start the APM thread. We do NOT want to do APM BIOS
  * calls from anything but the APM thread, if for no other reason
@@ -1587,7 +1585,7 @@ static int __init apm_init(void)
 {
        if (apm_bios_info.version == 0) {
                printk(KERN_INFO "apm: BIOS not found.\n");
-               APM_INIT_ERROR_RETURN;
+               return -ENODEV;
        }
        printk(KERN_INFO
                "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
@@ -1597,7 +1595,7 @@ static int __init apm_init(void)
                driver_version);
        if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
                printk(KERN_INFO "apm: no 32 bit BIOS support\n");
-               APM_INIT_ERROR_RETURN;
+               return -ENODEV;
        }
 
        /*
@@ -1626,15 +1624,15 @@ static int __init apm_init(void)
 
        if (apm_disabled) {
                printk(KERN_NOTICE "apm: disabled on user request.\n");
-               APM_INIT_ERROR_RETURN;
+               return -ENODEV;
        }
        if ((smp_num_cpus > 1) && !power_off) {
                printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
-               APM_INIT_ERROR_RETURN;
+               return -ENODEV;
        }
        if (PM_IS_ACTIVE()) {
                printk(KERN_NOTICE "apm: overridden by ACPI.\n");
-               APM_INIT_ERROR_RETURN;
+               return -ENODEV;
        }
        pm_active = 1;
 
@@ -1683,7 +1681,7 @@ static int __init apm_init(void)
        if (smp_num_cpus > 1) {
                printk(KERN_NOTICE
                   "apm: disabled - APM is not SMP safe (power off active).\n");
-               APM_INIT_ERROR_RETURN;
+               return 0;
        }
 
        misc_register(&apm_device);
index 79ab9a5ff8713f7205abef432f7a76adbe432964..59826db68388802b135424f533bb9001706b60f8 100644 (file)
@@ -66,22 +66,19 @@ void do_machine_check(struct pt_regs * regs, long error_code)
  *     This has to be run for each processor
  */
  
-void mcheck_init(void)
+void mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int i;
-       struct cpuinfo_x86 *c;
        static int done;
 
-       c=cpu_data+smp_processor_id();
-       
-       if(c->x86_vendor!=X86_VENDOR_INTEL)
+       if( c->x86_vendor != X86_VENDOR_INTEL )
                return;
        
-       if(!(c->x86_capability&X86_FEATURE_MCE))
+       if( !test_bit(X86_FEATURE_TSC, &c->x86_capability) )
                return;
                
-       if(!(c->x86_capability&X86_FEATURE_MCA))
+       if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
                return;
                
        /* Ok machine check is available */
index b17c30041d7ca2fdec5703d38f771ddd575ff341..86f154da8b3a9e4cb34f0dcbe37e14740d30b24f 100644 (file)
@@ -378,7 +378,7 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
        processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
                                   (boot_cpu_data.x86_model << 4) |
                                   boot_cpu_data.x86_mask;
-       processor.mpc_featureflag = boot_cpu_data.x86_capability;
+       processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
        processor.mpc_reserved[0] = 0;
        processor.mpc_reserved[1] = 0;
        for (i = 0; i < 2; i++) {
index fe52293daf1a82efd6fa8eea18d6bd60a6b54623..badb6ed152df2204fd9d72b1297e89284906f984 100644 (file)
@@ -231,7 +231,7 @@ static int msr_open(struct inode *inode, struct file *file)
   
   if ( !(cpu_online_map & (1UL << cpu)) )
     return -ENXIO;             /* No such CPU */
-  if ( !(c->x86_capability & X86_FEATURE_MSR) )
+  if ( !test_bit(X86_FEATURE_MSR, &c->x86_capability) )
     return -EIO;               /* MSR not supported */
   
   return 0;
index 045374d503db6b1bb6e204ef3811596a819bf21c..47c83f58ed9f1d86790c996523109e71f9cf7f56 100644 (file)
     20000221   Richard Gooch <rgooch@atnf.csiro.au>
                Compile fix if procfs and devfs not enabled.
               Formatting changes.
+  v1.37
+    20001109   H. Peter Anvin <hpa@zytor.com>
+              Use the new centralized CPU feature detects.
 */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/hardirq.h>
 #include <linux/irq.h>
 
-#define MTRR_VERSION            "1.36 (20000221)"
+#define MTRR_VERSION            "1.37 (20001109)"
 
 #define TRUE  1
 #define FALSE 0
 
+/*
+ * The code assumes all processors support the same MTRR
+ * interface.  This is generally a good assumption, but could
+ * potentially be a problem.
+ */
+enum mtrr_if_type {
+    MTRR_IF_NONE,              /* No MTRRs supported */
+    MTRR_IF_INTEL,             /* Intel (P6) standard MTRRs */
+    MTRR_IF_AMD_K6,            /* AMD pre-Athlon MTRRs */
+    MTRR_IF_CYRIX_ARR,         /* Cyrix ARRs */
+    MTRR_IF_CENTAUR_MCR,       /* Centaur MCRs */
+} mtrr_if = MTRR_IF_NONE;
+
+static __initdata char *mtrr_if_name[] = {
+    "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR"
+};
+
 #define MTRRcap_MSR     0x0fe
 #define MTRRdefType_MSR 0x2ff
 
@@ -350,18 +370,11 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
     /*  Disable interrupts locally  */
     __save_flags (ctxt->flags); __cli ();
 
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
-       /* else fall through */
-      case X86_VENDOR_CENTAUR:
-       if(boot_cpu_data.x86 != 6)
-               return;
-       /*break;*/
-    }
+    if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
+        return;
+
     /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
-    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+    if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) )
        asm volatile ("movl  %%cr4, %0\n\t"
                      "movl  %0, %1\n\t"
                      "andb  $0x7f, %b1\n\t"
@@ -377,20 +390,15 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
                  "wbinvd\n\t"
                  : "=r" (tmp) : : "memory");
 
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-      case X86_VENDOR_INTEL:
-      case X86_VENDOR_CENTAUR:
+    if ( mtrr_if == MTRR_IF_INTEL ) {
        /*  Disable MTRRs, and set the default type to uncached  */
        rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
        wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
-       break;
-      case X86_VENDOR_CYRIX:
+    } else {
+       /* Cyrix ARRs - everything else were excluded at the top */
        tmp = getCx86 (CX86_CCR3);
        setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
        ctxt->ccr3 = tmp;
-       break;
     }
 }   /*  End Function set_mtrr_prepare  */
 
@@ -399,33 +407,21 @@ static void set_mtrr_done (struct set_mtrr_context *ctxt)
 {
     unsigned long tmp;
 
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
-       /* else fall through */
-      case X86_VENDOR_CENTAUR:
-       if(boot_cpu_data.x86 != 6)
-       {
-               __restore_flags (ctxt->flags);
-               return;
-       }
-       /*break;*/
+    if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) {
+        __restore_flags (ctxt->flags);
+        return;
     }
+
     /*  Flush caches and TLBs  */
     asm volatile ("wbinvd" : : : "memory" );
 
     /*  Restore MTRRdefType  */
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-      case X86_VENDOR_INTEL:
-      case X86_VENDOR_CENTAUR:
+    if ( mtrr_if == MTRR_IF_INTEL ) {
+       /* Intel (P6) standard MTRRs */
        wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
-       break;
-      case X86_VENDOR_CYRIX:
+    } else {
+       /* Cyrix ARRs - everything else was excluded at the top */
        setCx86 (CX86_CCR3, ctxt->ccr3);
-       break;
     }
 
     /*  Enable caches  */
@@ -435,7 +431,7 @@ static void set_mtrr_done (struct set_mtrr_context *ctxt)
                  : "=r" (tmp) : : "memory");
 
     /*  Restore value of CR4  */
-    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+    if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) )
        asm volatile ("movl  %0, %%cr4"
                      : : "r" (ctxt->cr4val) : "memory");
 
@@ -448,31 +444,20 @@ static unsigned int get_num_var_ranges (void)
 {
     unsigned long config, dummy;
 
-    switch (boot_cpu_data.x86_vendor)
+    switch ( mtrr_if )
     {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 < 6) return 2; /* pre-Athlon CPUs */
-       /* else fall through */
-      case X86_VENDOR_INTEL:
+    case MTRR_IF_INTEL:
        rdmsr (MTRRcap_MSR, config, dummy);
        return (config & 0xff);
-       /*break;*/
-      case X86_VENDOR_CYRIX:
-       /*  Cyrix have 8 ARRs  */
+    case MTRR_IF_AMD_K6:
+       return 2;
+    case MTRR_IF_CYRIX_ARR:
        return 8;
-      case X86_VENDOR_CENTAUR:
-        /*  and Centaur has 8 MCR's  */
-       if(boot_cpu_data.x86==5)
-               return 8;
-       /*  the cyrix III has intel compatible MTRR */
-       if(boot_cpu_data.x86==6)
-       {
-               rdmsr (MTRRcap_MSR, config, dummy);
-               return (config & 0xff);
-       }
-       /*break;*/
+    case MTRR_IF_CENTAUR_MCR:
+       return 8;
+    default:
+       return 0;
     }
-    return 0;
 }   /*  End Function get_num_var_ranges  */
 
 /*  Returns non-zero if we have the write-combining memory type  */
@@ -480,24 +465,19 @@ static int have_wrcomb (void)
 {
     unsigned long config, dummy;
 
-    switch (boot_cpu_data.x86_vendor)
+    switch ( mtrr_if )
     {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */
-       /* else fall through */
-      case X86_VENDOR_CENTAUR:
-        if (boot_cpu_data.x86 == 5)
-               return 1;       /* C6 */
-        /* CyrixIII is Intel like */
-      case X86_VENDOR_INTEL:
+    case MTRR_IF_INTEL:
        rdmsr (MTRRcap_MSR, config, dummy);
        return (config & (1<<10));
-       /*break;*/
-      case X86_VENDOR_CYRIX:
        return 1;
-       /*break;*/
+    case MTRR_IF_AMD_K6:
+    case MTRR_IF_CENTAUR_MCR:
+    case MTRR_IF_CYRIX_ARR:
+       return 1;
+    default:
+       return 0;
     }
-    return 0;
 }   /*  End Function have_wrcomb  */
 
 static void intel_get_mtrr (unsigned int reg, unsigned long *base,
@@ -1171,47 +1151,48 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
     mtrr_type ltype;
     unsigned long lbase, lsize, last;
 
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
-    switch (boot_cpu_data.x86_vendor)
+    switch ( mtrr_if )
     {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 < 6)
-       {   /* pre-Athlon CPUs */
-           /* Apply the K6 block alignment and size rules
-            In order
-               o Uncached or gathering only
-               o 128K or bigger block
-               o Power of 2 block
-               o base suitably aligned to the power
-           */
-           if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
-                (size & ~(size-1))-size || ( base & (size-1) ) )
-               return -EINVAL;
-         break;
-       }
-       /*  Else fall through  */
-      case X86_VENDOR_INTEL:
-       /*  Double check for Intel, we may run on Athlon  */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+    case MTRR_IF_NONE:
+       return -ENXIO;          /* No MTRRs whatsoever */
+
+    case MTRR_IF_AMD_K6:
+       /* Apply the K6 block alignment and size rules
+          In order
+          o Uncached or gathering only
+          o 128K or bigger block
+          o Power of 2 block
+          o base suitably aligned to the power
+       */
+       if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+            (size & ~(size-1))-size || ( base & (size-1) ) )
+           return -EINVAL;
+       break;
+
+    case MTRR_IF_INTEL:
+       /*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
+       if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+            boot_cpu_data.x86 == 6 &&
+            boot_cpu_data.x86_model == 1 &&
+            boot_cpu_data.x86_mask <= 7 )
        {
-           /*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
-           if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
-                (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) -1 ) ) )
+           if ( base & ((1 << 22)-1) )
            {
                printk (KERN_WARNING "mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
                return -EINVAL;
            }
        }
-       /*  Fall through  */
-      case X86_VENDOR_CYRIX:
-      case X86_VENDOR_CENTAUR:
+       /* Fall through */
+       
+    case MTRR_IF_CYRIX_ARR:
+    case MTRR_IF_CENTAUR_MCR:
        if ( (base & 0xfff) || (size & 0xfff) )
        {
            printk ("mtrr: size and base must be multiples of 4 kiB\n");
            printk ("mtrr: size: %lx  base: %lx\n", size, base);
            return -EINVAL;
        }
-        if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 5)
+        if ( mtrr_if == MTRR_IF_CENTAUR_MCR )
        {
            if (type != MTRR_TYPE_WRCOMB)
            {
@@ -1237,10 +1218,11 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
            return -EINVAL;
        }
        break;
-      default:
+
+    default:
        return -EINVAL;
-       /*break;*/
     }
+
     if (type >= MTRR_NUM_TYPES)
     {
        printk ("mtrr: type: %u illegal\n", type);
@@ -1328,7 +1310,8 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
     mtrr_type ltype;
     unsigned long lbase, lsize;
 
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+    if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO;
+
     max = get_num_var_ranges ();
     down (&main_lock);
     if (reg < 0)
@@ -1356,7 +1339,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
        printk ("mtrr: register: %d too big\n", reg);
        return -EINVAL;
     }
-    if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX)
+    if ( mtrr_if == MTRR_IF_CYRIX_ARR )
     {
        if ( (reg == 3) && arr3_protected )
        {
@@ -1772,42 +1755,41 @@ static void __init centaur_mcr_init(void)
     set_mtrr_done (&ctxt);
 }   /*  End Function centaur_mcr_init  */
 
-static void __init mtrr_setup(void)
+static int __init mtrr_setup(void)
 {
-    printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 < 6)
-       {
-           /* pre-Athlon CPUs */
-           get_mtrr = amd_get_mtrr;
-           set_mtrr_up = amd_set_mtrr_up;
-           break;
-       }
-       /*   Else fall through  */
-      case X86_VENDOR_INTEL:
+    if ( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ) {
+       /* Intel (P6) standard MTRRs */
+       mtrr_if = MTRR_IF_INTEL;
        get_mtrr = intel_get_mtrr;
        set_mtrr_up = intel_set_mtrr_up;
-       break;
-      case X86_VENDOR_CYRIX:
+    } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) {
+       /* Pre-Athlon (K6) AMD CPU MTRRs */
+       mtrr_if = MTRR_IF_AMD_K6;
+       get_mtrr = amd_get_mtrr;
+       set_mtrr_up = amd_set_mtrr_up;
+    } else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) {
+       /* Cyrix ARRs */
+       mtrr_if = MTRR_IF_CYRIX_ARR;
        get_mtrr = cyrix_get_arr;
        set_mtrr_up = cyrix_set_arr_up;
        get_free_region = cyrix_get_free_region;
-       break;
-     case X86_VENDOR_CENTAUR:
-        if(boot_cpu_data.x86 == 5)
-        {
-               get_mtrr = centaur_get_mcr;
-               set_mtrr_up = centaur_set_mcr_up;
-       }
-       if(boot_cpu_data.x86 == 6)
-       {
-               get_mtrr = intel_get_mtrr;
-               set_mtrr_up = intel_set_mtrr_up;
-       }
-        break;
+       cyrix_arr_init();
+    } else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) {
+       /* Centaur MCRs */
+       mtrr_if = MTRR_IF_CENTAUR_MCR;
+       get_mtrr = centaur_get_mcr;
+       set_mtrr_up = centaur_set_mcr_up;
+       centaur_mcr_init();
+    } else {
+       /* No supported MTRR interface */
+       mtrr_if = MTRR_IF_NONE;
     }
+
+    printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n"
+           "mtrr: detected mtrr type: %s\n",
+           MTRR_VERSION, mtrr_if_name[mtrr_if]);
+
+    return (mtrr_if != MTRR_IF_NONE);
 }   /*  End Function mtrr_setup  */
 
 #ifdef CONFIG_SMP
@@ -1817,24 +1799,12 @@ static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
 
 void __init mtrr_init_boot_cpu(void)
 {
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
-    mtrr_setup ();
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 < 6) break;  /*  Pre-Athlon CPUs  */
-      case X86_VENDOR_INTEL:
+    if ( !mtrr_setup () )
+       return;
+
+    if ( mtrr_if == MTRR_IF_INTEL ) {
+       /* Only for Intel MTRRs */
        get_mtrr_state (&smp_mtrr_state);
-       break;
-      case X86_VENDOR_CYRIX:
-       cyrix_arr_init ();
-       break;
-      case X86_VENDOR_CENTAUR:         /* C6 and Cyrix III have different ones */
-       if(boot_cpu_data.x86 == 5)
-               centaur_mcr_init ();
-       if(boot_cpu_data.x86 == 6)
-               get_mtrr_state(&smp_mtrr_state);
-        break;
     }
 }   /*  End Function mtrr_init_boot_cpu  */
 
@@ -1859,16 +1829,12 @@ static void __init intel_mtrr_init_secondary_cpu(void)
 
 void __init mtrr_init_secondary_cpu(void)
 {
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-       /*  Just for robustness: pre-Athlon CPUs cannot do SMP  */
-       if (boot_cpu_data.x86 < 6) break;
-      case X86_VENDOR_INTEL:
-       intel_mtrr_init_secondary_cpu ();
+    switch ( mtrr_if ) {
+    case MTRR_IF_INTEL:
+       /* Intel (P6) standard MTRRs */
+       intel_mtrr_init_secondary_cpu();
        break;
-      case X86_VENDOR_CYRIX:
+    case MTRR_IF_CYRIX_ARR:
        /* This is _completely theoretical_!
         * I assume here that one day Cyrix will support Intel APIC.
         * In reality on non-Intel CPUs we won't even get to this routine.
@@ -1877,39 +1843,26 @@ void __init mtrr_init_secondary_cpu(void)
         */
        cyrix_arr_init_secondary ();
        break;
-      default:
+    default:
+       /* I see no MTRRs I can support in SMP mode... */
        printk ("mtrr: SMP support incomplete for this vendor\n");
-       break;
     }
 }   /*  End Function mtrr_init_secondary_cpu  */
 #endif  /*  CONFIG_SMP  */
 
 int __init mtrr_init(void)
 {
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
 #ifdef CONFIG_SMP
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_AMD:
-       if (boot_cpu_data.x86 < 6) break;  /*  Pre-Athlon CPUs  */
-      case X86_VENDOR_INTEL:
+    /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */
+
+    if ( mtrr_if == MTRR_IF_INTEL ) {
        finalize_mtrr_state (&smp_mtrr_state);
        mtrr_state_warn (smp_changes_mask);
-       break;
     }
-#else  /*  CONFIG_SMP  */
-    mtrr_setup ();
-    switch (boot_cpu_data.x86_vendor)
-    {
-      case X86_VENDOR_CYRIX:
-       cyrix_arr_init ();
-       break;
-      case X86_VENDOR_CENTAUR:
-        if(boot_cpu_data.x86 == 5)
-               centaur_mcr_init ();
-        break;
-    }
-#endif  /*  !CONFIG_SMP  */
+#else
+    if ( !mtrr_setup() )
+       return 0;               /* MTRRs not supported? */
+#endif
 
 #ifdef CONFIG_PROC_FS
     proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
@@ -1924,3 +1877,11 @@ int __init mtrr_init(void)
     init_table ();
     return 0;
 }   /*  End Function mtrr_init  */
+
+/*
+ * Local Variables:
+ * mode:c
+ * c-file-style:"k&r"
+ * c-basic-offset:4
+ * End:
+ */
index e5ace04040d055be5ed453bdb7369a1a4b7177d1..4bee9fc12f0868287451c61a49b31928a0519b4d 100644 (file)
@@ -55,6 +55,9 @@
  *  Cyrix III, Pentium IV support.
  *  Dave Jones <davej@suse.de>, October 2000
  *
+ *  Massive cleanup of CPU detection and bug handling;
+ *  Transmeta CPU detection,
+ *  H. Peter Anvin <hpa@zytor.com>, November 2000
  */
 
 /*
@@ -545,7 +548,7 @@ static inline void parse_mem_cmdline (char ** cmdline_p)
                                to--;
                        if (!memcmp(from+4, "nopentium", 9)) {
                                from += 9+4;
-                               boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
+                               clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);
                        } else if (!memcmp(from+4, "exactmap", 8)) {
                                from += 8+4;
                                e820.nr_map = 0;
@@ -848,70 +851,158 @@ void __init setup_arch(char **cmdline_p)
 #endif
 }
 
+#ifndef CONFIG_X86_TSC
+static int tsc_disable __initdata = 0;
+
+static int __init tsc_setup(char *str)
+{
+       tsc_disable = 1;
+       return 1;
+}
+
+__setup("notsc", tsc_setup);
+#endif
+
 static int __init get_model_name(struct cpuinfo_x86 *c)
 {
-       unsigned int n, dummy, *v;
+       unsigned int *v;
+       char *p, *q;
 
-       cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
-       if (n < 0x80000004)
+       if (cpuid_eax(0x80000000) < 0x80000004)
                return 0;
-       cpuid(0x80000001, &dummy, &dummy, &dummy, &(c->x86_capability));
+
        v = (unsigned int *) c->x86_model_id;
        cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
        cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
        cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
        c->x86_model_id[48] = 0;
+
+       /* Intel chips right-justify this string for some dumb reason;
+          undo that brain damage */
+       p = q = &c->x86_model_id[0];
+       while ( *p == ' ' )
+            p++;
+       if ( p != q ) {
+            while ( *p )
+                 *q++ = *p++;
+            while ( q <= &c->x86_model_id[48] )
+                 *q++ = '\0';  /* Zero-pad the rest */
+       }
+
        return 1;
 }
 
 
 static void __init display_cacheinfo(struct cpuinfo_x86 *c)
 {
-       unsigned int n, dummy, ecx, edx;
+       unsigned int n, dummy, ecx, edx, l2size;
 
-       cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
+       n = cpuid_eax(0x80000000);
 
        if (n >= 0x80000005) {
                cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
-               printk("CPU: L1 I Cache: %dK  L1 D Cache: %dK (%d bytes/line)\n",
-                       edx>>24, ecx>>24, edx&0xFF);
+               printk("CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
+                       edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
                c->x86_cache_size=(ecx>>24)+(edx>>24);  
        }
 
-       if (n < 0x80000006)     /* Cyrix just has large L1. */
+       if (n < 0x80000006)     /* Some chips just has a large L1. */
                return;
 
-       cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
-       c->x86_cache_size = ecx >>16;
+       ecx = cpuid_ecx(0x80000006);
+       l2size = ecx >> 16;
 
        /* AMD errata T13 (order #21922) */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-               boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 3 &&
-               boot_cpu_data.x86_mask == 0)
-       {
-               c->x86_cache_size = 64;
+       if (c->x86_vendor == X86_VENDOR_AMD &&
+           c->x86 == 6 &&
+           c->x86_model == 3 &&
+           c->x86_mask == 0) {
+               l2size = 64;
        }
-       printk("CPU: L2 Cache: %dK\n", ecx>>16);
+
+       if ( l2size == 0 )
+               return;         /* Again, no L2 cache is possible */
+
+       c->x86_cache_size = l2size;
+
+       printk("CPU: L2 Cache: %dK (%d bytes/line)\n",
+              l2size, ecx & 0xFF);
 }
 
+/*
+ *     B step AMD K6 before B 9730xxxx have hardware bugs that can cause
+ *     misexecution of code under Linux. Owners of such processors should
+ *     contact AMD for precise details and a CPU swap.
+ *
+ *     See     http://www.mygale.com/~poulot/k6bug.html
+ *             http://www.amd.com/K6/k6docs/revgd.html
+ *
+ *     The following test is erm.. interesting. AMD neglected to up
+ *     the chip setting when fixing the bug but they also tweaked some
+ *     performance at the same time..
+ */
+extern void vide(void);
+__asm__(".align 4\nvide: ret");
 
-static int __init amd_model(struct cpuinfo_x86 *c)
+static int __init init_amd(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        unsigned long flags;
        int mbytes = max_mapnr >> (20-PAGE_SHIFT);
+       int r;
 
-       int r=get_model_name(c);
+       /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+          3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+       clear_bit(0*32+31, &c->x86_capability);
+       
+       r = get_model_name(c);
 
        switch(c->x86)
        {
                case 5:
                        if( c->x86_model < 6 )
                        {
-                               /* Anyone with a K5 want to fill this in */                             
+                               /* Based on AMD doc 20734R - June 2000 */
+                               if ( c->x86_model == 0 ) {
+                                       clear_bit(X86_FEATURE_APIC, &c->x86_capability);
+                                       set_bit(X86_FEATURE_PGE, &c->x86_capability);
+                               }
                                break;
                        }
                        
+                       if ( c->x86_model == 6 && c->x86_mask == 1 ) {
+                               const int K6_BUG_LOOP = 1000000;
+                               int n;
+                               void (*f_vide)(void);
+                               unsigned long d, d2;
+                               
+                               printk(KERN_INFO "AMD K6 stepping B detected - ");
+                               
+                               /*
+                                * It looks like AMD fixed the 2.6.2 bug and improved indirect 
+                                * calls at the same time.
+                                */
+
+                               n = K6_BUG_LOOP;
+                               f_vide = vide;
+                               rdtscl(d);
+                               while (n--) 
+                                       f_vide();
+                               rdtscl(d2);
+                               d = d2-d;
+                               
+                               /* Knock these two lines out if it debugs out ok */
+                               printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
+                               printk(KERN_INFO "AMD K6 stepping B detected - ");
+                               /* -- cut here -- */
+                               if (d > 20*K6_BUG_LOOP) 
+                                       printk("system stability may be impaired when more than 32 MB are used.\n");
+                               else 
+                                       printk("probably OK (after B9730xxxx).\n");
+                               printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
+                       }
+
                        /* K6 with old style WHCR */
                        if( c->x86_model < 8 ||
                                (c->x86_model== 8 && c->x86_mask < 8))
@@ -956,11 +1047,11 @@ static int __init amd_model(struct cpuinfo_x86 *c)
                                }
 
                                /*  Set MTRR capability flag if appropriate */
-                               if((boot_cpu_data.x86_model == 13) ||
-                                  (boot_cpu_data.x86_model == 9) ||
-                                  ((boot_cpu_data.x86_model == 8) && 
-                                   (boot_cpu_data.x86_mask >= 8)))
-                                       c->x86_capability |= X86_FEATURE_MTRR;
+                               if ( (c->x86_model == 13) ||
+                                    (c->x86_model == 9) ||
+                                    ((c->x86_model == 8) && 
+                                    (c->x86_mask >= 8)) )
+                                       set_bit(X86_FEATURE_K6_MTRR, &c->x86_capability);
                                break;
                        }
 
@@ -974,17 +1065,6 @@ static int __init amd_model(struct cpuinfo_x86 *c)
        return r;
 }
 
-static void __init intel_model(struct cpuinfo_x86 *c)
-{
-       unsigned int *v = (unsigned int *) c->x86_model_id;
-       cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
-       cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
-       cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-       c->x86_model_id[48] = 0;
-       printk("CPU: %s\n", c->x86_model_id);
-}
-                       
-
 /*
  * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
  */
@@ -1044,14 +1124,56 @@ static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
 static char cyrix_model_mult1[] __initdata = "12??43";
 static char cyrix_model_mult2[] __initdata = "12233445";
 
-static void __init cyrix_model(struct cpuinfo_x86 *c)
+/*
+ * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
+ * BIOSes for compatability with DOS games.  This makes the udelay loop
+ * work correctly, and improves performance.
+ */
+
+extern void calibrate_delay(void) __init;
+
+static void __init check_cx686_slop(struct cpuinfo_x86 *c)
+{
+       if (Cx86_dir0_msb == 3) {
+               unsigned char ccr3, ccr5;
+
+               cli();
+               ccr3 = getCx86(CX86_CCR3);
+               setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
+               ccr5 = getCx86(CX86_CCR5);
+               if (ccr5 & 2)
+                       setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
+               setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
+               sti();
+
+               if (ccr5 & 2) { /* possible wrong calibration done */
+                       printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
+                       calibrate_delay();
+                       c->loops_per_sec = loops_per_sec;
+               }
+       }
+}
+
+static void __init init_cyrix(struct cpuinfo_x86 *c)
 {
        unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
        char *buf = c->x86_model_id;
        const char *p = NULL;
 
+       /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+          3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+       clear_bit(0*32+31, &c->x86_capability);
+
+       /* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */
+       if ( test_bit(1*32+24, &c->x86_capability) ) {
+               clear_bit(1*32+24, &c->x86_capability);
+               set_bit(X86_FEATURE_CXMMX, &c->x86_capability);
+       }
+
        do_cyrix_devid(&dir0, &dir1);
 
+       check_cx686_slop(c);
+
        Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family"   */
        dir0_lsn = dir0 & 0xf;                /* model or clock multiplier */
 
@@ -1092,7 +1214,7 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
                } else             /* 686 */
                        p = Cx86_cb+1;
                /* Emulate MTRRs using Cyrix's ARRs. */
-               c->x86_capability |= X86_FEATURE_MTRR;
+               set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
                /* 6x86's contain this bug */
                c->coma_bug = 1;
                break;
@@ -1124,14 +1246,14 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
                /* GXm supports extended cpuid levels 'ala' AMD */
                if (c->cpuid_level == 2) {
                        get_model_name(c);  /* get CPU marketing name */
-                       c->x86_capability&=~X86_FEATURE_TSC;
+                       clear_bit(X86_FEATURE_TSC, c->x86_capability);
                        return;
                }
                else {  /* MediaGX */
                        Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
                        p = Cx86_cb+2;
                        c->x86_model = (dir1 & 0x20) ? 1 : 2;
-                       c->x86_capability&=~X86_FEATURE_TSC;
+                       clear_bit(X86_FEATURE_TSC, &c->x86_capability);
                }
                break;
 
@@ -1144,7 +1266,7 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
                if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
                        (c->x86_model)++;
                /* Emulate MTRRs using Cyrix's ARRs. */
-               c->x86_capability |= X86_FEATURE_MTRR;
+               set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
                break;
 
        case 0xf:  /* Cyrix 486 without DEVID registers */
@@ -1170,7 +1292,7 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
        return;
 }
 
-static void __init centaur_model(struct cpuinfo_x86 *c)
+static void __init init_centaur(struct cpuinfo_x86 *c)
 {
        enum {
                ECX8=1<<1,
@@ -1199,6 +1321,10 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
        u32  lo,hi,newlo;
        u32  aa,bb,cc,dd;
 
+       /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+          3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+       clear_bit(0*32+31, &c->x86_capability);
+
        switch (c->x86) {
 
                case 5:
@@ -1208,7 +1334,7 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
                                fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK;
                                fcr_clr=DPDC;
                                printk("Disabling bugged TSC.\n");
-                               c->x86_capability &= ~X86_FEATURE_TSC;
+                               clear_bit(X86_FEATURE_TSC, &c->x86_capability);
                                break;
                        case 8:
                                switch(c->x86_mask) {
@@ -1250,15 +1376,15 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
                                printk("Centaur FCR is 0x%X\n",lo);
                        }
                        /* Emulate MTRRs using Centaur's MCR. */
-                       c->x86_capability |= X86_FEATURE_MTRR;
+                       set_bit(X86_FEATURE_CENTAUR_MCR, &c->x86_capability);
                        /* Report CX8 */
-                       c->x86_capability |= X86_FEATURE_CX8;
+                       set_bit(X86_FEATURE_CX8, &c->x86_capability);
                        /* Set 3DNow! on Winchip 2 and above. */
                        if (c->x86_model >=8)
-                               c->x86_capability |= X86_FEATURE_AMD3D;
+                               set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
                        /* See if we can find out some more. */
-                       cpuid(0x80000000,&aa,&bb,&cc,&dd);
-                       if (aa>=0x80000005) { /* Yes, we can. */
+                       if ( cpuid_eax(0x80000000) >= 0x80000005 ) {
+                               /* Yes, we can. */
                                cpuid(0x80000005,&aa,&bb,&cc,&dd);
                                /* Add L1 data and code cache sizes. */
                                c->x86_cache_size = (cc>>24)+(dd>>24);
@@ -1273,10 +1399,10 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
                                        lo |= (1<<1 | 1<<7);    /* Report CX8 & enable PGE */
                                        wrmsr (0x1107, lo, hi);
 
-                                       c->x86_capability |= X86_FEATURE_CX8;
+                                       set_bit(X86_FEATURE_CX8, &c->x86_capability);
                                        rdmsr (0x80000001, lo, hi);
                                        if (hi & (1<<31))
-                                               c->x86_capability |= X86_FEATURE_AMD3D;
+                                               set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
 
                                        get_model_name(c);
                                        display_cacheinfo(c);
@@ -1288,7 +1414,7 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
 }
 
 
-static void __init transmeta_model(struct cpuinfo_x86 *c)
+static void __init init_transmeta(struct cpuinfo_x86 *c)
 {
        unsigned int cap_mask, uk, max, dummy;
        unsigned int cms_rev1, cms_rev2;
@@ -1299,17 +1425,15 @@ static void __init transmeta_model(struct cpuinfo_x86 *c)
        display_cacheinfo(c);
 
        /* Print CMS and CPU revision */
-       cpuid(0x80860000, &max, &dummy, &dummy, &dummy);
+       max = cpuid_eax(0x80860000);
        if ( max >= 0x80860001 ) {
                cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); 
-               printk("CPU: Processor revision %u.%u.%u.%u, %u MHz%s%s\n",
+               printk("CPU: Processor revision %u.%u.%u.%u, %u MHz\n",
                       (cpu_rev >> 24) & 0xff,
                       (cpu_rev >> 16) & 0xff,
                       (cpu_rev >> 8) & 0xff,
                       cpu_rev & 0xff,
-                      cpu_freq,
-                      (cpu_flags & 1) ? " [recovery]" : "",
-                      (cpu_flags & 2) ? " [longrun]" : "");
+                      cpu_freq);
        }
        if ( max >= 0x80860002 ) {
                cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy);
@@ -1345,13 +1469,116 @@ static void __init transmeta_model(struct cpuinfo_x86 *c)
                printk("CPU: %s\n", cpu_info);
        }
 
-       /* Unhide possibly hidden flags */
+       /* Unhide possibly hidden capability flags */
        rdmsr(0x80860004, cap_mask, uk);
        wrmsr(0x80860004, ~0, uk);
-       cpuid(0x00000001, &dummy, &dummy, &dummy, &c->x86_capability);
+       c->x86_capability[0] = cpuid_edx(0x00000001);
        wrmsr(0x80860004, cap_mask, uk);
 }
 
+extern void trap_init_f00f_bug(void);
+
+static void __init init_intel(struct cpuinfo_x86 *c)
+{
+#ifndef CONFIG_M686
+       static int f00f_workaround_enabled = 0;
+#endif
+       extern void mcheck_init(struct cpuinfo_x86 *c);
+       char *p = NULL;
+
+#ifndef CONFIG_M686
+       /*
+        * All current models of Pentium and Pentium with MMX technology CPUs
+        * have the F0 0F bug, which lets nonpriviledged users lock up the system.
+        * Note that the workaround only should be initialized once...
+        */
+       c->f00f_bug = 0;
+       if ( c->x86 == 5 ) {
+               c->f00f_bug = 1;
+               if ( !f00f_workaround_enabled ) {
+                       trap_init_f00f_bug();
+                       printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
+                       f00f_workaround_enabled = 1;
+               }
+       }
+#endif
+
+
+       if (c->cpuid_level > 1) {
+               /* supports eax=2  call */
+               int edx = cpuid_edx(2);
+
+               /* We need only the LSB */
+               edx &= 0xff;
+
+               switch (edx) {
+               case 0x40:
+                       c->x86_cache_size = 0;
+                       break;
+                       
+               case 0x41: /* 4-way 128 */
+                       c->x86_cache_size = 128;
+                       break;
+                       
+               case 0x42: /* 4-way 256 */
+               case 0x82: /* 8-way 256 */
+                       c->x86_cache_size = 256;
+                       break;
+                       
+               case 0x43: /* 4-way 512 */
+                       c->x86_cache_size = 512;
+                       break;
+                       
+               case 0x44: /* 4-way 1024 */
+               case 0x84: /* 8-way 1024 */
+                       c->x86_cache_size = 1024;
+                       break;
+                       
+               case 0x45: /* 4-way 2048 */
+               case 0x85: /* 8-way 2048 */
+                       c->x86_cache_size = 2048;
+                       break;
+                       
+               default:
+                       c->x86_cache_size = 0;
+                       break;
+               }
+       }
+
+       /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */
+       if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 )
+               clear_bit(X86_FEATURE_SEP, &c->x86_capability);
+       
+       /* Names for the Pentium II/Celeron processors 
+          detectable only by also checking the cache size.
+          Dixon is NOT a Celeron. */
+       if (c->x86 == 6) {
+               switch (c->x86_model) {
+               case 5:
+                       if (c->x86_cache_size == 0)
+                               p = "Celeron (Covington)";
+                       if (c->x86_cache_size == 256)
+                               p = "Mobile Pentium II (Dixon)";
+                       break;
+                       
+               case 6:
+                       if (c->x86_cache_size == 128)
+                               p = "Celeron (Mendocino)";
+                       break;
+                       
+               case 8:
+                       if (c->x86_cache_size == 128)
+                               p = "Celeron (Coppermine)";
+                       break;
+               }
+       }
+
+       if ( p )
+               strcpy(c->x86_model_id, p);
+
+       /* Enable MCA if available */
+       mcheck_init(c);
+}
 
 void __init get_cpu_vendor(struct cpuinfo_x86 *c)
 {
@@ -1371,7 +1598,8 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c)
                c->x86_vendor = X86_VENDOR_NEXGEN;
        else if (!strcmp(v, "RiseRiseRise"))
                c->x86_vendor = X86_VENDOR_RISE;
-       else if (!strcmp(v, "GenuineTMx86"))
+       else if (!strcmp(v, "GenuineTMx86") ||
+                !strcmp(v, "TransmetaCPU"))
                c->x86_vendor = X86_VENDOR_TRANSMETA;
        else
                c->x86_vendor = X86_VENDOR_UNKNOWN;
@@ -1379,11 +1607,13 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c)
 
 struct cpu_model_info {
        int vendor;
-       int x86;
+       int family;
        char *model_names[16];
 };
 
 /* Naming convention should be: <Name> [(<Codename>)] */
+/* This table only is used unless init_<vendor>() below doesn't set it; */
+/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
 static struct cpu_model_info cpu_models[] __initdata = {
        { X86_VENDOR_INTEL,     4,
          { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", 
@@ -1403,12 +1633,12 @@ static struct cpu_model_info cpu_models[] __initdata = {
          { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
            "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
            "Am5x86-WB" }},
-       { X86_VENDOR_AMD,       5,
+       { X86_VENDOR_AMD,       5, /* Is this this really necessary?? */
          { "K5/SSA5", "K5",
            "K5", "K5", NULL, NULL,
            "K6", "K6", "K6-2",
            "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }},
-       { X86_VENDOR_AMD,       6,
+       { X86_VENDOR_AMD,       6, /* Is this this really necessary?? */
          { "Athlon", "Athlon",
            "Athlon", NULL, "Athlon", NULL,
            NULL, NULL, NULL,
@@ -1422,11 +1652,27 @@ static struct cpu_model_info cpu_models[] __initdata = {
        { X86_VENDOR_RISE,      5,
          { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL,
            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
-       { X86_VENDOR_TRANSMETA, 5,
-         { NULL, NULL, NULL, "Crusoe", NULL, NULL, NULL,
-           NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
 };
 
+/* Look up CPU names by table lookup. */
+static char __init *table_lookup_model(struct cpuinfo_x86 *c)
+{
+       struct cpu_model_info *info = cpu_models;
+       int i;
+
+       if ( c->x86_model >= 16 )
+               return NULL;    /* Range check */
+
+       for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) {
+               if ( info->vendor == c->x86_vendor &&
+                    info->family == c->x86 ) {
+                       return info->model_names[c->x86_model];
+               }
+               info++;
+       }
+       return NULL;            /* Not found */
+}
+
 /*
  *     Detect a NexGen CPU running without BIOS hypercode new enough
  *     to have CPUID. (Thanks to Herbert Oppmann)
@@ -1451,13 +1697,15 @@ static int __init deep_magic_nexgen_probe(void)
 
 static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
 {
-       if(c->x86_capability&(X86_FEATURE_PN) && disable_x86_serial_nr) {
+       if( test_bit(X86_FEATURE_PN, &c->x86_capability) &&
+           disable_x86_serial_nr ) {
                /* Disable processor serial number */
                unsigned long lo,hi;
                rdmsr(0x119,lo,hi);
                lo |= 0x200000;
                wrmsr(0x119,lo,hi);
                printk(KERN_INFO "CPU serial number disabled.\n");
+               clear_bit(X86_FEATURE_PN, &c->x86_capability);
        }
 }
 
@@ -1470,157 +1718,255 @@ int __init x86_serial_nr_setup(char *s)
 __setup("serialnumber", x86_serial_nr_setup);
 
 
-void __init identify_cpu(struct cpuinfo_x86 *c)
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(u32 flag)
 {
-       int i=0;
-       char *p = NULL;
-       extern void mcheck_init(void);
-
-       c->loops_per_sec = loops_per_sec;
-       c->x86_cache_size = -1;
+       u32 f1, f2;
+
+       asm("pushfl\n\t"
+           "pushfl\n\t"
+           "popl %0\n\t"
+           "movl %0,%1\n\t"
+           "xorl %2,%0\n\t"
+           "pushl %0\n\t"
+           "popfl\n\t"
+           "pushfl\n\t"
+           "popl %0\n\t"
+           "popfl\n\t"
+           : "=&r" (f1), "=&r" (f2)
+           : "ir" (flag));
+
+       return ((f1^f2) & flag) != 0;
+}
 
-       get_cpu_vendor(c);
 
+/* Probe for the CPUID instruction */
+static int __init have_cpuid_p(void)
+{
+       return flag_is_changeable_p(X86_EFLAGS_ID);
+}
 
-       switch (c->x86_vendor) {
+/*
+ * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
+ * by the fact that they preserve the flags across the division of 5/2.
+ * PII and PPro exhibit this behavior too, but they have cpuid available.
+ */
+/*
+ * Perform the Cyrix 5/2 test. A Cyrix won't change
+ * the flags, while other 486 chips will.
+ */
+static inline int test_cyrix_52div(void)
+{
+       unsigned int test;
+
+       __asm__ __volatile__(
+            "sahf\n\t"         /* clear flags (%eax = 0x0005) */
+            "div %b2\n\t"      /* divide 5 by 2 */
+            "lahf"             /* store flags into %ah */
+            : "=a" (test)
+            : "0" (5), "q" (2)
+            : "cc");
+
+       /* AH is 0x02 on Cyrix after the divide.. */
+       return (unsigned char) (test >> 8) == 0x02;
+}
 
-               case X86_VENDOR_UNKNOWN:
-                       if (c->cpuid_level < 0)
-                       {
-                               /* It may be a nexgen with cpuid disabled.. */
-                               if(deep_magic_nexgen_probe())
-                               {
-                                       strcpy(c->x86_model_id, "Nx586");
-                                       c->x86_vendor = X86_VENDOR_NEXGEN;
-                               }
-                               return;
-                       }
-                       break;
+/* Try to detect a CPU with disabled CPUID, and if so, enable.  This routine
+   may also be used to detect non-CPUID processors and fill in some of
+   the information manually. */
+static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c)
+{
+       /* First of all, decide if this is a 486 or higher */
+       /* It's a 486 if we can modify the AC flag */
+       if ( flag_is_changeable_p(X86_EFLAGS_AC) )
+               c->x86 = 4;
+       else
+               c->x86 = 3;
 
-               case X86_VENDOR_CYRIX:
-                       cyrix_model(c);
-                       return;
+       /* Detect Cyrix with disabled CPUID */
+       if ( c->x86 == 4 && test_cyrix_52div() ) {
+               strcpy(c->x86_vendor_id, "CyrixInstead");
+       }
 
-               case X86_VENDOR_AMD:
-                       if (amd_model(c))
-                               return;
-                       break;
+       /* Detect NexGen with old hypercode */
+       if ( deep_magic_nexgen_probe() ) {
+               strcpy(c->x86_vendor_id, "NexGenDriven");
+       }
 
-               case X86_VENDOR_CENTAUR:
-                       centaur_model(c);
-                       return;
+       return have_cpuid_p();  /* Check to see if CPUID now enabled? */
+}
 
-               case X86_VENDOR_INTEL:
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init identify_cpu(struct cpuinfo_x86 *c)
+{
+       int junk, i;
+       u32 xlvl, tfms;
 
-                       squash_the_stupid_serial_number(c);
-                       mcheck_init();
+       c->loops_per_sec = loops_per_sec;
+       c->x86_cache_size = -1;
+       c->x86_vendor = X86_VENDOR_UNKNOWN;
+       c->cpuid_level = -1;    /* CPUID not detected */
+       c->x86_model = c->x86_mask = 0; /* So far unknown... */
+       c->x86_vendor_id[0] = '\0'; /* Unset */
+       c->x86_model_id[0] = '\0';  /* Unset */
+       memset(&c->x86_capability, 0, sizeof c->x86_capability);
+
+       if ( !have_cpuid_p() && !id_and_try_enable_cpuid(c) ) {
+               /* CPU doesn't have CPUID */
+
+               /* If there are any capabilities, they're vendor-specific */
+               /* enable_cpuid() would have set c->x86 for us. */
+       } else {
+               /* CPU does have CPUID */
+
+               /* Get vendor name */
+               cpuid(0x00000000, &c->cpuid_level,
+                     (int *)&c->x86_vendor_id[0],
+                     (int *)&c->x86_vendor_id[8],
+                     (int *)&c->x86_vendor_id[4]);
+               
+               get_cpu_vendor(c);
+
+               /* Initialize the standard set of capabilities */
+               /* Note that the vendor-specific code below might override */
+
+               /* Intel-defined flags: level 0x00000001 */
+               if ( c->cpuid_level >= 0x00000001 ) {
+                       cpuid(0x00000001, &tfms, &junk, &junk,
+                             &c->x86_capability[0]);
+                       c->x86 = (tfms >> 8) & 15;
+                       c->x86_model = (tfms >> 4) & 15;
+                       c->x86_mask = tfms & 15;
+               } else {
+                       /* Have CPUID level 0 only - unheard of */
+                       c->x86 = 4;
+               }
 
-                       if (c->cpuid_level > 1) {
-                               /* supports eax=2  call */
-                               int edx, dummy;
+               /* AMD-defined flags: level 0x80000001 */
+               xlvl = cpuid_eax(0x80000000);
+               if ( (xlvl & 0xffff0000) == 0x80000000 ) {
+                       if ( xlvl >= 0x80000001 )
+                               c->x86_capability[1] = cpuid_edx(0x80000001);
+                       if ( xlvl >= 0x80000004 )
+                               get_model_name(c); /* Default name */
+               }
 
-                               cpuid(2, &dummy, &dummy, &dummy, &edx);
+               /* Transmeta-defined flags: level 0x80860001 */
+               xlvl = cpuid_eax(0x80860000);
+               if ( (xlvl & 0xffff0000) == 0x80860000 ) {
+                       if (  xlvl >= 0x80860001 )
+                               c->x86_capability[2] = cpuid_edx(0x80860001);
+               }
+       }
 
-                               /* We need only the LSB */
-                               edx &= 0xff;
+       printk("CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n",
+              c->x86_capability[0],
+              c->x86_capability[1],
+              c->x86_capability[2],
+              c->x86_vendor);
 
-                               switch (edx) {
-                               case 0x40:
-                                       c->x86_cache_size = 0;
-                                       break;
+       /*
+        * Vendor-specific initialization.  In this section we
+        * canonicalize the feature flags, meaning if there are
+        * features a certain CPU supports which CPUID doesn't
+        * tell us, CPUID claiming incorrect flags, or other bugs,
+        * we handle them here.
+        *
+        * At the end of this section, c->x86_capability better
+        * indicate the features this CPU genuinely supports!
+        */
+       switch ( c->x86_vendor ) {
+       case X86_VENDOR_UNKNOWN:
+       default:
+               /* Not much we can do here... */
+               break;
 
-                               case 0x41: /* 4-way 128 */
-                                       c->x86_cache_size = 128;
-                                       break;
+       case X86_VENDOR_CYRIX:
+               init_cyrix(c);
+               break;
 
-                               case 0x42: /* 4-way 256 */
-                               case 0x82: /* 8-way 256 */
-                                       c->x86_cache_size = 256;
-                                       break;
+       case X86_VENDOR_AMD:
+               init_amd(c);
+               break;
 
-                               case 0x43: /* 4-way 512 */
-                                       c->x86_cache_size = 512;
-                                       break;
+       case X86_VENDOR_CENTAUR:
+               init_centaur(c);
+               break;
 
-                               case 0x44: /* 4-way 1024 */
-                               case 0x84: /* 8-way 1024 */
-                                       c->x86_cache_size = 1024;
-                                       break;
+       case X86_VENDOR_INTEL:
+               init_intel(c);
+               break;
 
-                               case 0x45: /* 4-way 2048 */
-                               case 0x85: /* 8-way 2048 */
-                                       c->x86_cache_size = 2048;
-                                       break;
+       case X86_VENDOR_NEXGEN:
+               c->x86_cache_size = 256; /* A few had 1 MB... */
+               break;
 
-                               default:
-                                       c->x86_cache_size = 0;
-                                       break;
-                               }
-                       }
+       case X86_VENDOR_TRANSMETA:
+               init_transmeta(c);
+               break;
+       }
+       
+       printk("CPU: After vendor init, caps: %08x %08x %08x %08x\n",
+              c->x86_capability[0],
+              c->x86_capability[1],
+              c->x86_capability[2],
+              c->x86_capability[3]);
 
-                       /* Pentium IV. */
-                       if (c->x86 == 15) {
-                               intel_model(c);
-                               return;
-                       }
+       /*
+        * The vendor-specific functions might have changed features.  Now
+        * we do "generic changes."
+        */
 
-                       /* Names for the Pentium II/Celeron processors 
-                          detectable only by also checking the cache size.
-                          Dixon is NOT a Celeron. */
-                       if (c->x86 == 6) {
-                               switch (c->x86_model) {
-                                       case 5:
-                                               if (c->x86_cache_size == 0)
-                                                       p = "Celeron (Covington)";
-                                               if (c->x86_cache_size == 256)
-                                                       p = "Mobile Pentium II (Dixon)";
-                                               break;
-
-                                       case 6:
-                                               if (c->x86_cache_size == 128)
-                                                       p = "Celeron (Mendocino)";
-                                               break;
-
-                                       case 8:
-                                               if (c->x86_cache_size == 128)
-                                                       p = "Celeron (Coppermine)";
-                                               break;
-                               }
-                       }
-                       if (p!=NULL)
-                               goto name_decoded;
+       /* TSC disabled? */
+#ifdef CONFIG_TSC
+       if ( tsc_disable )
+               clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+#endif
 
-                       break;
+       /* Disable the PN if appropriate */
+       squash_the_stupid_serial_number(c);
 
-               case X86_VENDOR_TRANSMETA:
-                       transmeta_model(c);
-                       squash_the_stupid_serial_number(c);
-                       return;
+       /* If the model name is still unset, do table lookup. */
+       if ( !c->x86_model_id[0] ) {
+               char *p;
+               p = table_lookup_model(c);
+               if ( p )
+                       strcpy(c->x86_model_id, p);
+               else
+                       /* Last resort... */
+                       sprintf(c->x86_model_id, "%02x/%02x",
+                               c->x86_vendor, c->x86_model);
        }
 
-       /* may be changed in the switch so needs to be after */
-       
-       if(c->x86_vendor == X86_VENDOR_NEXGEN)
-               c->x86_cache_size = 256;        /* A few had 1Mb.. */
-
-       for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
-               if (cpu_models[i].vendor == c->x86_vendor &&
-                   cpu_models[i].x86 == c->x86) {
-                       if (c->x86_model <= 16)
-                               p = cpu_models[i].model_names[c->x86_model];
-               }
-       }
+       /* Now the feature flags better reflect actual CPU features! */
 
-name_decoded:
+       printk("CPU: After generic, caps: %08x %08x %08x %08x\n",
+              c->x86_capability[0],
+              c->x86_capability[1],
+              c->x86_capability[2],
+              c->x86_capability[3]);
 
-       if (p) {
-               strcpy(c->x86_model_id, p);
-               return;
+       /*
+        * On SMP, boot_cpu_data holds the common feature set between
+        * all CPUs; so make sure that we indicate which features are
+        * common between the CPUs.  The first time this routine gets
+        * executed, c == &boot_cpu_data.
+        */
+       if ( c != &boot_cpu_data ) {
+               /* AND the already accumulated flags with these */
+               for ( i = 0 ; i < NCAPINTS ; i++ )
+                       boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
        }
 
-       sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model);
+       printk("CPU: Common caps: %08x %08x %08x %08x\n",
+              boot_cpu_data.x86_capability[0],
+              boot_cpu_data.x86_capability[1],
+              boot_cpu_data.x86_capability[2],
+              boot_cpu_data.x86_capability[3]);
 }
-
 /*
  *     Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
  */
@@ -1629,14 +1975,12 @@ void __init dodgy_tsc(void)
 {
        get_cpu_vendor(&boot_cpu_data);
 
-       if(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)
-               return;
-
-       cyrix_model(&boot_cpu_data);
+       if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX )
+               init_cyrix(&boot_cpu_data);
 }
 
 
-
+/* These need to match <asm/processor.h> */
 static char *cpu_vendor_names[] __initdata = {
        "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
 
@@ -1658,7 +2002,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
        else
                printk("%s", c->x86_model_id);
 
-       if (c->x86_mask || c->cpuid_level>=0) 
+       if (c->x86_mask || c->cpuid_level >= 0) 
                printk(" stepping %02x\n", c->x86_mask);
        else
                printk("\n");
@@ -1671,23 +2015,39 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
 int get_cpuinfo(char * buffer)
 {
        char *p = buffer;
-       int sep_bug;
 
        /* 
-        * Flags should be entered into the array ONLY if there is no overlap.
-        * Else a number should be used and then overridden in the case 
-        * statement below. --Jauder <jauderho@carumba.com>
-        *
-        * NOTE: bits 10, 19-22, 26-31 are reserved.
-        *
-        * Data courtesy of http://www.sandpile.org/arch/cpuid.htm
-        * Thanks to the Greasel!
+        * These flag bits must match the definitions in <asm/cpufeature.h>.
+        * NULL means this bit is undefined or reserved; either way it doesn't
+        * have meaning as far as Linux is concerned.  Note that it's important
+        * to realize there is a difference between this table and CPUID -- if
+        * applications want to get the raw CPUID data, they should access
+        * /dev/cpu/<cpu_nr>/cpuid instead.
         */
        static char *x86_cap_flags[] = {
+               /* Intel-defined */
                "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-               "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
-               "16", "pse36", "psn", "19", "20", "21", "22", "mmx",
-               "24", "xmm", "26", "27", "28", "29", "30", "31"
+               "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+               "pat", "pse36", "pn", "clflsh", NULL, "dtes", NULL, "mmx",
+               "fxsr", "sse", "sse2", "selfsnoop", NULL, "acc", "ia64", NULL,
+
+               /* AMD-defined */
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, "mmxext", NULL,
+               NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
+
+               /* Transmeta-defined */
+               "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+               /* Other (Linux-defined) */
+               "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        };
        struct cpuinfo_x86 *c = cpu_data;
        int i, n;
@@ -1714,7 +2074,7 @@ int get_cpuinfo(char * buffer)
                else
                        p += sprintf(p, "stepping\t: unknown\n");
 
-               if (c->x86_capability & X86_FEATURE_TSC) {
+               if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
                        p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n",
                                cpu_khz / 1000, (cpu_khz % 1000));
                }
@@ -1723,65 +2083,19 @@ int get_cpuinfo(char * buffer)
                if (c->x86_cache_size >= 0)
                        p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size);
                
-               /* Modify the capabilities according to chip type */
-               switch (c->x86_vendor) {
-
-                   case X86_VENDOR_CYRIX:
-                               x86_cap_flags[24] = "cxmmx";
-                               break;
-
-                   case X86_VENDOR_AMD:
-                               if (c->x86 == 5 && c->x86_model == 6)
-                                       x86_cap_flags[10] = "sep";
-                               if (c->x86 < 6)
-                                       x86_cap_flags[16] = "fcmov";
-                               else
-                                       x86_cap_flags[16] = "pat";
-                               x86_cap_flags[22] = "mmxext";
-                               x86_cap_flags[24] = "fxsr";
-                               x86_cap_flags[30] = "3dnowext";
-                               x86_cap_flags[31] = "3dnow";
-                               break;
-
-                   case X86_VENDOR_INTEL:
-                               x86_cap_flags[16] = "pat";
-                               x86_cap_flags[18] = "pn";
-                               x86_cap_flags[24] = "fxsr";
-                               x86_cap_flags[25] = "xmm";
-                               break;
-
-                   case X86_VENDOR_CENTAUR:
-                               if (c->x86_model >=8)   /* Only Winchip2 and above */
-                                   x86_cap_flags[31] = "3dnow";
-                               break;
-
-                   default:
-                               /* Unknown CPU manufacturer or no special handling needed */
-                               break;
-               }
-
-               sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
-                         c->x86 == 0x06 &&
-                         c->cpuid_level >= 0 &&
-                         (c->x86_capability & X86_FEATURE_SEP) &&
-                         c->x86_model < 3 &&
-                         c->x86_mask < 3;
-
                /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
-               fpu_exception = c->hard_math && (ignore_irq13 | (c->x86_capability & X86_FEATURE_FPU));
+               fpu_exception = c->hard_math && (ignore_irq13 | test_bit(X86_FEATURE_FPU, &c->x86_capability));
                p += sprintf(p, "fdiv_bug\t: %s\n"
                                "hlt_bug\t\t: %s\n"
-                               "sep_bug\t\t: %s\n"
                                "f00f_bug\t: %s\n"
                                "coma_bug\t: %s\n"
                                "fpu\t\t: %s\n"
                                "fpu_exception\t: %s\n"
                                "cpuid level\t: %d\n"
                                "wp\t\t: %s\n"
-                               "flags\t\t:",
+                               "features\t:",
                             c->fdiv_bug ? "yes" : "no",
                             c->hlt_works_ok ? "no" : "yes",
-                            sep_bug ? "yes" : "no",
                             c->f00f_bug ? "yes" : "no",
                             c->coma_bug ? "yes" : "no",
                             c->hard_math ? "yes" : "no",
@@ -1789,8 +2103,9 @@ int get_cpuinfo(char * buffer)
                             c->cpuid_level,
                             c->wp_works_ok ? "yes" : "no");
 
-               for ( i = 0 ; i < 32 ; i++ )
-                       if ( c->x86_capability & (1 << i) )
+               for ( i = 0 ; i < 32*NCAPINTS ; i++ )
+                       if ( test_bit(i, &c->x86_capability) &&
+                            x86_cap_flags[i] != NULL )
                                p += sprintf(p, " %s", x86_cap_flags[i]);
 
                p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n",
@@ -1800,18 +2115,6 @@ int get_cpuinfo(char * buffer)
        return p - buffer;
 }
 
-#ifndef CONFIG_X86_TSC
-static int tsc_disable __initdata = 0;
-
-static int __init tsc_setup(char *str)
-{
-       tsc_disable = 1;
-       return 1;
-}
-
-__setup("notsc", tsc_setup);
-#endif
-
 static unsigned long cpu_initialized __initdata = 0;
 
 /*
@@ -1836,7 +2139,8 @@ void __init cpu_init (void)
 #ifndef CONFIG_X86_TSC
        if (tsc_disable && cpu_has_tsc) {
                printk("Disabling TSC...\n");
-               boot_cpu_data.x86_capability &= ~X86_FEATURE_TSC;
+               /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
+               clear_bit(&boot_cpu_data.x86_capability, X86_FEATURE_TSC);
                set_in_cr4(X86_CR4_TSD);
        }
 #endif
@@ -1881,3 +2185,11 @@ void __init cpu_init (void)
        current->used_math = 0;
        stts();
 }
+
+/*
+ * Local Variables:
+ * mode:c
+ * c-file-style:"k&r"
+ * c-basic-offset:8
+ * End:
+ */
index 50b99ec22820e9ec64a85dcfe03457783d9865b2..86485ab334260cf76d1541bd081b053287eb861c 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.104 2000/10/04 09:01:38 anton Exp $
+# $Id: config.in,v 1.105 2000/11/12 10:01:41 davem Exp $
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
index a8f5fb9c202b7c812413828187d39dd8d75659e8..85161a3a6c6c70834fa13c877c21bfeab39f7697 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.94 2000/10/19 00:49:51 davem Exp $
+/*  $Id: init.c,v 1.95 2000/11/10 04:49:56 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 72120b563fb719656fe6d12d88a1d017b59b1c54..80c74aa1885ef6c26a11aaa8c0ad9927dd7d61ea 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dtlb_base.S,v 1.7 2000/03/26 09:13:48 davem Exp $
+/* $Id: dtlb_base.S,v 1.8 2000/11/10 08:28:45 davem Exp $
  * dtlb_base.S:        Front end to DTLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -57,7 +57,7 @@
         srax           %g4, VPTE_SHIFT, %g6            ! Create VPTE offset
        ldxa            [%g3 + %g6] ASI_S, %g5          ! Load VPTE
 1:     brlz,pt         %g5, 9f                         ! Valid, load into TLB
-        and            %g5, (_PAGE_PRESENT|_PAGE_READ), %g4    ! Mask readable bits
+        nop                                            ! Delay-slot
        ba,a,pt         %xcc, 4f                        ! Invalid, branch out
 
 /* DTLB ** ICACHE line 2: Quick kernel TLB misses      */
         nop
 9:     stxa            %g5, [%g0] ASI_DTLB_DATA_IN     ! Reload TLB
        retry                                           ! Trap return
-       nop
+4:     rdpr            %pstate, %g5                    ! Move into alternate globals
 
 /* DTLB ** ICACHE line 3: winfixups+real_faults                */
-4:     cmp             %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page?
-       be,pn           %xcc, 5f                        ! Yep, refbit update
-        sllx           %g1, 60, %g4                    ! Get valid bit
-       rdpr            %pstate, %g5                    ! Move into alternate globals
        wrpr            %g5, PSTATE_AG|PSTATE_MG, %pstate
        rdpr            %tl, %g4                        ! See where we came from.
        cmp             %g4, 1                          ! Is etrap/rtrap window fault?
        mov             TLB_TAG_ACCESS, %g4             ! Prepare for fault processing
-
-/* DTLB ** ICACHE line 4: padding              */
        ldxa            [%g4] ASI_DMMU, %g5             ! Load faulting VA page
        be,pt           %xcc, sparc64_realfault_common  ! Jump to normal fault handling
         mov            FAULT_CODE_DTLB, %g4            ! It was read from DTLB
        ba,a,pt         %xcc, winfix_trampoline         ! Call window fixup code
-5:     or              %g5, _PAGE_ACCESSED, %g5        ! Indicate reference
-       or              %g5, %g4, %g5                   ! Set valid
-       stxa            %g5, [%g3 + %g6] ASI_S          ! Update PTE table (cant trap)
-       ba,a,pt         %xcc, 9b                        ! Complete tlb miss
+
+/* DTLB ** ICACHE line 4: Unused...    */
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
 
 #undef TAG_CONTEXT_BITS
 #undef VPTE_SHIFT
index 5e99d5d476107379729fb82c5ab1411d958d8a52..1da370c7c4b0c165c984e6325844e8d946147116 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.20 2000/03/26 09:13:48 davem Exp $
+/* $Id: dtlb_prot.S,v 1.21 2000/11/10 08:28:45 davem Exp $
  * dtlb_prot.S: DTLB protection trap strategy.
  *              This is included directly into the trap table.
  *
@@ -6,10 +6,6 @@
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
-#define TAG_CONTEXT_BITS       0x3ff
-#define VPTE_SHIFT             (PAGE_SHIFT - 3)
-#define MODIFIED_BITS          (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED)
-
 /* Ways we can get here:
  *
  * [TL == 0] 1) User stores to readonly pages.
  */
 
 /* PROT ** ICACHE line 1: User DTLB protection trap    */
-       ldxa            [%g1] ASI_DMMU, %g6             ! Primary or Secondary ctx?
-       and             %g6, 0x10, %g6                  ! Get pri/sec ctx bit
        stxa            %g0, [%g1] ASI_DMMU             ! Clear SFSR FaultValid bit
        membar          #Sync                           ! Synchronize ASI stores
-       ldxa            [%g1 + %g1] ASI_DMMU, %g4       ! Load TAG_ACCESS
-       andn            %g4, TAG_CONTEXT_BITS, %g4      ! Clear CTX bits
-       stxa            %g0, [%g4 + %g6] ASI_DMMU_DEMAP ! Perform TLB flush of page
-       membar          #Sync                           ! Synchronize ASI stores
-
-/* PROT ** ICACHE line 2: Further normal processing    */
-       srax            %g4, VPTE_SHIFT, %g6            ! Compute VPTE offset
-       ldxa            [%g3 + %g6] ASI_S, %g5          ! Load PTE entry
-       andcc           %g5, _PAGE_WRITE, %g0           ! Writable page?
-       be,pt           %xcc, 1f                        ! Nope, real fault
-        or             %g5, (MODIFIED_BITS), %g5       ! Mark as writable/modified
-       stxa            %g5, [%g3 + %g6] ASI_S          ! Update PTE entry
-       stxa            %g5, [%g0] ASI_DTLB_DATA_IN     ! Load PTE into TLB
-       retry                                           ! Trap return
-
-/* PROT ** ICACHE line 3: Real user faults             */
-1:     rdpr            %pstate, %g5                    ! Move into alternate globals
+       rdpr            %pstate, %g5                    ! Move into alternate globals
        wrpr            %g5, PSTATE_AG|PSTATE_MG, %pstate
        rdpr            %tl, %g1                        ! Need to do a winfixup?
        cmp             %g1, 1                          ! Trap level >1?
        mov             TLB_TAG_ACCESS, %g4             ! Prepare reload of vaddr
+       nop
+
+/* PROT ** ICACHE line 2: More real fault processing */
        bgu,pn          %xcc, winfix_trampoline         ! Yes, perform winfixup
         ldxa           [%g4] ASI_DMMU, %g5             ! Put tagaccess in %g5
        ba,pt           %xcc, sparc64_realfault_common  ! Nope, normal fault
-
-/* PROT ** ICACHE line 4: More real fault processing */
         mov            FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
        nop
        nop
        nop
        nop
+
+/* PROT ** ICACHE line 3: Unused...    */
+       nop
+       nop
+       nop
+       nop
+       nop
        nop
        nop
        nop
 
-#undef TAG_CONTEXT_BITS
-#undef VPTE_SHIFT
-#undef MODIFIED_BITS
+/* PROT ** ICACHE line 3: Unused...    */
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
index 7f0da3d141754ae9486b1a1d6c4b4f0e0f087330..bd6a3603dde409c1ca0101a8939e5a7e27c6bd9f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: itlb_base.S,v 1.9 2000/03/26 09:13:48 davem Exp $
+/* $Id: itlb_base.S,v 1.10 2000/11/10 08:28:45 davem Exp $
  * itlb_base.S:        Front end to ITLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
        srax            %g4, VPTE_SHIFT, %g6            ! Create VPTE offset
        ldxa            [%g3 + %g6] ASI_P, %g5          ! Load VPTE
 1:     brgez,pn        %g5, 3f                         ! Not valid, branch out
-        and            %g5, (_PAGE_PRESENT|_PAGE_READ), %g4    ! Mask readable bits
+        nop                                            ! Delay-slot
 2:     stxa            %g5, [%g0] ASI_ITLB_DATA_IN     ! Load PTE into TLB
        retry                                           ! Trap return
-3:     cmp             %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page?
+3:     rdpr            %pstate, %g4                    ! Move into alternate globals
 
-/* ITLB ** ICACHE line 2: Quick user ref updates       */
-       bne,pn          %xcc, 4f                        ! Nope, real missing page
-        sllx           %g1, 60, %g4                    ! Sliiickkk...
-       or              %g5, _PAGE_ACCESSED, %g5        ! Mark as touched
-       or              %g5, %g4, %g5                   ! Allow user to see it
-       ba,pt           %xcc, 2b                        ! Branch to load TLB
-        stxa           %g5, [%g3 + %g6] ASI_S          ! Update PTE table
-4:     rdpr            %pstate, %g4                    ! Move into alternate globals
+/* ITLB ** ICACHE line 2: Real faults                  */
        wrpr            %g4, PSTATE_AG|PSTATE_MG, %pstate
-
-/* ITLB ** ICACHE line 3: Real faults                  */
        rdpr            %tpc, %g5                       ! And load faulting VA
        mov             FAULT_CODE_ITLB, %g4            ! It was read from ITLB
 sparc64_realfault_common:                              ! Called by TL0 dtlb_miss too
@@ -46,10 +37,11 @@ sparc64_realfault_common:                           ! Called by TL0 dtlb_miss too
        stx             %g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
        ba,pt           %xcc, etrap                     ! Save state
 1:      rd             %pc, %g7                        ! ...
+       nop
+
+/* ITLB ** ICACHE line 3: Finish faults + window fixups        */
        call            do_sparc64_fault                ! Call fault handler
         add            %sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
-
-/* ITLB ** ICACHE line 4: Finish faults + window fixups        */
        ba,pt           %xcc, rtrap_clr_l6              ! Restore cpu state
         nop
 winfix_trampoline:
@@ -57,6 +49,14 @@ winfix_trampoline:
        or              %g3, 0x7c, %g3                  ! Compute offset to branch
        wrpr            %g3, %tnpc                      ! Write it into TNPC
        done                                            ! Do it to it
+
+/* ITLB ** ICACHE line 4: Unused...    */
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
        nop
        nop
 
index 71676e05ddfaa92c54c8d9545ff8920927b28b2a..9b211d86d338584f88eec1d624208f9dbed48a97 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.165 2000/10/10 04:47:31 davem Exp $
+/* $Id: sys_sparc32.c,v 1.166 2000/11/10 04:49:56 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
index e4d709cb02ed6d519dd45722786464068efb672c..8b6d71237fd988d34bd64b05826ce65f895f57c1 100644 (file)
@@ -271,24 +271,8 @@ static struct atmdev_ops atm_ops =
    proc_read:  ns_proc_read
 };
 static struct timer_list ns_timer;
-static char *mac[NS_MAX_CARDS] = { NULL
-#if NS_MAX_CARDS > 1
-                                 , NULL
-#endif /* NS_MAX_CARDS > 1 */
-#if NS_MAX_CARDS > 2
-                                 , NULL
-#endif /* NS_MAX_CARDS > 2 */
-#if NS_MAX_CARDS > 3
-                                 , NULL
-#endif /* NS_MAX_CARDS > 3 */
-#if NS_MAX_CARDS > 4
-                                 , NULL
-#endif /* NS_MAX_CARDS > 4 */
-                                        };
-
-#ifdef MODULE
+static char *mac[NS_MAX_CARDS];
 MODULE_PARM(mac, "1-" __MODULE_STRING(NS_MAX_CARDS) "s");
-#endif /* MODULE */
 
 
 /* Functions*******************************************************************/
index 7e01a75c5b38d1a34210499d89051281dc7d3aaf..fbfde6329561a886da78b5a40f969c8fe2c92f16 100644 (file)
@@ -683,7 +683,7 @@ static int __make_request(request_queue_t * q, int rw,
 {
        unsigned int sector, count;
        int max_segments = MAX_SEGMENTS;
-       struct request * req = NULL;
+       struct request * req = NULL, *freereq = NULL;
        int rw_ahead, max_sectors, el_ret;
        struct list_head *head = &q->queue_head;
        int latency;
@@ -733,6 +733,7 @@ static int __make_request(request_queue_t * q, int rw,
         * Now we acquire the request spinlock, we have to be mega careful
         * not to schedule or do something nonatomic
         */
+again:
        spin_lock_irq(&io_request_lock);
 
        /*
@@ -791,19 +792,16 @@ static int __make_request(request_queue_t * q, int rw,
         * are not crucial.
         */
 get_rq:
-       if ((req = get_request(q, rw)) == NULL) {
+       if (freereq) {
+               req = freereq;
+               freereq = NULL;
+       } else if ((req = get_request(q, rw)) == NULL) {
                spin_unlock_irq(&io_request_lock);
                if (rw_ahead)
                        goto end_io;
 
-               req = __get_request_wait(q, rw);
-               spin_lock_irq(&io_request_lock);
-               
-               if (q->head_active) {
-                       head = &q->queue_head;
-                       if (!q->plugged)
-                               head = head->next;
-               }
+               freereq = __get_request_wait(q, rw);
+               goto again;
        }
 
 /* fill up the request-info, and add it to the queue */
@@ -824,6 +822,8 @@ get_rq:
 out:
        if (!q->plugged)
                (q->request_fn)(q);
+       if (freereq)
+               blkdev_release_request(freereq);
        spin_unlock_irq(&io_request_lock);
        return 0;
 end_io:
@@ -1059,7 +1059,7 @@ int __init blk_dev_init(void)
 #endif
 #ifdef CONFIG_ISP16_CDI
        isp16_init();
-#endif CONFIG_ISP16_CDI
+#endif
 #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
        ide_init();             /* this MUST precede hd_init */
 #endif
@@ -1099,37 +1099,37 @@ int __init blk_dev_init(void)
 #endif
 #ifdef CONFIG_CDU31A
        cdu31a_init();
-#endif CONFIG_CDU31A
+#endif
 #ifdef CONFIG_ATARI_ACSI
        acsi_init();
-#endif CONFIG_ATARI_ACSI
+#endif
 #ifdef CONFIG_MCD
        mcd_init();
-#endif CONFIG_MCD
+#endif
 #ifdef CONFIG_MCDX
        mcdx_init();
-#endif CONFIG_MCDX
+#endif
 #ifdef CONFIG_SBPCD
        sbpcd_init();
-#endif CONFIG_SBPCD
+#endif
 #ifdef CONFIG_AZTCD
        aztcd_init();
-#endif CONFIG_AZTCD
+#endif
 #ifdef CONFIG_CDU535
        sony535_init();
-#endif CONFIG_CDU535
+#endif
 #ifdef CONFIG_GSCD
        gscd_init();
-#endif CONFIG_GSCD
+#endif
 #ifdef CONFIG_CM206
        cm206_init();
 #endif
 #ifdef CONFIG_OPTCD
        optcd_init();
-#endif CONFIG_OPTCD
+#endif
 #ifdef CONFIG_SJCD
        sjcd_init();
-#endif CONFIG_SJCD
+#endif
 #ifdef CONFIG_APBLOCK
        ap_init();
 #endif
@@ -1150,7 +1150,7 @@ int __init blk_dev_init(void)
 #endif
 #ifdef CONFIG_BLK_DEV_LVM
        lvm_init();
-#endif 
+#endif
        return 0;
 };
 
index 0d2b834b92ef25a914dadc68caa19544d9a6ec0e..cf9a9f5d9a479a627c17cb0355f4fc6b63f9997a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.6 2000/08/10 05:26:23 davem Exp $
+/* $Id: ffb_drv.c,v 1.7 2000/11/12 10:01:41 davem Exp $
  * ffb_drv.c: Creator/Creator3D direct rendering driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
index 78617055e12b8880ae04997a589d33e257348d64..e41b4e5622c2d3e285496bca26fdeb446fb0cfb7 100644 (file)
  *  best to be responsive.  -- REW
  * */
 
+#include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/mm.h>
+#include <linux/generic_serial.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/generic_serial.h>
 
 #define DEBUG 
 
 static char *                  tmp_buf; 
 static DECLARE_MUTEX(tmp_buf_sem);
 
-int gs_debug;
+static int gs_debug;
 
 
 #ifdef DEBUG
@@ -57,30 +57,7 @@ int gs_debug;
 
 #define RS_EVENT_WRITE_WAKEUP  1
 
-#ifdef MODULE
 MODULE_PARM(gs_debug, "i");
-#endif
-
-#ifdef DEBUG
-static void my_hd (unsigned char *addr, int len)
-{
-       int i, j, ch;
-
-       for (i=0;i<len;i+=16) {
-               printk ("%08x ", (int) addr+i);
-               for (j=0;j<16;j++) {
-                       printk ("%02x %s", addr[j+i], (j==7)?" ":"");
-               }
-               for (j=0;j<16;j++) {
-                       ch = addr[j+i];
-                       printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
-               }
-               printk ("\n");
-       }
-}
-#else
-#define my_hd(addr,len) 
-#endif
 
 
 void gs_put_char(struct tty_struct * tty, unsigned char ch)
@@ -1083,15 +1060,21 @@ void gs_getserial(struct gs_port *port, struct serial_struct *sp)
        copy_to_user(sp, &sio, sizeof(struct serial_struct));
 }
 
-
-#ifdef MODULE
-int init_module (void)
-{
-  return 0;
-}
-
-int cleanup_module (void)
-{
-  return 0;
-}
-#endif
+EXPORT_SYMBOL(gs_put_char);
+EXPORT_SYMBOL(gs_write);
+EXPORT_SYMBOL(gs_write_room);
+EXPORT_SYMBOL(gs_chars_in_buffer);
+EXPORT_SYMBOL(gs_flush_buffer);
+EXPORT_SYMBOL(gs_flush_chars);
+EXPORT_SYMBOL(gs_stop);
+EXPORT_SYMBOL(gs_start);
+EXPORT_SYMBOL(gs_hangup);
+EXPORT_SYMBOL(gs_do_softint);
+EXPORT_SYMBOL(block_til_ready);
+EXPORT_SYMBOL(gs_close);
+EXPORT_SYMBOL(gs_set_termios);
+EXPORT_SYMBOL(gs_init_port);
+EXPORT_SYMBOL(gs_setserial);
+EXPORT_SYMBOL(gs_getserial);
+
+EXPORT_SYMBOL(gs_debug);
index 6514bef9b12ad47f4a4aacddc8ab882f8cc08766..dbd46fb7e77483e61f8f6d4f2c3a4cf1828c3cac 100644 (file)
 #include <linux/gameport.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
 
 /*
  * Option parsing.
  */
 
-MODULE_PARM(js,"1-16s");
-
 #define ANALOG_PORTS           16
 
 static char *js[ANALOG_PORTS];
 static int analog_options[ANALOG_PORTS];
+MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
+MODULE_PARM_DESC(js, "Analog joystick options");
 
 /*
  * Times, feature definitions.
index cd842e86fd72d1ef80f6f51dd4058aafd0dbca0b..c9d230187f12000b0a4ab51d8a0af29d74d1f986 100644 (file)
@@ -179,8 +179,11 @@ static inline int noncached_address(unsigned long addr)
         * caching for the high addresses through the KEN pin, but
         * we maintain the tradition of paranoia in this code.
         */
-       return !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR)
-               && addr >= __pa(high_memory);
+       return !( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ||
+                 test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ||
+                 test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ||
+                 test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) )
+         && addr >= __pa(high_memory);
 #else
        return addr >= __pa(high_memory);
 #endif
index 1681ac603339b0052e00cf4fcc371e5879150525..2ab0563c20e6b9864946268fc4475357fb300cea 100644 (file)
 #define CI104J_ASIC_ID  5
 
 enum {
-       MXSER_BOARD_C168_ISA = 1,
+       MXSER_BOARD_C168_ISA = 0,
        MXSER_BOARD_C104_ISA,
        MXSER_BOARD_CI104J,
        MXSER_BOARD_C168_PCI,
index bf1242e3514de57730e42344aaa36c2150140479..bbd5aff21e3a92fe987320ab31fa86c10d0670ac 100644 (file)
@@ -710,7 +710,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
        int             entropy = 0;
 
 #if defined (__i386__)
-       if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+       if ( test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability) ) {
                __u32 high;
                __asm__(".byte 0x0f,0x31"
                        :"=a" (time), "=d" (high));
index 570ba04fab72828e3a74bc5d846bc9de7f84e1ab..66b7dfd493aabecd68cc6f0cdf9ecadc4114aa92 100644 (file)
@@ -965,8 +965,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
        slot = lp->ppp_slot;
        if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
                printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
-               kfree_skb(skb);
-               return;
+               goto drop_packet;
        }
        is = ippp_table[slot];
        
@@ -974,14 +973,11 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
                if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
                        printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
-                       kfree_skb(skb);
-                       return;
+                       goto drop_packet;
                }
        }
        mis = ippp_table[slot];
-       if (mis != is) {
-               printk(KERN_WARNING __FUNCTION__ ": BUG: is != mis %d %d %p %p\n", slot, lp->ppp_slot, mis, is);
-       }
+
        if (is->debug & 0x10) {
                printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
                isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
@@ -995,15 +991,11 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                case PPP_IPX:  /* untested */
                        if (is->debug & 0x20)
                                printk(KERN_DEBUG "isdn_ppp: IPX\n");
-                       skb->dev = dev;
-                       skb->mac.raw = skb->data;
                        skb->protocol = htons(ETH_P_IPX);
                        break;
                case PPP_IP:
                        if (is->debug & 0x20)
                                printk(KERN_DEBUG "isdn_ppp: IP\n");
-                       skb->dev = dev;
-                       skb->mac.raw = skb->data;
                        skb->protocol = htons(ETH_P_IP);
                        break;
 #ifdef CONFIG_ISDN_PPP_VJ
@@ -1012,10 +1004,10 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                                printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
                        if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
                                printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
-                               net_dev->local->stats.rx_dropped++;
-                               kfree_skb(skb);
-                               return;
+                               goto drop_packet;
                        }
+                       skb->protocol = htons(ETH_P_IP);
+                       break;
                case PPP_VJC_COMP:
                        if (is->debug & 0x20)
                                printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
@@ -1026,22 +1018,17 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
 
                                if (!skb) {
                                        printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-                                       net_dev->local->stats.rx_dropped++;
-                                       kfree_skb(skb_old);
-                                       return;
+                                       skb = skb_old;
+                                       goto drop_packet;
                                }
-                               skb->dev = dev;
                                skb_put(skb, skb_old->len + 128);
                                memcpy(skb->data, skb_old->data, skb_old->len);
-                               skb->mac.raw = skb->data;
                                pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
                                                skb->data, skb_old->len);
                                kfree_skb(skb_old);
-                               if (pkt_len < 0) {
-                                       kfree_skb(skb);
-                                       lp->stats.rx_dropped++;
-                                       return;
-                               }
+                               if (pkt_len < 0)
+                                       goto drop_packet;
+
                                skb_trim(skb, pkt_len);
                                skb->protocol = htons(ETH_P_IP);
                        }
@@ -1058,16 +1045,22 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                        /* fall through */
                default:
                        isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);     /* push data to pppd device */
-                       dev_kfree_skb(skb);
+                       kfree_skb(skb);
                        return;
        }
 
        /* Reset hangup-timer */
        lp->huptimer = 0;
-       netif_rx(skb);
-       /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
 
+       skb->dev = dev;
+       skb->mac.raw = skb->data;
+       netif_rx(skb);
+       /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
        return;
+
+ drop_packet:
+       net_dev->local->stats.rx_dropped++;
+       kfree_skb(skb);
 }
 
 /*
index ad57901b7114f685fd863ba820d8cea6b427602d..0915515972c55df8853b049baf10a2d5846f1a23 100644 (file)
@@ -30,8 +30,8 @@
 
 #include <linux/module.h>
 #include <linux/config.h>
-#include <linux/sysctl.h>
 #include <linux/raid/md.h>
+#include <linux/sysctl.h>
 #include <linux/raid/xor.h>
 #include <linux/devfs_fs_kernel.h>
 
index fac6990c422c48faec81e23ae918cbc0632a164a..6bd9d7d15a424958fd3ab6385a6b3828a8960d97 100644 (file)
@@ -39,8 +39,8 @@ zoran-objs      :=    zr36120.o zr36120_i2c.o zr36120_mem.o
 obj-$(CONFIG_VIDEO_DEV) += videodev.o
 
 obj-$(CONFIG_BUS_I2C) += i2c-old.o
-obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \
-       tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o tuner.o
+obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
+       tda7432.o tda9875.o tuner.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o 
index 23d1b125959cfa08a60386f720d75613b60c1e44..dec29511af42ba407607413da251fa6e8e4433d8 100644 (file)
 /* select from TV,radio,extern,MUTE */
 #define AUDC_SET_INPUT        _IOW('m',17,int)
 
+/* audio inputs */
+#define AUDIO_TUNER        0x00
+#define AUDIO_RADIO        0x01
+#define AUDIO_EXTERN       0x02
+#define AUDIO_INTERN       0x03
+#define AUDIO_OFF          0x04 
+#define AUDIO_ON           0x05
+#define AUDIO_MUTE         0x80
+#define AUDIO_UNMUTE       0x81
+
 /* all the stuff below is obsolete and just here for reference.  I'll
  * remove it once the driver is tested and works fine.
  *
index b2c26e35bd33cb73f32e66df76d439523b7530b5..11c6474c79d76598747323b211bf998033a02ce7 100644 (file)
@@ -1,7 +1,6 @@
 /*
     bttv-cards.c  --  this file has card-specific stuff
 
-
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
 #include <linux/module.h>
 #include <linux/kmod.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 
 #include <asm/io.h>
 
-#include "bttv.h"
+#include "bttvp.h"
 #include "tuner.h"
 
 /* fwd decl */
 static void hauppauge_eeprom(struct bttv *btv);
-static void hauppauge_boot_msp34xx(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
+#if 0
 static void init_tea5757(struct bttv *btv);
+#endif
+
+static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
+static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
+                                   int set);
+static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
+static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
 
 MODULE_PARM(card,"1-4i");
+MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
 MODULE_PARM(pll,"1-4i");
+MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
 MODULE_PARM(autoload,"i");
+MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
 
 static unsigned int card[4] = { -1, -1, -1, -1 };
 static unsigned int pll[4]  = { -1, -1, -1, -1 };
@@ -55,6 +65,14 @@ static unsigned int autoload = 1;
 static unsigned int autoload = 0;
 #endif
 
+MODULE_PARM(gpiomask,"i");
+MODULE_PARM(audioall,"i");
+MODULE_PARM(audiomux,"1-5i");
+static unsigned int gpiomask = -1;
+static unsigned int audioall = -1;
+static unsigned int audiomux[5] = { -1, -1, -1, -1, -1 };
+
+
 /* ----------------------------------------------------------------------- */
 /* list of card IDs for bt878+ cards                                       */
 
@@ -66,8 +84,9 @@ static struct CARD {
        { 0x00011002, BTTV_HAUPPAUGE878,  "ATI TV Wonder" },
        { 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
        { 0x00021461, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
+       { 0x00031002, BTTV_HAUPPAUGE878,  "ATI TV Wonder/VE" },
        { 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-       { 0x00041461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
+       { 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
        { 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
        { 0x1118153b, BTTV_TERRATVALUE,   "Terratec TV Value" },
        { 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV/Radio+" },
@@ -77,12 +96,17 @@ static struct CARD {
        { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
        { 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
        { 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
+       { 0x3000121a, 0/* no entry yet */,"VoodooTV 200" },
        { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" },
        { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
        { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
        { 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master" },
+       { 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
        { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
-       { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" },
+       { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+       { 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
+       { 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
+       { 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
 #if 0 /* probably wrong */
        { 0x14610002, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
        { 0x6606217d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
@@ -93,286 +117,694 @@ static struct CARD {
 /* ----------------------------------------------------------------------- */
 /* array with description for bt848 / bt878 tv/grabber cards               */
 
-struct tvcard bttv_tvcards[] = 
+struct tvcard bttv_tvcards[] = {
 {
-       /* 0x00 */
-        { " *** UNKNOWN *** ",
-          3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "MIRO PCTV",
-          4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "Hauppauge old",
-          4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,0,1,0,0,0,1,  PLL_NONE, -1 },
-        { "STB",
-          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
-         0,1,1,1,1,0,0,1,  PLL_NONE, -1 },
-
-        { "Intel",
-          3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-       { "Diamond DTV2000",
-          3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-       { "AVerMedia TVPhone",
-          3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_28, -1 },
-        { "MATRIX-Vision MV-Delta",
-          5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-
-       /* 0x08 */
-        { "Fly Video II",
-          3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},
-         { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "TurboTV",
-          3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "Hauppauge new (bt878)",
-         4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,0,1,0,0,0,1,  PLL_28,   -1 },
-        { "MIRO PCTV pro",
-         3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0,
-       /* 3, 1, 0, 2, 0x3004F, { 2, 3, 1, 1}, {1, 0x10011, 5, 0,10}, 0x3004F, */
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-
-       { "ADS Technologies Channel Surfer TV",
-         3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "AVerMedia TVCapture 98",
-         3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
-        { "Aimslab VHX",
-          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "Zoltrix TV-Max",
-          3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-
-       /* 0x10 */
-        { "Pixelview PlayTV (bt878)",
-          3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1},
-         { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0,
-         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
-        { "Leadtek WinView 601",
-          3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0},
-         { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "AVEC Intercapture",
-         3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-       { "LifeView FlyKit w/o Tuner",
-         3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0,
-         0,0,0,0,0,0,0,1,  PLL_NONE, -1 },
-
-        { "CEI Raffles Card",
-         3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-       { "Lucky Star Image World ConferenceTV",
-         3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0,
-         1,1,1,1,0,0,0,1,  PLL_28,   TUNER_PHILIPS_PAL_I },
-       { "Phoebe Tv Master + FM",
-         3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "Modular Technology MM205 PCTV, bt878",
-         2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-
-       /* 0x18 */
-        { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
-         3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
-        { "Terratec/Vobis TV-Boostar",
-          3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "Newer Hauppauge WinCam (bt878)",
-         4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "MAXI TV Video PCI2",
-          3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, TUNER_PHILIPS_SECAM },
-
-        { "Terratec TerraTV+",
-          3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, 
-          { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "Imagenation PXC200",
-          5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "FlyVideo 98",
-          3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, 
-          { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-        { "iProTV",
-         3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-
-       /* 0x20 */
-       { "Intel Create and Share PCI",
-         4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-       { "Terratec TerraTValue",
-         3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1},
-         { 0x500, 0, 0x300, 0x900, 0x900},0,
-         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
-       { "Leadtek WinFast 2000",
-         3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0},
-         { 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},0,
-         1,1,1,1,1,0,0,1,  PLL_28,   -1 },
-       { "Chronos Video Shuttle II",
-         3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0,
-         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
-
-       { "Typhoon TView TV/FM Tuner",
-         3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0,
-         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
-       { "PixelView PlayTV pro",
-          3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },
-          { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0,
-         0,0,0,0,0,0,0,1,  PLL_28,   -1 },
-       { "TView99 CPH063",
-         3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1},
-         { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0,
-         1,1,1,1,0,0,0,1,  PLL_28, -1 },
-       { "Pinnacle PCTV Rave",
-         3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0,
-         1,1,1,1,0,0,0,1,  PLL_28, -1 },
-
-        /* 0x28 */
-        { "STB2",
-          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
-         0,1,1,1,0,1,1,1,  PLL_NONE, -1 },
-        { "AVerMedia TVPhone 98",
-         3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
-         1,1,1,1,0,0,0,1,  PLL_28,   5 },
-        { "ProVideo PV951", /* pic16c54 */
-          3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
-         0,0,0,0,0,0,0,0,  PLL_28,   1 },
-       { "Little OnAir TV",
-         3, 1, 0, 2, 0xe00b, {2, 3, 1, 1},
-         {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0,
-         0,0,0,0,0,0,0,0, PLL_NONE, -1 },
-
-       { "Sigma TVII-FM",
-         2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0,
-         0,0,0,0,0,0,0,0, PLL_NONE, -1 },      
-       { "MATRIX-Vision MV-Delta 2",
-         5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0,
-         0,0,0,0,0,0,0,0,  PLL_28, -1 },
-       { "Zoltrix Genie TV",
-         3, 1, 0, 2, 0xbcf03f, { 2, 3, 1, 1},
-         { 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f}, 0,
-         0,0,0,0,0,0,0,0,  PLL_28, 5 },
-       { "Terratec TV/Radio+", /* Radio ?? */
-         3, 1, 0, 2, 0x1f0000, { 2, 3, 1, 1},
-         { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },0,
-         0,0,0,0,0,0,0,0,  PLL_35,  1 },
-
-       /* 0x30 */
-       { "Dynalink Magic TView ",
-         3, 1, 0, 2, 15, { 2, 3, 1, 1}, {2,0,0,0,1},0,
-         1,1,1,1,0,0,0,1,  PLL_28,  -1 },
-};
+/* ---- card 0x00 ---------------------------------- */
+       name:           " *** UNKNOWN *** ",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       muxsel:         { 2, 3, 1, 0},
+       tuner_type:     -1,
+},{
+       name:           "MIRO PCTV",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       15,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 2, 0, 0, 0, 10},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Hauppauge old",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       7,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 1, 2, 3, 4},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "STB",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       7,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 4, 0, 2, 3, 1},
+       no_msp34xx:     1,
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x04 ---------------------------------- */
+       name:           "Intel",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           -1,
+       gpiomask:       7,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 1, 2, 3, 4},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Diamond DTV2000",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       3,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 1, 0, 1, 3},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "AVerMedia TVPhone",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           3,
+       gpiomask:       15,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       {12, 4,11,11, 0},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "MATRIX-Vision MV-Delta",
+       video_inputs:   5,
+       audio_inputs:   1,
+       tuner:          -1,
+       svhs:           3,
+       gpiomask:       0,
+       muxsel:         { 2, 3, 1, 0, 0},
+       audiomux:       {0 },
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x08 ---------------------------------- */
+       name:           "Fly Video II",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xc00,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "TurboTV",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       3,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 1, 1, 2, 3, 0},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Hauppauge new (bt878)",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       7,
+       muxsel:         { 2, 0, 1, 1},
+       audiomux:       { 0, 1, 2, 3, 4},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "MIRO PCTV pro",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       65551,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       {1,65537, 0, 0,10},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x0c ---------------------------------- */
+       name:           "ADS Technologies Channel Surfer TV",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       15,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 13, 14, 11, 7, 0, 0},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "AVerMedia TVCapture 98",
+       video_inputs:   3,
+       audio_inputs:   4,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       15,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 13, 14, 11, 7, 0, 0},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     5,
+},{
+       name:           "Aimslab VHX",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       7,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 1, 2, 3, 4},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Zoltrix TV-Max",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       15,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       {0 , 0, 1 , 0, 10},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x10 ---------------------------------- */
+       name:           "Pixelview PlayTV (bt878)",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x01fe00,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "Leadtek WinView 601",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x8300f8,
+       muxsel:         { 2, 3, 1, 1,0},
+       audiomux:       { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+       audio_hook:     winview_audio,
+},{
+       name:           "AVEC Intercapture",
+       video_inputs:   3,
+       audio_inputs:   2,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0,
+       muxsel:         {2, 3, 1, 1},
+       audiomux:       {1, 0, 0, 0, 0},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "LifeView FlyKit w/o Tuner",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          -1,
+       svhs:           -1,
+       gpiomask:       0x8dff00,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0 },
+       no_msp34xx:     1,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x14 ---------------------------------- */
+       name:           "CEI Raffles Card",
+       video_inputs:   3,
+       audio_inputs:   3,
+       tuner:          0,
+       svhs:           2,
+       muxsel:         {2, 3, 1, 1},
+       tuner_type:     -1,
+},{
+       name:           "Lucky Star Image World ConferenceTV",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x00fffe07,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 131072, 1, 1638400, 3, 4},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     TUNER_PHILIPS_PAL_I,
+},{
+       name:           "Phoebe Tv Master + FM",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xc00,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       {0, 1, 0x800, 0x400, 0xc00, 0},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Modular Technology MM205 PCTV, bt878",
+       video_inputs:   2,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           -1,
+       gpiomask:       7,
+       muxsel:         { 2, 3 },
+       audiomux:       { 0, 0, 0, 0, 0 },
+       no_msp34xx:     1,
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x18 ---------------------------------- */
+       name:           "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xe00,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       {0x400, 0x400, 0x400, 0x400, 0},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "Terratec/Vobis TV-Boostar",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       16777215,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 131072, 1, 1638400, 3,4},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Newer Hauppauge WinCam (bt878)",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           3,
+       gpiomask:       7,
+       muxsel:         { 2, 0, 1, 1},
+       audiomux:       { 0, 1, 2, 3, 4},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "MAXI TV Video PCI2",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xffff,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 1, 2, 3, 0xc00},
+       needs_tvaudio:  1,
+       tuner_type:     TUNER_PHILIPS_SECAM,
+},{
+
+/* ---- card 0x1c ---------------------------------- */
+       name:           "Terratec TerraTV+",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x70000,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+       audio_hook:     terratv_audio,
+},{
+       name:           "Imagenation PXC200",
+       video_inputs:   5,
+       audio_inputs:   1,
+       tuner:          -1,
+       svhs:           4,
+       gpiomask:       0,
+       muxsel:         { 2, 3, 1, 0, 0},
+       audiomux:       { 0 },
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "FlyVideo 98",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x8dfe00,
+       muxsel:         {2, 3, 1, 1},
+       audiomux:       { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "iProTV",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       1,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 1, 0, 0, 0, 0 },
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x20 ---------------------------------- */
+       name:           "Intel Create and Share PCI",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       7,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 4, 4, 4, 4, 4},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Terratec TerraTValue",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xffff00,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0x500, 0, 0x300, 0x900, 0x900},
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "Leadtek WinFast 2000",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xfff000,
+       muxsel:         { 2, 3, 1, 1,0},
+       audiomux:       { 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "Chronos Video Shuttle II",
+       video_inputs:   3,
+       audio_inputs:   3,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x1800,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 0, 0x1000, 0x1000, 0x0800},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x24 ---------------------------------- */
+       name:           "Typhoon TView TV/FM Tuner",
+       video_inputs:   3,
+       audio_inputs:   3,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x1800,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 0x800, 0, 0, 0x1800, 0 },
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "PixelView PlayTV pro",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xff,
+       muxsel:         { 2, 3, 1, 1 },
+       audiomux:       { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+       no_msp34xx:     1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "TView99 CPH063",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x551e00,
+       muxsel:         { 2, 3, 1, 0},
+       audiomux:       { 0x551400, 0x551200, 0, 0, 0, 0x551200 },
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "Pinnacle PCTV Rave",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x03000F,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 2, 0, 0, 0, 1},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x28 ---------------------------------- */
+       name:           "STB2",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       7,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 4, 0, 2, 3, 1},
+       no_msp34xx:     1,
+       needs_tvaudio:  1,
+       tuner_type:     -1,
+},{
+       name:           "AVerMedia TVPhone 98",
+       video_inputs:   3,
+       audio_inputs:   4,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       4,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 13, 14, 11, 7, 0, 0},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     5,
+       audio_hook:     avermedia_tvphone_audio,
+},{
+       name:           "ProVideo PV951", /* pic16c54 */
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0, 0, 0, 0, 0},
+       no_msp34xx:     1,
+       pll:            PLL_28,
+       tuner_type:     1,
+},{
+       name:           "Little OnAir TV",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xe00b,
+       muxsel:         {2, 3, 1, 1},
+       audiomux:       {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
+       no_msp34xx:     1,
+       tuner_type:     -1,
+},{
+
+/* ---- card 0x2c ---------------------------------- */
+       name:           "Sigma TVII-FM",
+       video_inputs:   2,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           -1,
+       gpiomask:       3,
+       muxsel:         {2, 3, 1, 1},
+       audiomux:       {1, 1, 0, 2, 3},
+       no_msp34xx:     1,
+       pll:            PLL_NONE,
+       tuner_type:     -1,
+},{
+       name:           "MATRIX-Vision MV-Delta 2",
+       video_inputs:   5,
+       audio_inputs:   1,
+       tuner:          -1,
+       svhs:           3,
+       gpiomask:       0,
+       muxsel:         { 2, 3, 1, 0, 0},
+       audiomux:       {0 },
+       no_msp34xx:     1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "Zoltrix Genie TV",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xbcf03f,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f},
+       no_msp34xx:     1,
+       pll:            PLL_28,
+       tuner_type:     5,
+},{
+       name:           "Terratec TV/Radio+",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x1f0000,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },
+       no_msp34xx:     1,
+       pll:            PLL_35,
+       tuner_type:     1,
+},{
+
+/* ---- card 0x30 ---------------------------------- */
+       name:           "Dynalink Magic TView ",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       15,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       {2,0,0,0,1},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "GV-BCTV3",
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x010f00,
+       muxsel:         {2, 3, 0, 0},
+       audiomux:       {0x10000, 0, 0x10000, 0, 0, 0},
+       no_msp34xx:     1,
+       pll:            PLL_28,
+       tuner_type:     TUNER_ALPS_TSHC6_NTSC,
+       audio_hook:     gvbctv3pci_audio,
+},{
+       name:           "Prolink PV-BT878P+4E (PixelView PlayTV PAK)",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xAA0000,
+       muxsel:         { 2,3,1,1 },
+       audiomux:       { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
+       no_msp34xx:     1,
+       pll:            PLL_28,
+       tuner_type:     TUNER_PHILIPS_PAL_I,
+},{
+       name:           "Eagle Wireless Capricorn2 (bt878A)",
+       video_inputs:   4,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       7,
+       muxsel:         { 2, 0, 1, 1},
+       audiomux:       { 0, 1, 2, 3, 4},
+       pll:            PLL_28,
+       tuner_type:     -1 /* TUNER_ALPS_TMDH2_NTSC */,
+},{
+
+/* ---- card 0x34 ---------------------------------- */
+       name:           "Pinnacle Studio PCTV Pro", /* David Härdeman <david@2gen.com> */
+       video_inputs:   3,
+       audio_inputs:   1,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0x03000F,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 1, 65537, 0, 0, 10},
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     -1,
+},{
+       name:           "Typhoon TView RDS", /* Claas Langbehn <claas@bigfoot.com> */
+       video_inputs:   3,
+       audio_inputs:   3,
+       tuner:          0,
+       svhs:           2,
+       gpiomask:       0xffff,
+       muxsel:         { 2, 3, 1, 1},
+       audiomux:       { 0xb002, 0, 0x12, 0x12, 0x3007 },
+       needs_tvaudio:  1,
+       pll:            PLL_28,
+       tuner_type:     TUNER_PHILIPS_PAL_I,
+}};
+
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
 
 /* ----------------------------------------------------------------------- */
 
 static unsigned char eeprom_data[256];
 
-static void __devinit bttv_dump_eeprom(struct bttv *btv,int addr)
-{
-       int i;
-
-       if (bttv_verbose < 2)
-               return;
-       /* for debugging: dump eeprom to syslog */
-       printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr);
-       for (i = 0; i < 256;) {
-               printk(KERN_DEBUG "  %02x:",i);
-               do {
-                       printk(" %02x",eeprom_data[i++]);
-               } while (i % 16);
-               printk("\n");
-       }
-}
-
-static int __devinit bttv_idcard_eeprom(struct bttv *btv)
-{
-       unsigned id;
-       int i,n;
-
-       id = (eeprom_data[252] << 24) |
-               (eeprom_data[253] << 16) |
-               (eeprom_data[254] << 8)  |
-               (eeprom_data[255]);
-       if (id == 0 || id == 0xffffffff)
-           return -1;
-
-       /* look for the card */
-       btv->cardid = id;
-       for (n = -1, i = 0; cards[i].id != 0; i++)
-               if (cards[i].id  == id)
-                       n = i;
-
-       if (n != -1) {
-               /* found it */
-               printk(KERN_INFO "bttv%d: card id: %s (0x%08x) => card=%d\n",
-                      btv->nr,cards[n].name,id,cards[n].cardnr);
-               return cards[n].cardnr;
-       } else {
-               /* 404 */
-               printk(KERN_INFO "bttv%d: id: unknown (0x%08x)\n",
-                      btv->nr, id);
-               printk(KERN_INFO "please mail id, board name and "
-                      "the correct card= insmod option to "
-                      "kraxel@goldbach.in-berlin.de\n");
-               return -1;
-       }
-}
-
-#ifndef HAVE_TVAUDIO
-/* can tda9855.c handle this too maybe? */
-static void __devinit init_tda9840(struct bttv *btv)
-{
-        /* Horrible Hack */
-        bttv_I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1);  /* sound mode switching */
-        /* 00 - mute
-           10 - mono / averaged stereo
-           2a - stereo
-           12 - dual A
-           1a - dual AB
-           16 - dual BA
-           1e - dual B
-           7a - external */
-}
-#endif
-
+/*
+ * identify card
+ */
 void __devinit bttv_idcard(struct bttv *btv)
 {
-       int type,eeprom = 0;
-
-       btwrite(0, BT848_GPIO_OUT_EN);
-
-       /* try to autodetect the card */
-       /* many bt878 cards have a eeprom @ 0xa0 => read ID
-          and try to identify it */
-       if (bttv_I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) {
-               eeprom = 0xa0;
-               bttv_readee(btv,eeprom_data,0xa0);
-               bttv_dump_eeprom(btv,0xa0); /* DEBUG */
-               type = bttv_idcard_eeprom(btv);
-               if (-1 != type) {
-                       btv->type = type;
-               } else if (btv->id <= 849) {
-                       /* for unknown bt848, assume old Hauppauge */
-                       btv->type=BTTV_HAUPPAUGE;
-               }
+       unsigned int gpiobits;
+       int i,type;
+       unsigned short tmp;
+
+       /* read PCI subsystem ID */
+       pci_read_config_word(btv->dev, PCI_SUBSYSTEM_ID, &tmp);
+       btv->cardid = tmp << 16;
+       pci_read_config_word(btv->dev, PCI_SUBSYSTEM_VENDOR_ID, &tmp);
+       btv->cardid |= tmp;
+
+       if (0 != btv->cardid && 0xffffffff != btv->cardid) {
+               /* look for the card */
+               for (type = -1, i = 0; cards[i].id != 0; i++)
+                       if (cards[i].id  == btv->cardid)
+                               type = i;
                
-       /* STB cards have a eeprom @ 0xae (old bt848) */
-       } else if (bttv_I2CRead(btv, I2C_STBEE, "eeprom")>=0) {
-               btv->type=BTTV_STB;
+               if (type != -1) {
+                       /* found it */
+                       printk(KERN_INFO "bttv%d: subsystem: %04x:%04x  =>  %s  =>  card=%d\n",
+                              btv->nr, btv->cardid & 0xffff, btv->cardid >> 16,
+                              cards[type].name,cards[type].cardnr);
+                       btv->type = cards[type].cardnr;
+               } else {
+                       /* 404 */
+                       printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
+                              btv->nr, btv->cardid&0xffff, btv->cardid>>16);
+                       printk(KERN_DEBUG "please mail id, board name and "
+                              "the correct card= insmod option to "
+                              "kraxel@goldbach.in-berlin.de\n");
+               }
        }
 
        /* let the user override the autodetected type */
@@ -387,8 +819,39 @@ void __devinit bttv_idcard(struct bttv *btv)
        printk(KERN_INFO "bttv%d: model: %s [%s]\n",btv->nr,btv->video_dev.name,
               (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
               "insmod option" : "autodetected");
-       
-        /* board specific initialisations */
+
+       /* overwrite gpio stuff ?? */
+       if (-1 == audioall && -1 == audiomux[0])
+               return;
+
+       if (-1 != audiomux[0]) {
+               gpiobits = 0;
+               for (i = 0; i < 5; i++) {
+                       bttv_tvcards[btv->type].audiomux[i] = audiomux[i];
+                       gpiobits |= audiomux[i];
+               }
+       } else {
+               gpiobits = audioall;
+               for (i = 0; i < 5; i++) {
+                       bttv_tvcards[btv->type].audiomux[i] = audioall;
+               }
+       }
+       bttv_tvcards[btv->type].gpiomask = (-1 != gpiomask) ? gpiomask : gpiobits;
+       printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
+              btv->nr,bttv_tvcards[btv->type].gpiomask);
+       for (i = 0; i < 5; i++) {
+               printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->type].audiomux[i]);
+       }
+       printk("\n");
+}
+
+/*
+ * (most) board specific initialisations goes here
+ */
+void __devinit bttv_init_card(struct bttv *btv)
+{
+       int eeprom = 0;
+
         if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) {
                 /* auto detect tuner for MIRO cards */
                 btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
@@ -407,7 +870,6 @@ void __devinit bttv_idcard(struct bttv *btv)
                        bttv_readee(btv,eeprom_data,0xa0);
                }
                 hauppauge_eeprom(btv);
-                hauppauge_boot_msp34xx(btv);
         }
        if (btv->type == BTTV_PXC200)
                init_PXC200(btv);
@@ -419,6 +881,10 @@ void __devinit bttv_idcard(struct bttv *btv)
                        btv->pll.pll_ifreq=28636363;
                        btv->pll.pll_crystal=BT848_IFORM_XT0;
                }
+               if (PLL_35 == bttv_tvcards[btv->type].pll) {
+                       btv->pll.pll_ifreq=35468950;
+                       btv->pll.pll_crystal=BT848_IFORM_XT1;
+               }
                /* insmod options can override */
                 switch (pll[btv->nr]) {
                 case 0: /* none */
@@ -427,18 +893,19 @@ void __devinit bttv_idcard(struct bttv *btv)
                        btv->pll.pll_ofreq   = 0;
                         break;
                 case 1: /* 28 MHz */
+               case 28:
                         btv->pll.pll_ifreq   = 28636363;
                        btv->pll.pll_ofreq   = 0;
-                        btv->pll.pll_crystal=BT848_IFORM_XT0;
+                        btv->pll.pll_crystal = BT848_IFORM_XT0;
                         break;
                 case 2: /* 35 MHz */
+               case 35:
                         btv->pll.pll_ifreq   = 35468950;
                        btv->pll.pll_ofreq   = 0;
-                        btv->pll.pll_crystal=BT848_IFORM_XT1;
+                        btv->pll.pll_crystal = BT848_IFORM_XT1;
                         break;
                 }
         }
-       
 
        /* tuner configuration */
        if (-1 != bttv_tvcards[btv->type].tuner_type)
@@ -447,62 +914,25 @@ void __devinit bttv_idcard(struct bttv *btv)
                bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
 
        /* try to detect audio/fader chips */
-       if (bttv_tvcards[btv->type].msp34xx &&
+       if (!bttv_tvcards[btv->type].no_msp34xx &&
            bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
                if (autoload)
                        request_module("msp3400");
        }
 
-#ifndef HAVE_TVAUDIO
-       if (bttv_tvcards[btv->type].tda8425 &&
-           bttv_I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) {
-               if (autoload)
-                       request_module("tda8425");
-        }
-
-       if (bttv_tvcards[btv->type].tda9840 &&
-           bttv_I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) {
-               init_tda9840(btv);
-                btv->audio_chip = TDA9840;
-               /* move this to a module too? */
-               init_tda9840(btv);
-       }
-
-       if (bttv_tvcards[btv->type].tda985x &&
-           bttv_I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) {
-               if (autoload)
-                       request_module("tda985x");
-       }
-       if (bttv_tvcards[btv->type].tea63xx) {
-               if (autoload)
-                       request_module("tea6300");
-       }
-#else
-       if (bttv_tvcards[btv->type].tda8425 ||
-           bttv_tvcards[btv->type].tda9840 ||
-           bttv_tvcards[btv->type].tda985x ||
-           bttv_tvcards[btv->type].tea63xx) {
-               if (autoload)
-                       request_module("tvaudio");
-       }
-#endif
-
-       if (bttv_tvcards[btv->type].tda9875 &&
-           bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
+       if (bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
                if (autoload)
                        request_module("tda9875");
        }
 
-       if (bttv_tvcards[btv->type].tda7432 &&
-           bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
+       if (bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
                if (autoload)
                        request_module("tda7432");
        }
 
-
-       if (bttv_tvcards[btv->type].tea64xx) {
+       if (bttv_tvcards[btv->type].needs_tvaudio) {
                if (autoload)
-                       request_module("tea6420");
+                       request_module("tvaudio");
        }
 
        if (bttv_tvcards[btv->type].tuner != -1) {
@@ -574,40 +1004,25 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
         {
                 btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
                if (bttv_verbose)
-                       printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
+                       printk("bttv%d: Hauppauge eeprom: model=%d, tuner=%s (%d)\n",btv->nr,
+                              eeprom_data[12] << 8 | eeprom_data[11],
                               hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
         }
 }
 
-static void __devinit hauppauge_boot_msp34xx(struct bttv *btv)
+void __devinit bttv_hauppauge_boot_msp34xx(struct bttv *btv)
 {
-       int i;
-
         /* reset/enable the MSP on some Hauppauge cards */
         /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */
         btaor(32, ~32, BT848_GPIO_OUT_EN);
         btaor(0, ~32, BT848_GPIO_DATA);
         udelay(2500);
         btaor(32, ~32, BT848_GPIO_DATA);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"msp34xx");
 
        if (bttv_verbose)
                printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr);
-
-       /* look if the msp3400 driver is already registered */
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               if (btv->i2c_clients[i] != NULL &&
-                   btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) {
-                       return;
-               }
-       }
-
-       /* if not: look for the chip ... */
-       if (bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx")) {
-               /* ... if found re-register to trigger a i2c bus rescan, */
-               /*     this time with the msp34xx chip activated */
-               i2c_bit_del_bus(&btv->i2c_adap);
-               i2c_bit_add_bus(&btv->i2c_adap);
-       }
 }
 
 
@@ -632,6 +1047,8 @@ static void __devinit init_PXC200(struct bttv *btv)
        /* GPIO inputs are pulled up, so no need to drive 
         * reset pin any longer */
        btwrite(0,BT848_GPIO_OUT_EN);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"pxc200");
 
        /*  we could/should try and reset/control the AD pots? but
            right now  we simply  turned off the crushing.  Without
@@ -716,6 +1133,8 @@ static int tea_read(struct bttv *btv)
        
        /* better safe than sorry */
        btaor((1<<TEA_CLK) | (1<<TEA_WE), ~((1<<TEA_CLK) | (1<<TEA_DATA) | (1<<TEA_WE) | (1<<TEA_MOST)), BT848_GPIO_OUT_EN);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"miro tea read");
        
        BUS_LOW(WE);
        BUS_LOW(CLK);
@@ -753,7 +1172,10 @@ static int tea_write(struct bttv *btv, int value)
        int reg = value;
        
        btaor((1<<TEA_CLK) | (1<<TEA_WE) | (1<<TEA_DATA), ~((1<<TEA_CLK) | (1<<TEA_DATA) | (1<<TEA_WE) | (1<<TEA_MOST)), BT848_GPIO_OUT_EN);
-       if (bttv_debug) printk("tea5757: write 0x%X\n", value);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"miro tea write");
+       if (bttv_debug)
+               printk("tea5757: write 0x%X\n", value);
        BUS_LOW(CLK);
        BUS_HIGH(WE);
        for(i = 0; i < 25; i++)
@@ -778,6 +1200,7 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
        if (bttv_debug) tea_read(btv);
 }
 
+#if 0
 void init_tea5757(struct bttv *btv)
 {
        BUS_LOW(CLK);
@@ -788,14 +1211,20 @@ void init_tea5757(struct bttv *btv)
        /* normal mode for GPIO */
        btaor(0, BT848_GPIO_DMA_CTL_GPIOMODE, BT848_GPIO_DMA_CTL);
 }
+#endif
 
 /* ----------------------------------------------------------------------- */
 /* winview                                                                 */
 
-void winview_setvol(struct bttv *btv, struct video_audio *v)
+void winview_audio(struct bttv *btv, struct video_audio *v, int set)
 {
        /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
        int bits_out, loops, vol, data;
+
+       if (!set) {
+               v->mode |= VIDEO_AUDIO_VOLUME;
+               return;
+       }
        
        /* 32 levels logarithmic */
        vol = 32 - ((v->volume>>11));
@@ -828,6 +1257,68 @@ void winview_setvol(struct bttv *btv, struct video_audio *v)
        btwrite(data, BT848_GPIO_DATA);
 }
 
+/* ----------------------------------------------------------------------- */
+/* mono/stereo control for various cards (which don't use i2c chips but    */
+/* connect something to the GPIO pins                                      */
+
+static void
+gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int con = 0;
+
+       if (set) {
+               btor(0x100, BT848_GPIO_OUT_EN);
+               if (v->mode & VIDEO_SOUND_LANG1)
+                       con = 0x000;
+               if (v->mode & VIDEO_SOUND_LANG2)
+                       con = 0x300;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       con = 0x200;
+//             if (v->mode & VIDEO_SOUND_MONO)
+//                     con = 0x100;
+               btaor(con, ~0x300, BT848_GPIO_DATA);
+       } else {
+               v->mode = VIDEO_SOUND_STEREO |
+                         VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
+       }
+}
+
+/*
+ * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
+ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+ *  0xdde enables mono and 0xccd enables sap
+ *
+ * Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+ *  input/output sound connection, so both must be set for output mode.
+ *
+ */
+static void
+avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       /* TODO */
+}
+
+static void
+terratv_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int con = 0;
+
+       if (set) {
+               btor(0x180000, BT848_GPIO_OUT_EN);
+               if (v->mode & VIDEO_SOUND_LANG2)
+                       con = 0x080000;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       con = 0x180000;
+               btaor(con, ~0x180000, BT848_GPIO_DATA);
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"terratv");
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       }
+}
+
 /*
  * Local variables:
  * c-basic-offset: 8
index fe0d72e696c5ef359246b03cda574def68a5c79b..9f2a1bc52cd1507cb776c46c08ddc0d3e501a4a0 100644 (file)
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
-#ifdef HACKING
-# include <linux/iobuf.h>
-#endif
 
-#include "bttv.h"
+#include "bttvp.h"
 #include "tuner.h"
 
 #define DEBUG(x)       /* Debug driver */
-#define IDEBUG(x)      /* Debug interrupt handler */
 #define MIN(a,b) (((a)>(b))?(b):(a))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-
 static void bt848_set_risc_jmps(struct bttv *btv, int state);
 
 int bttv_num;                  /* number of Bt848s in use */
 struct bttv bttvs[BTTV_MAX];
 
-
 /* insmod args */
 MODULE_PARM(triton1,"i");
 MODULE_PARM(radio,"1-4i");
+MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
 MODULE_PARM(bigendian,"i");
+MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
 MODULE_PARM(fieldnr,"i");
+MODULE_PARM_DESC(fieldnr,"count fields, default is 0 (no)");
 MODULE_PARM(bttv_verbose,"i");
+MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
+MODULE_PARM(bttv_gpio,"i");
+MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
 MODULE_PARM(bttv_debug,"i");
+MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
+MODULE_PARM(irq_debug,"i");
+MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
 MODULE_PARM(gbuffers,"i");
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");
 MODULE_PARM(gbufsize,"i");
+MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM(combfilter,"i");
 
 MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph  Metzler & Marcus Metzler & Gerd Knorr");
@@ -84,10 +90,13 @@ static unsigned int bigendian=0;
 static int triton1=0;
 static unsigned int radio[BTTV_MAX];
 static unsigned int fieldnr = 0;
+static unsigned int irq_debug = 0;
 static unsigned int gbuffers = 2;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
+static unsigned int combfilter = 0;
 unsigned int bttv_debug = 0;
 unsigned int bttv_verbose = 1;
+unsigned int bttv_gpio = 0;
 
 #define I2C_TIMING (0x7<<4)
 #define I2C_DELAY   10
@@ -133,8 +142,9 @@ static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
                         ptep = pte_offset(pmd, adr);
                         pte = *ptep;
                         if(pte_present(pte)) {
-                               ret = (unsigned long) page_address(pte_page(pte));
-                                ret |= (adr & (PAGE_SIZE - 1));
+                               ret  = (unsigned long) page_address(pte_page(pte));
+                               ret |= (adr & (PAGE_SIZE - 1));
+                               
                        }
                 }
         }
@@ -239,9 +249,9 @@ static int fbuffer_alloc(struct bttv *btv)
 }
 
 
+/* init + register i2c algo-bit adapter */
 static int __devinit init_bttv_i2c(struct bttv *btv)
 {
-       /* i2c bit_adapter */
        memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, sizeof(struct i2c_adapter));
        memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, sizeof(struct i2c_algo_bit_data));
        memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client));
@@ -256,13 +266,25 @@ static int __devinit init_bttv_i2c(struct bttv *btv)
        bttv_bit_setscl(btv,1);
        bttv_bit_setsda(btv,1);
 
-       btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap);
-       return btv->i2c_ok;
+       btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
+       return btv->i2c_rc;
 }
 
 
 /* ----------------------------------------------------------------------- */
 
+void bttv_gpio_tracking(struct bttv *btv, char *comment)
+{
+       unsigned int outbits, data;
+       outbits = btread(BT848_GPIO_OUT_EN);
+       data    = btread(BT848_GPIO_DATA);
+       printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
+              btv->nr,outbits,data & outbits, data & ~outbits, comment);
+}
+
+static char *audio_modes[] = { "audio: tuner", "audio: radio", "audio: extern",
+                              "audio: intern", "audio: off" };
+
 static void audio(struct bttv *btv, int mode, int no_irq_context)
 {
        btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask,
@@ -295,6 +317,8 @@ static void audio(struct bttv *btv, int mode, int no_irq_context)
                mode = AUDIO_RADIO;
        btaor(bttv_tvcards[btv->type].audiomux[mode],
               ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,audio_modes[mode]);
        if (no_irq_context)
                bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
 }
@@ -406,14 +430,16 @@ static int set_pll(struct bttv *btv)
 
 static void bt848_muxsel(struct bttv *btv, unsigned int input)
 {
+
+#if 0 /* seems no card uses this ... */
        btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2,
               BT848_GPIO_OUT_EN);
+#endif
 
        /* This seems to get rid of some synchronization problems */
        btand(~(3<<5), BT848_IFORM);
        mdelay(10); 
         
-        
        input %= bttv_tvcards[btv->type].video_inputs;
        if (input==bttv_tvcards[btv->type].svhs) 
        {
@@ -428,8 +454,13 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input)
        btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);
        audio(btv, (input!=bttv_tvcards[btv->type].tuner) ? 
               AUDIO_EXTERN : AUDIO_TUNER, 1);
+
+#if 0 /* seems no card uses this ... */
        btaor(bttv_tvcards[btv->type].muxsel[input]>>4,
                ~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"muxsel");
+#endif
 }
 
 
@@ -942,9 +973,9 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
                                lastbit=cbit;
                                sx += dx;
                                dx = 1;
-                               if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16)
+                               if (ro - btv->risc_scr_odd>(RISCMEM_LEN>>3) - 16)
                                        outofmem++;
-                               if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16)
+                               if (re - btv->risc_scr_even>(RISCMEM_LEN>>3) - 16)
                                        outofmem++;
                        }
                        x++;
@@ -997,17 +1028,17 @@ static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn,
                ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
        vscale |= inter ? (BT848_VSCALE_INT<<8) : 0;
 
-#if 0
-       /* Some people say interpolation looks bad ... */
-       vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
-       if (width < 767)
-               btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-       else
+       if (combfilter) {
+               /* Some people say interpolation looks bad ... */
+               vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+               if (width < 769)
+                       btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+               else
+                       btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+       } else {
+               vtc = 0;
                btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-#else
-       vtc = 0;
-       btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-#endif
+       }
 
        btwrite(vtc, BT848_E_VTC+off);
        btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
@@ -1133,131 +1164,6 @@ static void bt848_set_winsize(struct bttv *btv)
         bt848_set_geo(btv,1);
 }
 
-#ifdef HACKING
-/* playing with kiobufs and dma-to-userspace. 2.4.x only
-   Yes, I know: cut+paste programming is ugly.
-   will fix later, this is proof-of-concept right now. */
-static int  make_vrisctab_kiobuf(struct bttv *btv, unsigned int *ro,
-                                unsigned int *re, struct kiobuf *iobuf,
-                                unsigned short width, unsigned short height,
-                                unsigned short palette)
-{
-       unsigned long bpl;  /* bytes per line */
-       unsigned long bl;
-       unsigned long todo;
-       unsigned long pageaddr;
-       unsigned int **rp;
-       unsigned long line,inter,offset,page;
-       
-       inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
-       bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
-       
-       *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 
-        *(ro++)=cpu_to_le32(0);
-       *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
-        *(re++)=cpu_to_le32(0);
-
-       offset   = iobuf->offset;
-       page     = 0;
-       pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
-       for (line=0; line < (height<<(1^inter)); line++)
-       {
-               if (inter) 
-                       rp= (line&1) ? &re : &ro;
-               else 
-                       rp= (line>=height) ? &ro : &re;
-
-               bl = PAGE_SIZE - offset;
-               if (bpl <= bl) {
-                       *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
-                                              BT848_RISC_EOL|bpl);
-                       *((*rp)++)=cpu_to_le32(pageaddr+offset);
-                       offset+=bpl;
-               } else {
-                       todo = bpl;
-                       *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl);
-                       *((*rp)++)=cpu_to_le32(pageaddr+offset);
-                       todo -= bl;
-                       offset = 0;
-                       page++;
-                       pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
-                       while (todo>PAGE_SIZE)
-                       {
-                               *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE);
-                               *((*rp)++)=cpu_to_le32(pageaddr);
-                               page++;
-                               pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
-                       }
-                       *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo);
-                       *((*rp)++)=cpu_to_le32(pageaddr);
-                       offset += todo;
-               }
-       }
-       
-       *(ro++)=cpu_to_le32(BT848_RISC_JUMP);
-       *(ro++)=cpu_to_le32(btv->bus_vbi_even);
-       *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
-       *(re++)=cpu_to_le32(btv->bus_vbi_odd);
-       
-       return 0;
-}
-
-static int vgrab_kiobuf(struct bttv *btv, struct bttv_just_hacking *mp,
-                       struct kiobuf *iobuf)
-{
-       unsigned int *ro, *re;
-       unsigned long flags;
-       
-       if(btv->gbuf[0].stat != GBUFFER_UNUSED)
-               return -EBUSY;
-       
-       if(mp->height < 32 || mp->width < 32)
-               return -EINVAL;
-       if (mp->format >= 12 /* more is'nt yet ... PALETTEFMT_MAX */)
-               return -EINVAL;
-
-       if(-1 == palette2fmt[mp->format])
-               return -EINVAL;
-
-       /*
-        *      Ok load up the BT848
-        */
-        
-       ro=btv->gbuf[0].risc;
-       re=ro+2048;
-        make_vrisctab_kiobuf(btv, ro, re, iobuf, mp->width, mp->height, mp->format);
-       
-       if (bttv_debug)
-               printk("bttv%d: cap vgrab_kiobuf: queue %d (%d:%dx%d)\n",
-                      btv->nr,0,mp->format,mp->width,mp->height);
-               spin_lock_irqsave(&btv->s_lock, flags); 
-        btv->gbuf[0].stat    = GBUFFER_GRABBING;
-       btv->gbuf[0].fmt     = palette2fmt[mp->format];
-       btv->gbuf[0].width   = mp->width;
-       btv->gbuf[0].height  = mp->height;
-       btv->gbuf[0].ro      = virt_to_bus(ro);
-       btv->gbuf[0].re      = virt_to_bus(re);
-
-#if 1
-       if (mp->height <= tvnorms[btv->win.norm].sheight/2 &&
-           mp->format != VIDEO_PALETTE_RAW)
-               btv->gbuf[0].ro = 0;
-#endif
-
-       if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) {
-               btv->gq_start = 1;
-               btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
-        }
-       btv->gqueue[btv->gq_in++] = 0;
-       btv->gq_in = btv->gq_in % MAX_GBUFFERS;
-
-       btor(3, BT848_CAP_CTL);
-       btor(3, BT848_GPIO_DMA_CTL);
-       spin_unlock_irqrestore(&btv->s_lock, flags);
-       return 0;
-}
-#endif
-
 /*
  *     Grab into virtual memory.
  */
@@ -1393,6 +1299,39 @@ static inline void burst(int on)
        tvnorms[2].hdelayx1     = 186  - (on?BURSTOFFSET  :0);
 }
 
+/*
+ * called from irq handler on fatal errors.  Takes the grabber chip
+ * offline, flag it needs a reinitialization (which can't be done
+ * from irq context) and wake up all sleeping proccesses.  They would
+ * block forever else.  We also need someone who actually does the
+ * reinitialization from process context...
+ */
+static void bt848_offline(struct bttv *btv)
+{
+       int i;
+       spin_lock(&btv->s_lock);
+
+       /* cancel all outstanding grab requests */
+       btv->gq_in = 0;
+       btv->gq_out = 0;
+       btv->gq_grab = -1;
+       for (i = 0; i < gbuffers; i++)
+               if (btv->gbuf[i].stat == GBUFFER_GRABBING)
+                       btv->gbuf[i].stat = GBUFFER_ERROR;
+
+       /* disable screen overlay and DMA */
+       btv->risc_cap_odd  = 0;
+       btv->risc_cap_even = 0;
+       bt848_set_risc_jmps(btv,0);
+
+       /* flag the chip needs a restart */
+       btv->needs_restart = 1;
+       spin_unlock(&btv->s_lock);
+
+       wake_up_interruptible(&btv->vbiq);
+       wake_up_interruptible(&btv->capq);
+}
+
 static void bt848_restart(struct bttv *btv)
 {
        unsigned long irq_flags;
@@ -1427,6 +1366,8 @@ static int bttv_open(struct video_device *dev, int flags)
         int i,ret;
 
        ret = -EBUSY;
+       if (bttv_debug)
+               printk("bttv%d: open called\n",btv->nr);
 
        MOD_INC_USE_COUNT;
        down(&btv->lock);
@@ -1724,6 +1665,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        btv->scr_on = 0;
                        bt848_set_risc_jmps(btv,-1);
                        spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+                       up(&btv->lock);
                        return -EINVAL;
                }
                if (btv->win.bpp < 4) 
@@ -1747,20 +1689,26 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                 *      Do any clips.
                 */
                if(vw.clipcount<0) {
-                       if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL)
+                       if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
+                               up(&btv->lock);
                                return -ENOMEM;
+                       }
                        if(copy_from_user(vcp, vw.clips,
                                          VIDEO_CLIPMAP_SIZE)) {
+                               up(&btv->lock);
                                vfree(vcp);
                                return -EFAULT;
                        }
                } else if (vw.clipcount) {
                        if((vcp=vmalloc(sizeof(struct video_clip)*
-                                       (vw.clipcount))) == NULL)
+                                       (vw.clipcount))) == NULL) {
+                               up(&btv->lock);
                                return -ENOMEM;
+                       }
                        if(copy_from_user(vcp,vw.clips,
                                          sizeof(struct video_clip)*
                                          vw.clipcount)) {
+                               up(&btv->lock);
                                vfree(vcp);
                                return -EFAULT;
                        }
@@ -1898,21 +1846,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                v.mode = VIDEO_SOUND_MONO;
                bttv_call_i2c_clients(btv,cmd,&v);
 
-               if (btv->type == BTTV_TERRATV) {
-                       v.mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                               VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-               }
-#ifndef HAVE_TVAUDIO
-               else if (btv->audio_chip == TDA9840) {
-                       /* begin of Horrible Hack <grin@tolna.net> */
-                       v.flags|=VIDEO_AUDIO_VOLUME;
-                       v.mode  = VIDEO_SOUND_MONO;
-                       v.mode |= VIDEO_SOUND_STEREO;
-                       v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
-                       v.volume = 32768;       /* fixme */
-                       v.step = 4096;
-               }
-#endif
+               /* card specific hooks */
+               if (bttv_tvcards[btv->type].audio_hook)
+                       bttv_tvcards[btv->type].audio_hook(btv,&v,0);
 
                if(copy_to_user(arg,&v,sizeof(v)))
                        return -EFAULT;
@@ -1938,17 +1874,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 
                bttv_call_i2c_clients(btv,cmd,&v);
                
-               if (btv->type == BTTV_TERRATV) {
-                       unsigned int con = 0;
-                       btor(0x180000, BT848_GPIO_OUT_EN);
-                       if (v.mode & VIDEO_SOUND_LANG2)
-                               con = 0x080000;
-                       if (v.mode & VIDEO_SOUND_STEREO)
-                               con = 0x180000;
-                       btaor(con, ~0x180000, BT848_GPIO_DATA);
-
-               } else if (btv->type == BTTV_WINVIEW_601)
-                       winview_setvol(btv,&v);
+               /* card specific hooks */
+               if (bttv_tvcards[btv->type].audio_hook)
+                       bttv_tvcards[btv->type].audio_hook(btv,&v,0);
 
                btv->audio_dev=v;
                up(&btv->lock);
@@ -2082,79 +2010,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                return  0;
        }
 
-#ifdef HACKING
-       /* playing with kiobufs and dma-to-userspace */
-       case BTTV_JUST_HACKING:
-       {
-               DECLARE_WAITQUEUE(wait, current);
-               struct bttv_just_hacking hack;
-               struct kiobuf *iobuf;
-               int err;
-               
-               if(copy_from_user((void *) &hack, (void *) arg, sizeof(hack)))
-                       return -EFAULT;
-               printk("bttv%d: hack: userland args: %dx%d, fmt=%d, buf=%lx, len=%d\n",
-                      btv->nr,hack.width,hack.height,hack.format,
-                      hack.buf,hack.len);
-
-               /* pin down */
-               err = alloc_kiovec(1,&iobuf);
-               if (err)
-                       goto hack_oops;
-               err = map_user_kiobuf(READ, iobuf, hack.buf, hack.len);
-               if (err)
-                       goto hack_oops;
-               err = lock_kiovec(1,&iobuf,1);
-               if (err)
-                       goto hack_oops;
-
-               /* have a look */
-               printk("bttv%d: hack: kiobuf: nr_pages=%d, offset=%d, length=%d, locked=%d\n",
-                      btv->nr,iobuf->nr_pages,iobuf->offset,iobuf->length,
-                      iobuf->locked);
-               printk("bttv%d: hack: pages (bus addr):",btv->nr);
-               for (i = 0; i < iobuf->nr_pages; i++) {
-                       printk(" %lx", virt_to_bus(page_address(iobuf->maplist[i])));
-               }
-               printk("\n");
-
-               /* start capture */
-               err = -EINVAL;
-               if (hack.height * hack.width * 2 * /* fixme: *2 */
-                   fmtbppx2[palette2fmt[hack.format]&0x0f]/2 > hack.len)
-                       goto hack_oops;
-               err = vgrab_kiobuf(btv,&hack,iobuf);
-               if (err)
-                       goto hack_oops;
-               printk("bttv%d: hack: capture started\n",btv->nr);
-
-               /* wait */
-               add_wait_queue(&btv->capq, &wait);
-               current->state = TASK_INTERRUPTIBLE;
-               while(btv->gbuf[0].stat==GBUFFER_GRABBING) {
-                       if (bttv_debug)
-                               printk("bttv%d: hack: cap sync: sleep on %d\n",btv->nr,0);
-                       schedule();
-#if 0
-                       if(signal_pending(current)) {
-                               remove_wait_queue(&btv->capq, &wait);
-                               current->state = TASK_RUNNING;
-                               return -EINTR;
-                       }
-#endif
-               }
-               remove_wait_queue(&btv->capq, &wait);
-               current->state = TASK_RUNNING;
-               printk("bttv%d: hack: capture done\n",btv->nr);
-               
-               /* release */
-               err = 0;
-       hack_oops:
-               free_kiovec(1,&iobuf);
-               return 0;
-       }
-#endif
-
        default:
                return -ENOIOCTLCMD;
        }
@@ -2353,7 +2208,8 @@ static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
        }
        case VIDIOCGFREQ:
        case VIDIOCSFREQ:
-               return bttv_ioctl((struct video_device *)btv,cmd,arg);
+       case BTTV_VERSION:
+               return bttv_ioctl(dev,cmd,arg);
        case BTTV_VBISIZE:
                /* make alevt happy :-) */
                return VBIBUF_SIZE;
@@ -2456,6 +2312,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                v.rangehigh=(int)(108*16);      /* eu: 87.5MHz - 108.0MHz */
                v.flags= 0; /* XXX */
                v.mode = 0; /* XXX */
+               bttv_call_i2c_clients(btv,cmd,&v);
                if(copy_to_user(arg,&v,sizeof(v)))
                        return -EFAULT;
                return 0;
@@ -2579,7 +2436,8 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
                        printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd);
                flags |= 3;
                btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd);
-       } else if (flags&2) {
+       } else if ((flags&2) &&
+                  (!btv->win.interlace || 0 == btv->risc_cap_even)) {
                if (bttv_debug > 1)
                        printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd));
                btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd));
@@ -2614,7 +2472,8 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
                        printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even);
                flags |= 3;
                btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even);
-       } else if (flags&1) {
+       } else if ((flags&1) &&
+                  btv->win.interlace) {
                if (bttv_debug > 1)
                        printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even));
                btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even));
@@ -2648,7 +2507,6 @@ static int __devinit init_video_dev(struct bttv *btv)
        memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
        memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
         
-       bttv_idcard(btv);
        audio(btv, AUDIO_MUTE, 1);
         
        if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
@@ -2680,12 +2538,8 @@ static int __devinit init_bt848(struct bttv *btv)
 
        /* dump current state of the gpio registers before changing them,
         * might help to make a new card work */
-       if (bttv_verbose >= 2)
-               printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n",
-                      btv->nr,
-                      btread(BT848_GPIO_OUT_EN),
-                      btread(BT848_GPIO_DATA),
-                      btread(BT848_GPIO_REG_INP));
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"init #1");
 
        /* reset the bt848 */
        btwrite(0, BT848_SRESET);
@@ -2724,10 +2578,6 @@ static int __devinit init_bt848(struct bttv *btv)
        btv->errors=0;
        btv->needs_restart=0;
 
-       /* i2c */
-        btv->tuner_type=-1;
-        init_bttv_i2c(btv);
-
        if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
                return -1;
        if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
@@ -2772,6 +2622,9 @@ static int __devinit init_bt848(struct bttv *btv)
 
         /* select direct input */
        btwrite(0x00, BT848_GPIO_REG_INP);
+       btwrite(0x00, BT848_GPIO_OUT_EN);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"init #2");
 
        btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO,
                BT848_IFORM);
@@ -2814,6 +2667,17 @@ static int __devinit init_bt848(struct bttv *btv)
        bt848_set_risc_jmps(btv,-1);
        spin_unlock_irqrestore(&btv->s_lock, irq_flags);
 
+       /* needs to be done before i2c is registered */
+        if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
+                bttv_hauppauge_boot_msp34xx(btv);
+
+       /* register i2c */
+        btv->tuner_type=-1;
+        init_bttv_i2c(btv);
+
+       /* some card-specific stuff (needs working i2c) */
+       bttv_init_card(btv);
+
        /*
         *      Now add the template and register the device unit.
         */
@@ -2822,11 +2686,18 @@ static int __devinit init_bt848(struct bttv *btv)
        return 0;
 }
 
+/* ----------------------------------------------------------------------- */
+
+static char *irq_name[] = { "FMTCHG", "VSYNC", "HSYNC", "OFLOW", "HLOCK",
+                           "VPRES", "6", "7", "I2CDONE", "GPINT", "10",
+                           "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
+                           "RIPERR", "PABORT", "OCERR", "SCERR" };
+
 static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
        u32 stat,astat;
        u32 dstat;
-       int count,i;
+       int count;
        struct bttv *btv;
 
        btv=(struct bttv *)dev_id;
@@ -2838,33 +2709,39 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                astat=stat&btread(BT848_INT_MASK);
                if (!astat)
                        return;
-               btwrite(astat,BT848_INT_STAT);
-               IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat));
-               IDEBUG(printk ("bttv%d:  stat=%08x\n", btv->nr, stat));
+               btwrite(stat,BT848_INT_STAT);
 
                /* get device status bits */
                dstat=btread(BT848_DSTATUS);
-    
-               if (astat&BT848_INT_GPINT) {
-                       IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr));
-                       wake_up_interruptible(&btv->gpioq);
-               }
 
-               if (astat&BT848_INT_FMTCHG) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr));
-                       /*btv->win.norm&=
-                         (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
-               }
-               if (astat&BT848_INT_VPRES) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr));
+               if (irq_debug) {
+                       int i;
+                       printk(KERN_DEBUG "bttv%d: irq loop=%d risc=%x, bits:",
+                              btv->nr, count, stat>>28);
+                       for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
+                               if (stat & (1 << i))
+                                       printk(" %s",irq_name[i]);
+                               if (astat & (1 << i))
+                                       printk("*");
+                       }
+                       if (stat & BT848_INT_HLOCK)
+                               printk("   HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
+                                      ? "yes" : "no");
+                       if (stat & BT848_INT_VPRES)
+                               printk("   PRES => %s", (dstat & BT848_DSTATUS_PRES)
+                                      ? "yes" : "no");
+                       if (stat & BT848_INT_FMTCHG)
+                               printk("   NUML => %s", (dstat & BT848_DSTATUS_PRES)
+                                      ? "625" : "525");
+                       printk("\n");
                }
+
+               if (astat&BT848_INT_GPINT)
+                       wake_up_interruptible(&btv->gpioq);
+
                if (astat&BT848_INT_VSYNC) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
                         btv->field++;
-               }
+
                if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
                        if (bttv_verbose)
                                printk("bttv%d: irq:%s%s risc_count=%08x\n",
@@ -2884,23 +2761,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                        } else {
                                if (bttv_verbose)
                                        printk("bttv%d: aiee: error loops\n",btv->nr);
-                               /* cancel all outstanding grab requests */
-                               spin_lock(&btv->s_lock);
-                               btv->gq_in = 0;
-                               btv->gq_out = 0;
-                               btv->gq_grab = -1;
-                               for (i = 0; i < gbuffers; i++)
-                                       if (btv->gbuf[i].stat == GBUFFER_GRABBING)
-                                               btv->gbuf[i].stat = GBUFFER_ERROR;
-                               /* disable DMA */
-                               btv->risc_cap_odd  = 0;
-                               btv->risc_cap_even = 0;
-                               bt848_set_risc_jmps(btv,0);
-                               btv->needs_restart = 1;
-                               spin_unlock(&btv->s_lock);
-
-                               wake_up_interruptible(&btv->vbiq);
-                               wake_up_interruptible(&btv->capq);
+                               bt848_offline(btv);
                        }
                }
                if (astat&BT848_INT_RISCI) 
@@ -2968,55 +2829,20 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                                spin_unlock(&btv->s_lock);
                        }
                }
-               if (astat&BT848_INT_OCERR) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr));
-               }
-               if (astat&BT848_INT_PABORT) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr));
-               }
-               if (astat&BT848_INT_RIPERR) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr));
-               }
-               if (astat&BT848_INT_PPERR) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr));
-               }
-               if (astat&BT848_INT_FDSR) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr));
-               }
-               if (astat&BT848_INT_FTRGT) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr));
-               }
-               if (astat&BT848_INT_FBUS) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr));
-               }
-               if (astat&BT848_INT_HLOCK) 
-               {
+
+               if (astat&BT848_INT_HLOCK) {
                        if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
                                audio(btv, AUDIO_ON,0);
                        else
                                audio(btv, AUDIO_OFF,0);
                }
     
-               if (astat&BT848_INT_I2CDONE) 
-               {
-                       IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr));
-               }
                count++;
-               if (count > 10)
-                       printk (KERN_WARNING "bttv%d: irq loop %d\n",
-                                btv->nr,count);
-               if (count > 20) 
-               {
+               if (count > 20) {
                        btwrite(0, BT848_INT_MASK);
                        printk(KERN_ERR 
                               "bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
+                       bt848_offline(btv);
                }
        }
 }
@@ -3033,8 +2859,11 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
         int j;
         struct bttv *btv = pci_get_drvdata(pci_dev);
 
+       if (bttv_verbose)
+               printk("bttv%d: unloading\n",btv->nr);
+
         /* unregister i2c_bus */
-       if (0 == btv->i2c_ok)
+       if (0 == btv->i2c_rc)
                i2c_bit_del_bus(&btv->i2c_adap);
 
         /* turn off all capturing, DMA and IRQs */
@@ -3044,6 +2873,8 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
         btwrite(0, BT848_INT_MASK);
         btwrite(~0x0UL,BT848_INT_STAT);
         btwrite(0x0, BT848_GPIO_OUT_EN);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"cleanup");
 
         /* disable PCI bus-mastering */
         pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
@@ -3084,7 +2915,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
         if (radio[btv->nr] && btv->radio_dev.minor != -1)
                 video_unregister_device(&btv->radio_dev);
 
-        release_mem_region(btv->bt848_adr,
+        release_mem_region(pci_resource_start(btv->dev,0),
                            pci_resource_len(btv->dev,0));
         /* wake up any waiting processes
            because shutdown flag is set, no new processes (in this queue)
@@ -3094,7 +2925,6 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
         wake_up(&btv->gpioq);
 
        pci_set_drvdata(pci_dev, NULL);
-
         return;
 }
 
@@ -3102,7 +2932,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
 static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
 {
        int result;
-       unsigned char command;
+       unsigned char command,lat;
        struct bttv *btv;
 #if defined(__powerpc__)
         unsigned int cmd;
@@ -3141,11 +2971,14 @@ static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
-        printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
-               bttv_num,btv->id, btv->revision);
-        printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn);
-        printk("irq: %d, ",btv->irq);
-        printk("memory: 0x%lx.\n", btv->bt848_adr);
+        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ",
+               bttv_num,btv->id, btv->revision, dev->bus->number,
+              PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
+        printk("irq: %d, latency: %d, memory: 0x%lx\n",
+              btv->irq, lat, btv->bt848_adr);
+       
+       bttv_idcard(btv);
 
 #if defined(__powerpc__)
         /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
index a58e441dbf8fc06c7b4a2b5fec914b645cf549f1..d2ed393079f3722b0ebed8370ba9f94dc73dc4fd 100644 (file)
@@ -3,7 +3,6 @@
        all the i2c code is here
        also the gpio interface exported by bttv (used by lirc)
 
-
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
@@ -34,7 +33,7 @@
 
 #include <asm/io.h>
 
-#include "bttv.h"
+#include "bttvp.h"
 #include "tuner.h"
 
 
@@ -79,6 +78,8 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
        
        btv = &bttvs[card];
        btaor(data, ~mask, BT848_GPIO_OUT_EN);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"extern enable");
        return 0;
 }
 
@@ -115,6 +116,8 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
 /* prior setting BT848_GPIO_REG_INP is (probably) not needed 
    because direct input is set on init */
        btaor(data & mask, ~mask, BT848_GPIO_DATA);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"extern write");
        return 0;
 }
 
@@ -195,8 +198,7 @@ static int attach_inform(struct i2c_client *client)
        int i;
 
        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               if (btv->i2c_clients[i] == NULL ||
-                   btv->i2c_clients[i]->driver->id == client->driver->id) {
+               if (btv->i2c_clients[i] == NULL) {
                        btv->i2c_clients[i] = client;
                        break;
                }
@@ -216,8 +218,7 @@ static int detach_inform(struct i2c_client *client)
         if (bttv_verbose)
                printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name);
        for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               if (NULL != btv->i2c_clients[i] &&
-                   btv->i2c_clients[i]->driver->id == client->driver->id) {
+               if (btv->i2c_clients[i] == client) {
                        btv->i2c_clients[i] = NULL;
                        break;
                }
@@ -240,33 +241,27 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
 }
 
 struct i2c_algo_bit_data bttv_i2c_algo_template = {
-       NULL,
-       bttv_bit_setsda,
-       bttv_bit_setscl,
-       bttv_bit_getsda,
-       bttv_bit_getscl,
-       10, 10, 100,
+       setsda:  bttv_bit_setsda,
+       setscl:  bttv_bit_setscl,
+       getsda:  bttv_bit_getsda,
+       getscl:  bttv_bit_getscl,
+       udelay:  40,
+       mdelay:  10,
+       timeout: 200,
 };
 
 struct i2c_adapter bttv_i2c_adap_template = {
-       "bt848",
-       I2C_HW_B_BT848,
-       NULL,
-       NULL,
-       bttv_inc_use,
-       bttv_dec_use,
-       attach_inform,
-       detach_inform,
-       NULL,
+       name:              "bt848",
+       id:                I2C_HW_B_BT848,
+       inc_use:           bttv_inc_use,
+       dec_use:           bttv_dec_use,
+       client_register:   attach_inform,
+       client_unregister: detach_inform,
 };
 
 struct i2c_client bttv_i2c_client_template = {
-        "bttv internal",
-        -1,
-        0,
-        0,
-        NULL,
-        NULL
+        name: "bttv internal use only",
+        id:   -1,
 };
 
 
@@ -275,7 +270,7 @@ int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
 {
         unsigned char buffer = 0;
 
-       if (0 != btv->i2c_ok)
+       if (0 != btv->i2c_rc)
                return -1;
        if (bttv_verbose && NULL != probe_for)
                printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
@@ -302,7 +297,7 @@ int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
         unsigned char buffer[2];
         int bytes = both ? 2 : 1;
 
-       if (0 != btv->i2c_ok)
+       if (0 != btv->i2c_rc)
                return -1;
         btv->i2c_client.addr = addr >> 1;
         buffer[0] = b1;
index 5b9c178cb08b76f26c5be36d9e4dc7140991fe7c..c7aaa8bf3b5a80a2cb8c1fa6481e8f2eb2dc70fd 100644 (file)
@@ -1,42 +1,19 @@
 /*
-    bttv - Bt848 frame grabber driver
-
-    Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+ *  bttv - Bt848 frame grabber driver
+ *
+ *  card ID's and external interfaces of the bttv driver
+ *  basically stuff needed by other drivers (i2c, lirc, ...)
+ *  and is supported not to change much over time.
+ *
+ *  Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ *  (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
 
 #ifndef _BTTV_H_
 #define _BTTV_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,38)
-
-#include <linux/types.h>
-#include <linux/wait.h>
 #include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "audiochip.h"
-#include "bt848.h"
-
-#ifdef __KERNEL__
-
-/* fwd decl */
-struct bttv;
-
 
 /* ---------------------------------------------------------- */
 /* exported by bttv-cards.c                                   */
@@ -90,6 +67,35 @@ struct bttv;
 #define BTTV_ZOLTRIX_GENIE 0x2e
 #define BTTV_TERRATVRADIO  0x2f
 #define BTTV_DYNALINK      0x30
+#define BTTV_GVBCTV3PCI    0x31
+#define BTTV_PXELVWPLTVPAK 0x32
+#define BTTV_EAGLE         0x33
+#define BTTV_PINNACLESTUDIO 0x34
+
+/* i2c address list */
+#define I2C_TSA5522        0xc2
+#define I2C_TDA7432        0x8a
+#define I2C_TDA8425        0x82
+#define I2C_TDA9840        0x84
+#define I2C_TDA9850        0xb6 /* also used by 9855,9873 */
+#define I2C_TDA9875        0xb0
+#define I2C_HAUPEE         0xa0
+#define I2C_STBEE          0xae
+#define I2C_VHX            0xc0
+#define I2C_MSP3400        0x80
+#define I2C_TEA6300        0x80
+#define I2C_DPL3518       0x84
+
+/* more card-specific defines */
+#define PT2254_L_CHANEL 0x10
+#define PT2254_R_CHANEL 0x08
+#define PT2254_DBS_IN_2 0x400
+#define PT2254_DBS_IN_10 0x20000
+#define WINVIEW_PT2254_CLK  0x40
+#define WINVIEW_PT2254_DATA 0x20
+#define WINVIEW_PT2254_STROBE 0x80
+
+struct bttv;
 
 struct tvcard
 {
@@ -103,15 +109,9 @@ struct tvcard
         u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
         u32 gpiomask2;   /* GPIO MUX mask */
 
-       /* look for these i2c audio chips */
-       int msp34xx:1;
-       int tda8425:1;
-       int tda9840:1;
-       int tda985x:1;
-       int tea63xx:1;
-       int tea64xx:1;
-       int tda7432:1;
-       int tda9875:1;
+       /* i2c audio flags */
+       int no_msp34xx:1;
+       int needs_tvaudio:1;
 
        /* other settings */
        int pll;
@@ -120,6 +120,7 @@ struct tvcard
 #define PLL_35   2
 
        int tuner_type;
+       void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
 };
 
 extern struct tvcard bttv_tvcards[];
@@ -127,10 +128,11 @@ extern const int bttv_num_tvcards;
 
 /* identification / initialization of the card */
 extern void bttv_idcard(struct bttv *btv);
+extern void bttv_init_card(struct bttv *btv);
 
 /* card-specific funtions */
 extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
-extern void winview_setvol(struct bttv *btv, struct video_audio *v);
+extern void bttv_hauppauge_boot_msp34xx(struct bttv *btv);
 
 /* ---------------------------------------------------------- */
 /* exported by bttv-if.c                                      */
@@ -176,6 +178,7 @@ extern int bttv_write_gpio(unsigned int card,
 extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
 
 /* i2c */
+#define I2C_CLIENTS_MAX 8
 struct i2c_algo_bit_data bttv_i2c_algo_template;
 struct i2c_adapter bttv_i2c_adap_template;
 struct i2c_client bttv_i2c_client_template;
@@ -187,234 +190,4 @@ int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
             unsigned char b2, int both);
 void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
-
-/* ---------------------------------------------------------- */
-/* bttv-driver.c                                              */
-
-/* insmod options */
-extern unsigned int bttv_verbose;
-extern unsigned int bttv_debug;
-
-/* Anybody who uses more than four? */
-#define BTTV_MAX 4
-extern int bttv_num;                   /* number of Bt848s in use */
-extern struct bttv bttvs[BTTV_MAX];
-
-
-#ifndef O_NONCAP  
-#define O_NONCAP       O_TRUNC
-#endif
-
-#define MAX_GBUFFERS   64
-#define RISCMEM_LEN    (32744*2)
-#define VBI_MAXLINES    16
-#define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
-
-#define BTTV_MAX_FBUF  0x208000
-#define I2C_CLIENTS_MAX 8
-
-struct bttv_window 
-{
-       int x, y;
-       ushort width, height;
-       ushort bpp, bpl;
-       ushort swidth, sheight;
-       unsigned long vidadr;
-       ushort freq;
-       int norm;
-       int interlace;
-       int color_fmt;
-       ushort depth;
-};
-
-struct bttv_pll_info {
-       unsigned int pll_ifreq;    /* PLL input frequency        */
-       unsigned int pll_ofreq;    /* PLL output frequency       */
-       unsigned int pll_crystal;  /* Crystal used for input     */
-       unsigned int pll_current;  /* Currently programmed ofreq */
-};
-
-struct bttv_gbuf {
-       int stat;
-#define GBUFFER_UNUSED       0
-#define GBUFFER_GRABBING     1
-#define GBUFFER_DONE         2
-#define GBUFFER_ERROR        3
-       struct timeval tv;
-       
-       u16 width;
-       u16 height;
-       u16 fmt;
-       
-       u32 *risc;
-       unsigned long ro;
-       unsigned long re;
-};
-
-struct bttv {
-       struct video_device video_dev;
-       struct video_device radio_dev;
-       struct video_device vbi_dev;
-       struct video_picture picture;           /* Current picture params */
-       struct video_audio audio_dev;           /* Current audio params */
-
-       spinlock_t s_lock;
-        struct semaphore lock;
-       int user;
-       int capuser;
-
-       /* i2c */
-       struct i2c_adapter         i2c_adap;
-       struct i2c_algo_bit_data   i2c_algo;
-       struct i2c_client          i2c_client;
-       int                        i2c_state, i2c_ok;
-       struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];
-
-        int tuner_type;
-        int channel;
-        
-        unsigned int nr;
-       unsigned short id;
-       struct pci_dev *dev;
-       unsigned int irq;          /* IRQ used by Bt848 card */
-       unsigned char revision;
-       unsigned long bt848_adr;      /* bus address of IO mem returned by PCI BIOS */
-       unsigned char *bt848_mem;   /* pointer to mapped IO memory */
-       unsigned long busriscmem; 
-       u32 *riscmem;
-  
-       unsigned char *vbibuf;
-       struct bttv_window win;
-       int fb_color_ctl;
-       int type;            /* card type  */
-       int cardid;
-       int audio;           /* audio mode */
-       int audio_chip;      /* set to one of the chips supported by bttv.c */
-       int radio;
-
-       u32 *risc_jmp;
-       u32 *vbi_odd;
-       u32 *vbi_even;
-       u32 bus_vbi_even;
-       u32 bus_vbi_odd;
-        wait_queue_head_t vbiq;
-       wait_queue_head_t capq;
-       int vbip;
-
-       u32 *risc_scr_odd;
-       u32 *risc_scr_even;
-       u32 risc_cap_odd;
-       u32 risc_cap_even;
-       int scr_on;
-       int vbi_on;
-       struct video_clip *cliprecs;
-
-       struct bttv_gbuf *gbuf;
-       int gqueue[MAX_GBUFFERS];
-       int gq_in,gq_out,gq_grab,gq_start;
-        char *fbuffer;
-
-       struct bttv_pll_info pll;
-       unsigned int Fsc;
-       unsigned int field;
-       unsigned int last_field; /* number of last grabbed field */
-       int i2c_command;
-       int triton1;
-
-       int errors;
-       int needs_restart;
-
-       wait_queue_head_t gpioq;
-       int shutdown;
-};
-#endif
-
-#if defined(__powerpc__) /* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
-{
-        __asm__ __volatile__ ("stwbrx %1,0,%2" : \
-                            "=m" (*addr) : "r" (val), "r" (addr));
-      __asm__ __volatile__ ("eieio" : : : "memory");
-}
-
-#define btwrite(dat,adr)  io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat))
-#define btread(adr)       ld_le32((unsigned *)(btv->bt848_mem+(adr)))
-#else
-#define btwrite(dat,adr)    writel((dat), (char *) (btv->bt848_mem+(adr)))
-#define btread(adr)         readl(btv->bt848_mem+(adr))
-#endif
-
-#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-/* bttv ioctls */
-
-#define BTTV_READEE            _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256])
-#define BTTV_WRITEE            _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256])
-#define BTTV_FIELDNR           _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
-#define BTTV_PLLSET            _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info)
-#define BTTV_BURST_ON          _IOR('v' , BASE_VIDIOCPRIVATE+4, int)
-#define BTTV_BURST_OFF         _IOR('v' , BASE_VIDIOCPRIVATE+5, int)
-#define BTTV_VERSION           _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
-#define BTTV_PICNR             _IOR('v' , BASE_VIDIOCPRIVATE+7, int)
-#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
-
-#define AUDIO_TUNER        0x00
-#define AUDIO_RADIO        0x01
-#define AUDIO_EXTERN       0x02
-#define AUDIO_INTERN       0x03
-#define AUDIO_OFF          0x04 
-#define AUDIO_ON           0x05
-#define AUDIO_MUTE         0x80
-#define AUDIO_UNMUTE       0x81
-
-#define TDA9850            0x01
-#define TDA9840            0x02
-#define TDA8425            0x03
-#define TEA6300            0x04
-
-#define I2C_TSA5522        0xc2
-#define I2C_TDA7432        0x8a
-#define I2C_TDA8425        0x82
-#define I2C_TDA9840        0x84
-#define I2C_TDA9850        0xb6 /* also used by 9855,9873 */
-#define I2C_TDA9875        0xb0
-#define I2C_HAUPEE         0xa0
-#define I2C_STBEE          0xae
-#define I2C_VHX            0xc0
-#define I2C_MSP3400        0x80
-#define I2C_TEA6300        0x80
-#define I2C_DPL3518       0x84
-
-#ifndef HAVE_TVAUDIO
-#define TDA9840_SW         0x00
-#define TDA9840_LVADJ      0x02
-#define TDA9840_STADJ      0x03
-#define TDA9840_TEST       0x04
-#endif
-
-#define PT2254_L_CHANEL 0x10
-#define PT2254_R_CHANEL 0x08
-#define PT2254_DBS_IN_2 0x400
-#define PT2254_DBS_IN_10 0x20000
-#define WINVIEW_PT2254_CLK  0x40
-#define WINVIEW_PT2254_DATA 0x20
-#define WINVIEW_PT2254_STROBE 0x80
-
-struct bttv_just_hacking {
-       int             height,width;     /* size */
-       unsigned        int format;       /* should be VIDEO_PALETTE_* */
-       long            buf;
-       int             len;
-};
-
-#define BTTV_JUST_HACKING       _IOR('v' , BASE_VIDIOCPRIVATE+31,struct bttv_just_hacking)
-
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#endif /* _BTTV_H_ */
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
new file mode 100644 (file)
index 0000000..4676ee6
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+    bttv - Bt848 frame grabber driver
+
+    bttv's *private* header file  --  nobody else than bttv itself
+    should ever include this file.
+
+    Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BTTVP_H_
+#define _BTTVP_H_
+
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,48)
+
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "bt848.h"
+#include "bttv.h"
+#include "audiochip.h"
+
+#ifdef __KERNEL__
+
+/* ---------------------------------------------------------- */
+/* bttv-driver.c                                              */
+
+/* insmod options */
+extern unsigned int bttv_verbose;
+extern unsigned int bttv_debug;
+extern unsigned int bttv_gpio;
+extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
+
+/* Anybody who uses more than four? */
+#define BTTV_MAX 4
+extern int bttv_num;                   /* number of Bt848s in use */
+extern struct bttv bttvs[BTTV_MAX];
+
+
+#ifndef O_NONCAP  
+#define O_NONCAP       O_TRUNC
+#endif
+
+#define MAX_GBUFFERS   64
+#define RISCMEM_LEN    (32744*2)
+#define VBI_MAXLINES    16
+#define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
+
+#define BTTV_MAX_FBUF  0x208000
+
+struct bttv_window 
+{
+       int x, y;
+       ushort width, height;
+       ushort bpp, bpl;
+       ushort swidth, sheight;
+       unsigned long vidadr;
+       ushort freq;
+       int norm;
+       int interlace;
+       int color_fmt;
+       ushort depth;
+};
+
+struct bttv_pll_info {
+       unsigned int pll_ifreq;    /* PLL input frequency        */
+       unsigned int pll_ofreq;    /* PLL output frequency       */
+       unsigned int pll_crystal;  /* Crystal used for input     */
+       unsigned int pll_current;  /* Currently programmed ofreq */
+};
+
+struct bttv_gbuf {
+       int stat;
+#define GBUFFER_UNUSED       0
+#define GBUFFER_GRABBING     1
+#define GBUFFER_DONE         2
+#define GBUFFER_ERROR        3
+       struct timeval tv;
+       
+       u16 width;
+       u16 height;
+       u16 fmt;
+       
+       u32 *risc;
+       unsigned long ro;
+       unsigned long re;
+};
+
+struct bttv {
+       struct video_device video_dev;
+       struct video_device radio_dev;
+       struct video_device vbi_dev;
+       struct video_picture picture;           /* Current picture params */
+       struct video_audio audio_dev;           /* Current audio params */
+
+       spinlock_t s_lock;
+        struct semaphore lock;
+       int user;
+       int capuser;
+
+       /* i2c */
+       struct i2c_adapter         i2c_adap;
+       struct i2c_algo_bit_data   i2c_algo;
+       struct i2c_client          i2c_client;
+       int                        i2c_state, i2c_rc;
+       struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];
+
+        int tuner_type;
+        int channel;
+        
+        unsigned int nr;
+       unsigned short id;
+       struct pci_dev *dev;
+       unsigned int irq;          /* IRQ used by Bt848 card */
+       unsigned char revision;
+       unsigned long bt848_adr;      /* bus address of IO mem returned by PCI BIOS */
+       unsigned char *bt848_mem;   /* pointer to mapped IO memory */
+       unsigned long busriscmem; 
+       u32 *riscmem;
+  
+       unsigned char *vbibuf;
+       struct bttv_window win;
+       int fb_color_ctl;
+       int type;            /* card type  */
+       int cardid;
+       int audio;           /* audio mode */
+       int audio_chip;      /* set to one of the chips supported by bttv.c */
+       int radio;
+
+       u32 *risc_jmp;
+       u32 *vbi_odd;
+       u32 *vbi_even;
+       u32 bus_vbi_even;
+       u32 bus_vbi_odd;
+        wait_queue_head_t vbiq;
+       wait_queue_head_t capq;
+       int vbip;
+
+       u32 *risc_scr_odd;
+       u32 *risc_scr_even;
+       u32 risc_cap_odd;
+       u32 risc_cap_even;
+       int scr_on;
+       int vbi_on;
+       struct video_clip *cliprecs;
+
+       struct bttv_gbuf *gbuf;
+       int gqueue[MAX_GBUFFERS];
+       int gq_in,gq_out,gq_grab,gq_start;
+        char *fbuffer;
+
+       struct bttv_pll_info pll;
+       unsigned int Fsc;
+       unsigned int field;
+       unsigned int last_field; /* number of last grabbed field */
+       int i2c_command;
+       int triton1;
+
+       int errors;
+       int needs_restart;
+
+       wait_queue_head_t gpioq;
+       int shutdown;
+};
+#endif
+
+#if defined(__powerpc__) /* big-endian */
+extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
+{
+        __asm__ __volatile__ ("stwbrx %1,0,%2" : \
+                            "=m" (*addr) : "r" (val), "r" (addr));
+      __asm__ __volatile__ ("eieio" : : : "memory");
+}
+
+#define btwrite(dat,adr)  io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat))
+#define btread(adr)       ld_le32((unsigned *)(btv->bt848_mem+(adr)))
+#else
+#define btwrite(dat,adr)    writel((dat), (char *) (btv->bt848_mem+(adr)))
+#define btread(adr)         readl(btv->bt848_mem+(adr))
+#endif
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+/* bttv ioctls */
+
+#define BTTV_READEE            _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256])
+#define BTTV_WRITEE            _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256])
+#define BTTV_FIELDNR           _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
+#define BTTV_PLLSET            _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info)
+#define BTTV_BURST_ON          _IOR('v' , BASE_VIDIOCPRIVATE+4, int)
+#define BTTV_BURST_OFF         _IOR('v' , BASE_VIDIOCPRIVATE+5, int)
+#define BTTV_VERSION           _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+#define BTTV_PICNR             _IOR('v' , BASE_VIDIOCPRIVATE+7, int)
+#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
+
+#define TDA9850            0x01
+#define TDA9840            0x02
+#define TDA8425            0x03
+#define TEA6300            0x04
+
+#endif /* _BTTVP_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/id.h b/drivers/media/video/id.h
new file mode 100644 (file)
index 0000000..d1f99ee
--- /dev/null
@@ -0,0 +1,26 @@
+/* FIXME: this temporarely, until these are included in linux/i2c-id.h */
+
+/* drivers */
+#ifndef  I2C_DRIVERID_TVMIXER
+# define I2C_DRIVERID_TVMIXER I2C_DRIVERID_EXP0
+#endif
+#ifndef  I2C_DRIVERID_TVAUDIO
+# define I2C_DRIVERID_TVAUDIO I2C_DRIVERID_EXP1
+#endif
+
+/* chips */
+#ifndef  I2C_DRIVERID_DPL3518
+# define I2C_DRIVERID_DPL3518 I2C_DRIVERID_EXP2
+#endif
+#ifndef  I2C_DRIVERID_TDA9873
+# define I2C_DRIVERID_TDA9873 I2C_DRIVERID_EXP3
+#endif
+#ifndef  I2C_DRIVERID_TDA9875
+# define I2C_DRIVERID_TDA9875 I2C_DRIVERID_EXP0+4
+#endif
+#ifndef  I2C_DRIVERID_PIC16C54_PV951
+# define I2C_DRIVERID_PIC16C54_PV951 I2C_DRIVERID_EXP0+5
+#endif
+#ifndef  I2C_DRIVERID_TDA7432
+# define I2C_DRIVERID_TDA7432 I2C_DRIVERID_EXP0+6
+#endif
index 2d2b1e89c1de9f75428f5543fb4fe90e3a64a87c..385beb49c64e63120498dbf46f459ec887106f5f 100644 (file)
@@ -88,8 +88,10 @@ struct msp3400c {
        int norm;
        int stereo;
        int nicam_on;
+       int acb;
        int main, second;       /* sound carrier */
 
+       int muted;
        int left, right;        /* volume */
        int bass, treble;
 
@@ -299,6 +301,43 @@ static struct CARRIER_DETECT carrier_detect_65[] = {
 
 #define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
 
+/* ----------------------------------------------------------------------- */
+
+#define SCART_MASK    0
+#define SCART_IN1     1
+#define SCART_IN2     2
+#define SCART_IN1_DA  3
+#define SCART_IN2_DA  4
+#define SCART_IN3     5
+#define SCART_IN4     6
+#define SCART_MONO    7
+#define SCART_MUTE    8
+
+static int scarts[3][9] = {
+  /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
+  {  0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
+  {  0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+  {  0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+};
+
+static char *scart_names[] = {
+  "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+};
+
+static void
+msp3400c_set_scart(struct i2c_client *client, int in, int out)
+{
+       struct msp3400c *msp = client->data;
+
+       if (-1 == scarts[out][in])
+               return;
+
+       dprintk("msp34xx: scart switch: %s => %d\n",scart_names[in],out);
+       msp->acb &= ~scarts[out][SCART_MASK];
+       msp->acb |=  scarts[out][in];
+       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
+}
+
 /* ------------------------------------------------------------------------ */
 
 static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
@@ -310,18 +349,21 @@ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
        msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
 }
 
-static void msp3400c_setvolume(struct i2c_client *client, int left, int right)
+static void msp3400c_setvolume(struct i2c_client *client,
+                              int muted, int left, int right)
 {
-       int vol,val,balance;
+       int vol = 0,val = 0,balance = 0;
 
-       vol     = (left > right) ? left : right;
-       val     = (vol * 0x73 / 65535) << 8;
-       balance = 0;
-       if (vol > 0)
+       if (!muted) {
+               vol     = (left > right) ? left : right;
+               val     = (vol * 0x73 / 65535) << 8;
+       }
+       if (vol > 0) {
                balance = ((right-left) * 127) / vol;
+       }
 
-       dprintk("msp34xx: setvolume: %d:%d 0x%02x 0x%02x\n",
-               left,right,val>>8,balance);
+       dprintk("msp34xx: setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
+               muted ? "on" : "off", left, right, val>>8, balance);
        msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
        msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
        /* scart - on/off only */
@@ -470,11 +512,8 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode)
                if (msp->mode == MSP_MODE_AM_NICAM) {
                        dprintk("msp3400: switching to AM mono\n");
                        /* AM mono decoding is handled by tuner, not MSP chip */
-                       /* so let's redirect sound from tuner via SCART */
-                       /* volume prescale for SCART */
-                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
-                       /* SCART switching control register*/
-                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, 0xe900);
+                       /* SCART switching control register */
+                       msp3400c_set_scart(client,SCART_MONO,0);
                        src = 0x0200;
                        break;
                }
@@ -711,7 +750,7 @@ static int msp3400c_thread(void *data)
                
        restart:
                msp->restart = 0;
-               msp3400c_setvolume(client, 0, 0);
+               msp3400c_setvolume(client, msp->muted, 0, 0);
                msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
                val1 = val2 = 0;
                max1 = max2 = -1;
@@ -829,6 +868,8 @@ static int msp3400c_thread(void *data)
                                msp->nicam_on = 0;
                                msp3400c_setstereo(client, VIDEO_SOUND_MONO);
                                msp3400c_setcarrier(client, msp->second, msp->main);
+                               /* volume prescale for SCART (AM mono input) */
+                               msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
                                msp->watch_stereo = 1;
                        } else if (max2 == 0 && msp->nicam) {
                                /* D/K NICAM */
@@ -854,7 +895,7 @@ static int msp3400c_thread(void *data)
                }
 
                /* unmute */
-               msp3400c_setvolume(client, msp->left, msp->right);
+               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 
                if (msp->watch_stereo)
                        mod_timer(&msp->wake_stereo, jiffies+5*HZ);
@@ -941,9 +982,6 @@ static int msp3410d_thread(void *data)
                if (msp->rmmod || signal_pending(current))
                        goto done;
 
-               if (VIDEO_MODE_RADIO == msp->norm)
-                       continue;  /* nothing to do */
-       
                msp->active = 1;
 
                if (msp->watch_stereo) {
@@ -966,6 +1004,11 @@ static int msp3410d_thread(void *data)
                /* put into sane state (and mute) */
                msp3400c_reset(client);
 
+               /* set various prescales */
+               msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */
+               msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
+               msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */
+
                /* start autodetect */
                switch (msp->norm) {
                case VIDEO_MODE_PAL:
@@ -978,7 +1021,11 @@ static int msp3410d_thread(void *data)
                        break;
                case VIDEO_MODE_SECAM: 
                        mode = 0x0003;
-                       std = 1;
+                       std  = 1;
+                       break;
+               case VIDEO_MODE_RADIO: 
+                       mode = 0x0003;
+                       std  = 0x0040;
                        break;
                default:
                        mode = 0x0003;
@@ -987,8 +1034,7 @@ static int msp3410d_thread(void *data)
                }
                msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
                msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
-               msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403);
-               msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00);
+
                if (debug) {
                        int i;
                        for (i = 0; modelist[i].name != NULL; i++)
@@ -1019,7 +1065,7 @@ static int msp3410d_thread(void *data)
                        }
                }
                for (i = 0; modelist[i].name != NULL; i++)
-                        if (modelist[i].retval == val)
+                       if (modelist[i].retval == val)
                                break;
                dprintk("msp3410: current mode: %s (0x%04x)\n",
                        modelist[i].name ? modelist[i].name : "unknown",
@@ -1035,11 +1081,24 @@ static int msp3410d_thread(void *data)
                        msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
                }
 
-               /* set prescale / stereo */
+               /* set stereo */
                switch (val) {
+               case 0x0008: /* B/G NICAM */
+               case 0x000a: /* I NICAM */
+                       if (val == 0x0008)
+                               msp->mode = MSP_MODE_FM_NICAM1;
+                       else
+                               msp->mode = MSP_MODE_FM_NICAM2;
+                       /* just turn on stereo */
+                       msp->stereo = VIDEO_SOUND_STEREO;
+                       msp->nicam_on = 1;
+                       msp->watch_stereo = 1;
+                       msp3400c_setstereo(client,VIDEO_SOUND_STEREO);
+                       break;
                case 0x0009:                    
                        msp->mode = MSP_MODE_AM_NICAM;
                        msp->stereo = VIDEO_SOUND_MONO;
+                       msp->nicam_on = 1;
                        msp3400c_setstereo(client,VIDEO_SOUND_MONO);
                        msp->watch_stereo = 1;
                        break;
@@ -1047,26 +1106,31 @@ static int msp3410d_thread(void *data)
                        /* just turn on stereo */
                        msp->mode   = MSP_MODE_BTSC;
                        msp->stereo = VIDEO_SOUND_STEREO;
+                       msp->nicam_on = 0;
                        msp->watch_stereo = 1;
                        msp3400c_setstereo(client,VIDEO_SOUND_STEREO);
-                       /* set prescale */
-                       msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
+                       break;
+               case 0x0040: /* FM radio */
+                       msp->mode   = MSP_MODE_FM_RADIO;
+                       msp->stereo = VIDEO_SOUND_STEREO;
+                       msp->nicam_on = 0;
+                       msp->watch_stereo = 0;
+                       /* scart routing */
+                       msp3400c_set_scart(client,SCART_IN2,0);
+                       msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);
                        break;
                case 0x0003:
                        msp->mode   = MSP_MODE_FM_TERRA;
                        msp->stereo = VIDEO_SOUND_MONO;
+                       msp->nicam_on = 0;
                        msp->watch_stereo = 1;
-                       /* fall */
-               default:
-                       msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
-                       msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */
                        break;
                }
-
+               
                /* unmute */
                msp3400c_setbass(client, msp->bass);
                msp3400c_settreble(client, msp->treble);
-               msp3400c_setvolume(client, msp->left, msp->right);
+               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 
                if (msp->watch_stereo)
                        mod_timer(&msp->wake_stereo, jiffies+HZ);
@@ -1093,22 +1157,18 @@ static int msp_probe(struct i2c_adapter *adap);
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
 static struct i2c_driver driver = {
-        "i2c msp3400 driver",
-        I2C_DRIVERID_MSP3400,
-        I2C_DF_NOTIFY,
-        msp_probe,
-        msp_detach,
-        msp_command,
+        name:           "i2c msp3400 driver",
+        id:             I2C_DRIVERID_MSP3400,
+        flags:          I2C_DF_NOTIFY,
+        attach_adapter: msp_probe,
+        detach_client:  msp_detach,
+        command:        msp_command,
 };
 
 static struct i2c_client client_template = 
 {
-        "unset",
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
+       name:   "(unset)",
+        driver: &driver,
 };
 
 static int msp_attach(struct i2c_adapter *adap, int addr,
@@ -1150,8 +1210,9 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
        }
     
        rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
-       rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
-       if (0 == rev1 && 0 == rev2) {
+       if (-1 != rev1)
+               rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+       if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {
                kfree(msp);
                printk("msp3400: error while reading chip version\n");
                return -1;
@@ -1180,7 +1241,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
        msp->wake_stereo.data     = (unsigned long)msp;
 
        /* hello world :-) */
-       printk(KERN_INFO "msp3400: init: chip=%s",c->name);
+       printk(KERN_INFO "msp34xx: init: chip=%s",c->name);
        if (msp->nicam)
                printk(", has NICAM support");
        printk("\n");
@@ -1194,11 +1255,6 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
        msp->notify = NULL;
        wake_up_interruptible(&msp->wq);
 
-#ifdef REGISTER_MIXER
-       if ((msp->mixer_num = register_sound_mixer(&msp3400c_mixer_fops,mixer)) < 0)
-               printk(KERN_ERR "msp3400c: cannot allocate mixer device\n");
-#endif
-
        /* update our own array */
        for (i = 0; i < MSP3400_MAX; i++) {
                if (NULL == msps[i]) {
@@ -1218,11 +1274,6 @@ static int msp_detach(struct i2c_client *client)
        struct msp3400c *msp  = (struct msp3400c*)client->data;
        int i;
        
-#ifdef REGISTER_MIXER
-       if (msp->mixer_num >= 0)
-               unregister_sound_mixer(msp->mixer_num);
-#endif
-
        /* shutdown control thread */
        del_timer(&msp->wake_stereo);
        if (msp->thread) 
@@ -1260,29 +1311,47 @@ static int msp_probe(struct i2c_adapter *adap)
 static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
 {
        struct msp3400c *msp  = (struct msp3400c*)client->data;
+        __u16           *sarg = arg;
 #if 0
        int             *iarg = (int*)arg;
-        __u16           *sarg = arg;
 #endif
 
        switch (cmd) {
 
+       case AUDC_SET_INPUT:
+#if 1
+               /* hauppauge 44xxx scart switching */
+               switch (*sarg) {
+               case AUDIO_RADIO:
+                       msp3400c_set_scart(client,SCART_IN2,0);
+                       break;
+               case AUDIO_EXTERN:
+                       msp3400c_set_scart(client,SCART_IN1,0);
+                       break;
+               default:
+                       if (*sarg & AUDIO_MUTE)
+                               msp3400c_set_scart(client,SCART_MUTE,0);
+                       break;
+               }
+#endif
+               break;
+
        case AUDC_SET_RADIO:
                msp->norm = VIDEO_MODE_RADIO;
                msp->watch_stereo=0;
                del_timer(&msp->wake_stereo);
+               dprintk("msp34xx: switching to radio mode\n");
                if (msp->simple) {
-                       msp3400c_reset(client);
-                       msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, 0x0003); /* automatic   */
-                       msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, 0x0040); /* FM Radio    */
-                       msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM prescale */
-                       msp3400c_setbass(client, msp->bass);
-                       msp3400c_settreble(client, msp->treble);
-                       msp3400c_setvolume(client, msp->left, msp->right);
+                       /* the thread will do for us */
+                       msp3400c_setvolume(client,msp->muted,0,0);
+                       if (msp->active)
+                               msp->restart = 1;
+                       wake_up_interruptible(&msp->wq);
                } else {
+                       /* set msp3400 to FM radio mode */
                        msp3400c_setmode(client,MSP_MODE_FM_RADIO);
                        msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
-                       msp3400c_setvolume(client,msp->left, msp->right);                       
+                       msp3400c_setvolume(client,msp->muted,msp->left,msp->right);                     
                }
                break;
 
@@ -1295,7 +1364,10 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
 
                va->flags |= VIDEO_AUDIO_VOLUME |
                        VIDEO_AUDIO_BASS |
-                       VIDEO_AUDIO_TREBLE;
+                       VIDEO_AUDIO_TREBLE |
+                       VIDEO_AUDIO_MUTABLE;
+               if (msp->muted)
+                       va->flags |= VIDEO_AUDIO_MUTE;
                va->volume=MAX(msp->left,msp->right);
                va->balance=(32768*MIN(msp->left,msp->right))/
                        (va->volume ? va->volume : 1);
@@ -1304,21 +1376,24 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
                va->bass = msp->bass;
                va->treble = msp->treble;
 
-               autodetect_stereo(client);
-               va->mode = msp->stereo;
+               if (msp->norm != VIDEO_MODE_RADIO) {
+                       autodetect_stereo(client);
+                       va->mode = msp->stereo;
+               }
                break;
        }
        case VIDIOCSAUDIO:
        {
                struct video_audio *va = arg;
 
+               msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
                msp->left = (MIN(65536 - va->balance,32768) *
                             va->volume) / 32768;
                msp->right = (MIN(va->balance,32768) *
                              va->volume) / 32768;
                msp->bass = va->bass;
                msp->treble = va->treble;
-               msp3400c_setvolume(client,msp->left, msp->right);
+               msp3400c_setvolume(client,msp->muted,msp->left,msp->right);
                msp3400c_setbass(client,msp->bass);
                msp3400c_settreble(client,msp->treble);
 
@@ -1334,13 +1409,14 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
        {
                struct video_channel *vc = arg;
                
+               dprintk("msp34xx: switching to TV mode\n");
                msp->norm = vc->norm;
                break;
        }
        case VIDIOCSFREQ:
        {
                /* new channel -- kick audio carrier scan */
-               msp3400c_setvolume(client,0,0);
+               msp3400c_setvolume(client,msp->muted,0,0);
                msp->watch_stereo=0;
                del_timer(&msp->wake_stereo);
                if (msp->active)
index 6b8c9063fb3622cec79123b18625471912d68e25..889856738bc3d03f3dd7f7ca08b192e64d436cb0 100644 (file)
  *                  Added I2C_DRIVERID_TDA7432
  *                     added loudness insmod control
  *  Revision: 0.1 - initial version
- *
- *  Changes:
- *  Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- *  - resource allocation fixes in tda7432_attach
  */
 
 #include <linux/module.h>
 
 #include "bttv.h"
 #include "audiochip.h"
-
-/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */
-#ifndef I2C_DRIVERID_TDA7432
-  #define I2C_DRIVERID_TDA7432 27
-#endif
-
+#include "id.h"
 
 MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>");
 MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
@@ -87,6 +78,7 @@ struct tda7432 {
        int tone;
        int lf, lr, rf, rr;
        int loud;
+       struct i2c_client c;
 };
 
 static struct i2c_driver driver;
@@ -316,19 +308,18 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr,
        struct tda7432 *t;
        struct i2c_client *client;
        d2printk("tda7432: In tda7432_attach\n");
-       client = kmalloc(sizeof *client,GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;         
+
+       t = kmalloc(sizeof *t,GFP_KERNEL);
+       if (!t)
+               return -ENOMEM;
+       memset(t,0,sizeof *t);
+
+       client = &t->c;
         memcpy(client,&client_template,sizeof(struct i2c_client));
         client->adapter = adap;
         client->addr = addr;
+       client->data = t;
        
-       client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
-       if (!t) {
-               kfree(client);
-               return -ENOMEM;
-       }
-       memset(t,0,sizeof *t);
        do_tda7432_init(client);
        MOD_INC_USE_COUNT;
        strcpy(client->name,"TDA7432");
@@ -353,7 +344,6 @@ static int tda7432_detach(struct i2c_client *client)
        i2c_detach_client(client);
        
        kfree(t);
-       kfree(client);
        MOD_DEC_USE_COUNT;
        return 0;
 }
diff --git a/drivers/media/video/tda8425.c b/drivers/media/video/tda8425.c
deleted file mode 100644 (file)
index 54f1935..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * for the TDA8425 chip (I don't know which cards have this)
- * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF A DIFFERENT
- * CHIP IS AT ADDRESS 0x82 (it relies on i2c to make sure that there is a
- * device acknowledging that address)
- *
- * Copyright (c) 1998 Greg Alexander <galexand@acm.org>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from msp3400.c, which is by Gerd Knorr
- *
- * All of this should work, though it would be nice to eventually support
- * balance (different left,right values).  Also, the chip seems (?) to have
- * two stereo inputs, so if someone has this card, could they tell me if the
- * second one can be used for anything (i.e., does it have an external input
- * that you can't hear even if you set input to composite?)
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- * - resource allocation fixes in tda8425_attach
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
-    I2C_TDA8425 >> 1,
-    I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-       normal_i2c, normal_i2c_range, 
-       probe, probe_range, 
-       ignore, ignore_range, 
-       force
-};
-
-MODULE_PARM(debug,"i");
-static int debug = 0; /* insmod parameter */
-#define dprintk  if (debug) printk
-
-
-struct tda8425 {
-       int mode;               /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */
-       int stereo;
-       __u16 left,right;
-       __u16 bass,treble;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-
-#define TDA8425_VL         0x00  /* volume left */
-#define TDA8425_VR         0x01  /* volume right */
-#define TDA8425_BA         0x02  /* bass */
-#define TDA8425_TR         0x03  /* treble */
-#define TDA8425_S1         0x08  /* switch functions */
-                                 /* values for those registers: */
-#define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
-#define TDA8425_S1_ON      0xCE  /* audio on (mute off) - "linear stereo" mode */
-
-
-/* ******************************** *
- * functions for talking to TDA8425 *
- * ******************************** */
-
-static int tda8425_write(struct i2c_client *client, int addr, int val)
-{
-       unsigned char buffer[2];
-       
-       buffer[0] = addr;
-       buffer[1] = val;
-       if (2 != i2c_master_send(client,buffer,2)) {
-               printk(KERN_WARNING "tda8425: I/O error, trying (write %d 0x%x)\n",
-                      addr, val);
-               return -1;
-       }
-       return 0;
-}
-
-static void tda8425_set(struct i2c_client *client)
-{
-       struct tda8425 *tda = client->data;
-
-       /* mode is ignored today */
-       dprintk(KERN_DEBUG "tda8425_set(%04x,%04x,%04x,%04x)\n",tda->left>>10,tda->right>>10,tda->bass>>12,tda->treble>>12);
-       tda8425_write(client, TDA8425_VL, tda->left>>10  |0xC0);
-       tda8425_write(client, TDA8425_VR, tda->right>>10 |0xC0);
-       tda8425_write(client, TDA8425_BA, tda->bass>>12  |0xF0);
-       tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0);
-}
-
-static void do_tda8425_init(struct i2c_client *client)
-{
-       struct tda8425 *tda = client->data;
-
-       tda->left=tda->right =61440;  /* 0dB */
-       tda->bass=tda->treble=24576;  /* 0dB */
-       tda->mode=AUDIO_OFF;
-       tda->stereo=1;
-       /* left=right=0x27<<10, bass=treble=0x07<<12 */
-       tda8425_write(client, TDA8425_S1, TDA8425_S1_OFF); /* mute */
-       tda8425_set(client);
-}
-
-static void tda8425_audio(struct i2c_client *client, int mode)
-{
-       struct tda8425 *tda = client->data;
-
-       /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */
-       dprintk(KERN_DEBUG "tda8425_audio:%d (T,R,E,I,O)\n",mode);
-       tda->mode=mode;
-       tda8425_write(client, TDA8425_S1,
-                     (mode==AUDIO_OFF)?TDA8425_S1_OFF:TDA8425_S1_ON);
-       /* this is the function we'll need to change if it turns out the
-        * input-selecting capabilities should be used. */
-}
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda8425_attach(struct i2c_adapter *adap, int addr,
-                         unsigned short flags, int kind)
-{
-       struct tda8425 *tda;
-       struct i2c_client *client;
-
-       client = kmalloc(sizeof *client,GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;         
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
-
-       client->data = tda = kmalloc(sizeof *tda,GFP_KERNEL);
-       if (!tda) {
-               kfree(client);
-               return -ENOMEM;
-       }
-       memset(tda,0,sizeof *tda);
-       do_tda8425_init(client);
-       MOD_INC_USE_COUNT;
-       strcpy(client->name,"TDA8425");
-       printk(KERN_INFO "tda8425: init\n");
-
-       i2c_attach_client(client);
-       return 0;
-}
-
-static int tda8425_probe(struct i2c_adapter *adap)
-{      
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
-               return i2c_probe(adap, &addr_data, tda8425_attach);
-       return 0;
-}
-
-
-static int tda8425_detach(struct i2c_client *client)
-{
-       struct tda8425 *tda  = client->data;
-    
-       do_tda8425_init(client);
-       i2c_detach_client(client);
-
-       kfree(tda);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-static int tda8425_command(struct i2c_client *client,
-                          unsigned int cmd, void *arg)
-{
-       struct tda8425 *tda = client->data;
-        __u16 *sarg = arg;
-
-       switch (cmd) {
-       case AUDC_SET_RADIO:
-               tda8425_audio(client,AUDIO_RADIO);
-               break;
-       case AUDC_SET_INPUT:
-               tda8425_audio(client,*sarg);
-               break;
-
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               va->flags |= VIDEO_AUDIO_VOLUME |
-                       VIDEO_AUDIO_BASS |
-                       VIDEO_AUDIO_TREBLE;
-               va->volume=MAX(tda->left,tda->right);
-               va->balance=(32768*MIN(tda->left,tda->right))/
-                       (va->volume ? va->volume : 1);
-               va->balance=(tda->left<tda->right)?
-                       (65535-va->balance) : va->balance;
-               va->bass = tda->bass;
-               va->treble = tda->treble;
-               break;
-       }
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               tda->left = (MIN(65536 - va->balance,32768) *
-                            va->volume) / 32768;
-               tda->right = (MIN(va->balance,32768) *
-                             va->volume) / 32768;
-               tda->bass = va->bass;
-               tda->treble = va->treble;
-               tda8425_set(client);
-               break;
-       }
-
-#if 0
-       /* --- old, obsolete interface --- */
-       case AUDC_GET_VOLUME_LEFT:
-               *sarg = tda->left;
-               break;
-       case AUDC_GET_VOLUME_RIGHT:
-               *sarg = tda->right;
-               break;
-       case AUDC_SET_VOLUME_LEFT:
-               tda->left = *sarg;
-               tda8425_set(client);
-               break;
-       case AUDC_SET_VOLUME_RIGHT:
-               tda->right = *sarg;
-               tda8425_set(client);
-               break;
-
-       case AUDC_GET_BASS:
-               *sarg = tda->bass;
-               break;
-       case AUDC_SET_BASS:
-               tda->bass = *sarg;
-               tda8425_set(client);
-               break;
-
-       case AUDC_GET_TREBLE:
-               *sarg = tda->treble;
-               break;
-       case AUDC_SET_TREBLE:
-               tda->treble = *sarg;
-               tda8425_set(client);
-               break;
-
-       case AUDC_GET_STEREO:
-               *sarg = tda->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO;
-               break;
-       case AUDC_SET_STEREO:
-               tda->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1;
-               /* TODO: make this write to the TDA9850? */
-               break;
-
-/*     case AUDC_SWITCH_MUTE:  someday, maybe -- not a lot of point to
-       case AUDC_NEWCHANNEL:   it and it would require preserving state
-       case AUDC_GET_DC:       huh?? (not used by bttv.c)
-*/
-#endif
-       default:
-               /* nothing */
-       }
-       return 0;
-}
-
-
-static struct i2c_driver driver = {
-        "i2c tda8424 driver",
-        I2C_DRIVERID_TDA8425,
-        I2C_DF_NOTIFY,
-       tda8425_probe,
-        tda8425_detach,
-        tda8425_command,
-};
-
-static struct i2c_client client_template =
-{
-        "(unset)",             /* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tda8425_init(void)
-#endif
-{
-       i2c_add_driver(&driver);
-       return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-       i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tda985x.c b/drivers/media/video/tda985x.c
deleted file mode 100644 (file)
index 2bf1618..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * For the TDA9850 and TDA9855 chips
- * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used 
- * on STB cards.  Other cards probably use these chips as well.)
- * This driver will not complain if used with any 
- * other i2c device with the same address.
- *
- * Copyright (c) 1999 Gerd Knorr
- * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com) 
- * This code is placed under the terms of the GNU General Public License
- * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
- * Which was based on tda8425.c by Greg Alexander (c) 1998
- *
- * Contributors:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * OPTIONS:
- * debug   - set to 1 if you'd like to see debug messages
- *         - set to 2 if you'd like to be flooded with debug messages
- * chip    - set to 9850 or 9855 to select your chip (default 9855)
- *
- * TODO:
- *   Fix channel change bug - sound goes out when changeing channels, mute
- *                            and unmote to fix. - Is this still here?
- *   Fine tune sound
- *   Get rest of capabilities into video_audio struct...
- *
- *  Revision  0.6 - resource allocation fixes in tda985x_attach (08/14/2000)
- *  Revision  0.5 - cleaned up debugging messages, added debug level=2 
- *  Revision: 0.4 - check for correct chip= insmod value
- *                  also cleaned up comments a bit
- *  Revision: 0.3 - took out extraneous tda985x_write in tda985x_command
- *  Revision: 0.2 - added insmod option chip=
- *  Revision: 0.1 - original version
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-MODULE_PARM(debug,"i");
-MODULE_PARM(chip,"i");
-MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855");
-
-static int debug = 0;  /* insmod parameter */
-static int chip = 9855;        /* insmod parameter */
-
-/* Addresses to scan */
-#define I2C_TDA985x_L        0xb4
-#define I2C_TDA985x_H        0xb6
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {
-       I2C_TDA985x_L >> 1,
-       I2C_TDA985x_H >> 1,
-       I2C_CLIENT_END
-};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-       normal_i2c, normal_i2c_range, 
-       probe, probe_range, 
-       ignore, ignore_range, 
-       force
-};
-
-/* This is a superset of the TDA9850 and TDA9855 members */
-
-struct tda985x {
-       int addr;
-       int rvol, lvol;
-       int bass, treble, sub;
-       int c4, c5, c6, c7;
-       int a1, a2, a3;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-#define dprintk  if (debug) printk
-#define d2printk if (debug == 2) printk
-
-/* The TDA9850 and TDA9855 are both made by Philips Semiconductor
- * http://www.semiconductors.philips.com
- * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder
- * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor
- *
- * The TDA9850 has more or less a subset of the functions that the TDA9855
- * has.  As a result, we can re-use many of these defines.  Anything with
- * TDA9855 is specific to that chip, anything with TDA9850 is specific
- * to that chip, and anything with TDA985x is valid for either.
- *
- * To complicate things further, the TDA9850 uses labels C1 through C4
- * for subaddresses 0x04 through 0x07, while the TDA9855 uses
- * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing.
- * To help keep things straight, I have renamed the various C[1,4] labels
- * to C[4,7] so that the numerical label matches the hex value of the
- * subaddress for both chips.  At least the A[1,3] labels line up.  :)
- */ 
-
-               /* subaddresses for TDA9855 */
-#define TDA9855_VR     0x00 /* Volume, right */
-#define TDA9855_VL     0x01 /* Volume, left */
-#define TDA9855_BA     0x02 /* Bass */
-#define TDA9855_TR     0x03 /* Treble */
-#define TDA9855_SW     0x04 /* Subwoofer - not connected on DTV2000 */
-
-               /* subaddresses for TDA9850 */
-#define TDA9850_C4     0x04 /* Control 1 for TDA9850 */
-
-               /* subaddesses for both chips */
-#define TDA985x_C5     0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
-#define TDA985x_C6     0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
-#define TDA985x_C7     0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
-#define TDA985x_A1     0x08 /* Alignment 1 for both chips */
-#define TDA985x_A2     0x09 /* Alignment 2 for both chips */
-#define TDA985x_A3     0x0a /* Alignment 3 for both chips */
-
-               /* Masks for bits in TDA9855 subaddresses */
-/* 0x00 - VR in TDA9855 */
-/* 0x01 - VL in TDA9855 */
-/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
- * in 1dB steps - mute is 0x27 */
-
-
-/* 0x02 - BA in TDA9855 */ 
-/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
- * in .5dB steps - 0 is 0x0E */
-
-
-/* 0x03 - TR in TDA9855 */
-/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
- * in 3dB steps - 0 is 0x7 */
-
-               /* Masks for bits in both chips' subaddresses */
-/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
-/* Unique to TDA9855: */
-/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
- * in 3dB steps - mute is 0x0 */
-/* Unique to TDA9850: */
-/* lower 4 bits control stereo noise threshold, over which stereo turns off
- * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
-
-
-/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
-/* Unique to TDA9855: */
-#define TDA9855_MUTE   1<<7 /* GMU, Mute at outputs */
-#define TDA9855_AVL    1<<6 /* AVL, Automatic Volume Level */
-#define TDA9855_LOUD   1<<5 /* Loudness, 1==off */
-#define TDA9855_SUR    1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
-                            /* Bits 0 to 3 select various combinations
-                              * of line in and line out, only the 
-                              * interesting ones are defined */
-#define TDA9855_EXT    1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
-#define TDA9855_INT    0    /* Selects inputs LOR and LOL.  (internal) */
-
-/* Unique to TDA9850:  */
-/* lower 4 bits contol SAP noise threshold, over which SAP turns off
- * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
-
-
-/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
-/* Common to TDA9855 and TDA9850: */
-#define TDA985x_SAP    3<<6 /* Selects SAP output, mute if not received */
-#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */
-#define TDA985x_MONO   0    /* Forces Mono output */
-#define TDA985x_LMU    1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
-
-/* Unique to TDA9855: */
-#define TDA9855_TZCM   1<<5 /* If set, don't mute till zero crossing */
-#define TDA9855_VZCM   1<<4 /* If set, don't change volume till zero crossing*/
-#define TDA9855_LINEAR 0    /* Linear Stereo */
-#define TDA9855_PSEUDO 1    /* Pseudo Stereo */
-#define TDA9855_SPAT_30        2    /* Spatial Stereo, 30% anti-phase crosstalk */
-#define TDA9855_SPAT_50        3    /* Spatial Stereo, 52% anti-phase crosstalk */
-#define TDA9855_E_MONO 7    /* Forced mono - mono select elseware, so useless*/
-
-
-/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
-/* Common to both TDA9855 and TDA9850: */
-/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
- * in .5dB steps -  0dB is 0x7 */
-
-
-/* 0x08, 0x09 - A1 and A2 (read/write) */
-/* Common to both TDA9855 and TDA9850: */
-/* lower 5 bites are wideband and spectral expander alignment
- * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
-#define TDA985x_STP    1<<5 /* Stereo Pilot/detect (read-only) */
-#define TDA985x_SAPP   1<<6 /* SAP Pilot/detect (read-only) */
-#define TDA985x_STS    1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
-
-
-/* 0x0a - A3 */
-/* Common to both TDA9855 and TDA9850: */
-/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
- * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
-#define TDA985x_ADJ    1<<7 /* Stereo adjust on/off (wideband and spectral */
-
-/* Unique to TDA9855: */
-/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), 
- * 1200ohm (0x1), 2100ohm (0x3) */
-
-
-/* Begin code */
-
-static int tda985x_write(struct i2c_client *client, int subaddr, int val)
-{
-       unsigned char buffer[2];
-       d2printk("tda985x: In tda985x_write\n");
-       dprintk("tda985x: Writing %d 0x%x\n", subaddr, val);
-       buffer[0] = subaddr;
-       buffer[1] = val;
-       if (2 != i2c_master_send(client,buffer,2)) {
-               printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n",
-                      subaddr, val);
-               return -1;
-       }
-       return 0;
-}
-
-static int tda985x_read(struct i2c_client *client)
-{
-       unsigned char buffer;
-       d2printk("tda985x: In tda985x_read\n");
-       if (1 != i2c_master_recv(client,&buffer,1)) {
-               printk(KERN_WARNING "tda985x: I/O error, trying (read)\n");
-               return -1;
-       }
-       dprintk("tda985x: Read 0x%02x\n", buffer); 
-       return buffer;
-}
-
-static int tda985x_set(struct i2c_client *client)
-{
-       struct tda985x *t = client->data;
-       unsigned char buf[16];
-       d2printk("tda985x: In tda985x_set\n");
-       
-       if (chip == 9855)
-       {
-               dprintk(KERN_INFO 
-                       "tda985x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
-                       t->rvol,t->lvol,t->bass,t->treble,t->sub,
-                       t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
-               buf[0]  = TDA9855_VR;
-               buf[1]  = t->rvol;
-               buf[2]  = t->lvol;
-               buf[3]  = t->bass;
-               buf[4]  = t->treble;
-               buf[5]  = t->sub;
-               buf[6]  = t->c5;
-               buf[7]  = t->c6;
-               buf[8]  = t->c7;
-               buf[9]  = t->a1;
-               buf[10] = t->a2;
-               buf[11] = t->a3;
-               if (12 != i2c_master_send(client,buf,12)) {
-                       printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n");
-                       return -1;
-               }
-       }
-
-       else if (chip == 9850)
-       {
-               dprintk(KERN_INFO 
-                       "tda986x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
-                        t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
-               buf[0]  = TDA9850_C4;
-               buf[1]  = t->c4;
-               buf[2]  = t->c5;
-               buf[3]  = t->c6;
-               buf[4]  = t->c7;
-               buf[5]  = t->a1;
-               buf[6]  = t->a2;
-               buf[7]  = t->a3;
-               if (8 != i2c_master_send(client,buf,8)) {
-                       printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n");
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static void do_tda985x_init(struct i2c_client *client)
-{
-       struct tda985x *t = client->data;
-       d2printk("tda985x: In tda985x_init\n");
-
-       if (chip == 9855)
-       {
-               printk("tda985x: Using tda9855 options\n");
-               t->rvol = 0x6f;         /* 0dB */
-               t->lvol = 0x6f;         /* 0dB */
-               t->bass = 0x0e;         /* 0dB */
-               t->treble = (0x07 << 1);        /* 0dB */
-               t->sub = 0x8 << 2;      /* 0dB */
-               t->c5 = TDA9855_MUTE | TDA9855_AVL | 
-                       TDA9855_LOUD | TDA9855_INT;  
-               /* Set Mute, AVL, Loudness off, Internal sound */
-               t->c6 = TDA985x_STEREO | TDA9855_LINEAR |
-                       TDA9855_TZCM | TDA9855_VZCM;
-               /* Stereo linear mode, also wait til zero crossings  */
-               t->c7 = 0x07;           /* 0dB input gain */
-       }
-
-       else if (chip == 9850)
-       {
-               printk("tda985x: Using tda9850 options\n");
-               t->c4 = 0x08;           /* Set stereo noise thresh to nominal */
-               t->c5 = 0x08;           /* Set SAP noise threshold to nominal */
-               t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */
-               t->c7 = 0x07;           /* 0dB input gain */
-       }
-
-       /* The following is valid for both chip types */        
-       t->a1 = 0x10;   /* Select nominal wideband expander */
-       t->a2 = 0x10;   /* Select nominal spectral expander and 30mV trigger */
-       t->a3 = 0x3;    /* Set: nominal timing current, 420ohm AVL attack */
-
-       tda985x_set(client);
-}
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda985x_attach(struct i2c_adapter *adap, int addr,
-                         unsigned short flags, int kind)
-{
-       struct tda985x *t;
-       struct i2c_client *client;
-       d2printk("tda985x: In tda985x_attach\n");
-       client = kmalloc(sizeof *client,GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;         
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
-       
-       client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
-       if (!t) {
-               kfree(client);
-               return -ENOMEM;
-       }
-       memset(t,0,sizeof *t);
-       do_tda985x_init(client);
-       MOD_INC_USE_COUNT;
-       strcpy(client->name,"TDA985x");
-       printk(KERN_INFO "tda985x: init\n");
-
-       i2c_attach_client(client);
-       return 0;
-}
-
-static int tda985x_probe(struct i2c_adapter *adap)
-{
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
-               return i2c_probe(adap, &addr_data, tda985x_attach);
-       return 0;
-}
-
-static int tda985x_detach(struct i2c_client *client)
-{
-       struct tda985x *t  = client->data;
-
-       do_tda985x_init(client);
-       i2c_detach_client(client);
-       
-       kfree(t);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-static int tda985x_command(struct i2c_client *client,
-                          unsigned int cmd, void *arg)
-{
-       struct tda985x *t = client->data;
-       d2printk("tda985x: In tda985x_command\n");
-#if 0
-       __u16 *sarg = arg;
-#endif
-
-       switch (cmd) {
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-               dprintk("tda985x: VIDIOCGAUDIO\n");
-               if (chip == 9855)
-               {
-                       int left,right;
-
-                       va->flags |= VIDEO_AUDIO_VOLUME |
-                               VIDEO_AUDIO_BASS |
-                               VIDEO_AUDIO_TREBLE;
-
-                       /* min is 0x27 max is 0x7f, vstep is 2e8 */
-                       left = (t->lvol-0x27)*0x2e8;
-                       right = (t->rvol-0x27)*0x2e8;
-                       va->volume=MAX(left,right);
-                       va->balance=(32768*MIN(left,right))/
-                               (va->volume ? va->volume : 1);
-                       va->balance=(left<right)?
-                               (65535-va->balance) : va->balance;
-                       va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */
-                       va->treble = ((t->treble>>1)-0x3)*0x1c71;
-               }
-
-               /* Valid for both chips: */
-               {
-                       va->mode = ((TDA985x_STP | TDA985x_SAPP) & 
-                                   tda985x_read(client)) >> 4;
-                       /* Add mono mode regardless of SAP and stereo */
-                       /* Allows forced mono */
-                       va->mode |= VIDEO_SOUND_MONO;
-               }
-
-               break; /* VIDIOCGAUDIO case */
-       }
-
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *va = arg;
-               dprintk("tda985x: VIDEOCSAUDIO\n");
-               if (chip == 9855)
-               {
-                       int left,right;
-
-                       left = (MIN(65536 - va->balance,32768) *
-                               va->volume) / 32768;
-                       right = (MIN(va->balance,32768) *
-                                va->volume) / 32768;
-                       t->lvol = left/0x2e8+0x27;
-                       t->rvol = right/0x2e8+0x27;
-                       t->bass = va->bass/0xccc+0x6;
-                       t->treble = (va->treble/0x1c71+0x3)<<1;
-                       tda985x_write(client,TDA9855_VL,t->lvol);
-                       tda985x_write(client,TDA9855_VR,t->rvol);
-                       tda985x_write(client,TDA9855_BA, t->bass);
-                       tda985x_write(client,TDA9855_TR,t->treble);
-               }
-
-               /* The following is valid for both chips */
-
-               switch (va->mode) {
-                       case VIDEO_SOUND_MONO:
-                               dprintk("tda985x: VIDEO_SOUND_MONO\n");
-                               t->c6= TDA985x_MONO | (t->c6 & 0x3f);
-                               tda985x_write(client,TDA985x_C6,t->c6);
-                               break;
-                       case VIDEO_SOUND_STEREO:
-                               dprintk("tda985x: VIDEO_SOUND_STEREO\n");
-                               t->c6= TDA985x_STEREO | (t->c6 & 0x3f);
-                               tda985x_write(client,TDA985x_C6,t->c6); 
-                               break;
-                       case VIDEO_SOUND_LANG1:
-                               dprintk("tda985x: VIDEO_SOUND_LANG1\n");
-                               t->c6= TDA985x_SAP | (t->c6 & 0x3f);
-                               tda985x_write(client,TDA985x_C6,t->c6);
-                               break;
-               } /* End of (va->mode) switch */
-               
-               break;
-
-       } /* end of VIDEOCSAUDIO case */
-
-       default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
-
-               /* nothing */
-               d2printk("tda985x: Default\n");
-
-       } /* end of (cmd) switch */
-
-       return 0;
-}
-
-
-static struct i2c_driver driver = {
-        "i2c tda985x driver",
-        I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */
-        I2C_DF_NOTIFY,
-       tda985x_probe,
-        tda985x_detach,
-        tda985x_command,
-};
-
-static struct i2c_client client_template =
-{
-        "(unset)",             /* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tda985x_init(void)
-#endif
-{
-       if ( (chip != 9850) && (chip != 9855) )
-       {
-               printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n");
-               return -EINVAL;
-       }
-       i2c_add_driver(&driver);
-       return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-       i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 7bfc319a6f34654eaf4836e21426687ba3d7743a..0cead825fd8227f367edbfa41357b09a422acfb6 100644 (file)
  * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
  * Which was based on tda8425.c by Greg Alexander (c) 1998
  *
- * Contributors:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.2)
- *
  * OPTIONS:
  * debug   - set to 1 if you'd like to see debug messages
  * 
- *  Revision  0.2 - resource allocation fixes in tda9875_attach (08/14/2000)
  *  Revision: 0.1 - original version
  */
 
 
 #include "bttv.h"
 #include "audiochip.h"
-
-/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */
-#ifndef I2C_DRIVERID_TDA9875
-  #define I2C_DRIVERID_TDA9875  28
-#endif
-
+#include "id.h"
 
 MODULE_PARM(debug,"i");
 
@@ -68,6 +59,7 @@ struct tda9875 {
        int mode;
        int rvol, lvol;
        int bass, treble;
+       struct i2c_client c;
 };
 
 
@@ -228,19 +220,18 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr,
        struct tda9875 *t;
        struct i2c_client *client;
        dprintk("In tda9875_attach\n");
-       client = kmalloc(sizeof *client,GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;         
+
+       t = kmalloc(sizeof *t,GFP_KERNEL);
+       if (!t)
+               return -ENOMEM;
+       memset(t,0,sizeof *t);
+
+       client = &t->c;
         memcpy(client,&client_template,sizeof(struct i2c_client));
         client->adapter = adap;
         client->addr = addr;
+       client->data = t;
        
-       client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
-       if (!t) {
-               kfree(client);
-               return -ENOMEM;
-       }
-       memset(t,0,sizeof *t);
        do_tda9875_init(client);
        MOD_INC_USE_COUNT;
        strcpy(client->name,"TDA9875");
@@ -265,7 +256,6 @@ static int tda9875_detach(struct i2c_client *client)
        i2c_detach_client(client);
        
        kfree(t);
-       kfree(client);
        MOD_DEC_USE_COUNT;
        return 0;
 }
diff --git a/drivers/media/video/tea6300.c b/drivers/media/video/tea6300.c
deleted file mode 100644 (file)
index 9dc13e6..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * for the TEA6300 chip (only found on Gateway STB TV/FM cards tho the best
- * of my knowledge)
- * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF THE WRONG
- * CHIP (i.e., an MSP3400) IS ON I2C ADDRESS 0x80 (it relies on i2c to
- * make sure that there is a device acknowledging that address).  This
- * is a potential problem because the MSP3400 is very popular and does
- * use this address!  You have been warned!
- *
- * Copyright (c) 1998 Greg Alexander <galexand@acm.org>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from msp3400.c, which is by Gerd Knorr
- *
- * All of this should work, though it would be nice to eventually support
- * balance (different left,right values) and, if someone ever finds a card
- * with the support (or if you're careful with a soldering iron), fade
- * (front/back).
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- * - resource allocation fixes in tea6300_attach
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-
-/* Addresses to scan */
-#define I2C_TEA6300    0x80
-static unsigned short normal_i2c[] = {
-    I2C_TEA6300 >> 1,
-    I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-       normal_i2c, normal_i2c_range, 
-       probe, probe_range, 
-       ignore, ignore_range, 
-       force
-};
-
-
-MODULE_PARM(debug,"i");
-static int debug = 0; /* insmod parameter */
-
-#define dprintk  if (debug) printk
-
-
-struct tea6300 {
-       int mode;               /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */
-       int stereo;
-       __u16 left,right;
-       __u16 bass,treble;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-#define TEA6300_VL         0x00  /* volume left */
-#define TEA6300_VR         0x01  /* volume right */
-#define TEA6300_BA         0x02  /* bass */
-#define TEA6300_TR         0x03  /* treble */
-#define TEA6300_FA         0x04  /* fader control */
-#define TEA6300_S          0x05  /* switch register */
-                                 /* values for those registers: */
-#define TEA6300_S_SA       0x01  /* stereo A input */
-#define TEA6300_S_SB       0x02  /* stereo B */
-#define TEA6300_S_SC       0x04  /* stereo C */
-#define TEA6300_S_GMU      0x80  /* general mute */
-
-
-/* ******************************** *
- * functions for talking to TEA6300 *
- * ******************************** */
-
-static int tea6300_write(struct i2c_client *client, int addr, int val)
-{
-       unsigned char buffer[2];
-
-       buffer[0] = addr;
-       buffer[1] = val;
-       if (2 != i2c_master_send(client,buffer,2)) {
-               printk(KERN_WARNING "tea6300: I/O error, trying (write %d 0x%x)\n",
-                      addr, val);
-               return -1;
-       }
-       return 0;
-}
-
-static void tea6300_set(struct i2c_client *client)
-{
-       struct tea6300 *tea = client->data;
-
-       /* mode is ignored today */
-       dprintk(KERN_DEBUG "tea6300_set(%04x,%04x,%04x,%04x)\n",tea->left>>10,tea->right>>10,tea->bass>>12,tea->treble>>12);
-       tea6300_write(client, TEA6300_VL, tea->left>>10  );
-       tea6300_write(client, TEA6300_VR, tea->right>>10 );
-       tea6300_write(client, TEA6300_BA, tea->bass>>12  );
-       tea6300_write(client, TEA6300_TR, tea->treble>>12);
-}
-
-static void do_tea6300_init(struct i2c_client *client)
-{
-       struct tea6300 *tea = client->data;
-       
-       tea->left=tea->right =49152;  /* -10dB (loud enough, but not beyond
-                                        normal line levels - so as to avoid
-                                        clipping */
-       tea->bass=tea->treble=28672;  /* 0dB */
-       tea->mode=AUDIO_OFF;
-       tea->stereo=1;
-       /* left=right=0x27<<10, bass=treble=0x07<<12 */
-       tea6300_write(client, TEA6300_FA, 0x3f         ); /* fader off */
-       tea6300_write(client, TEA6300_S , TEA6300_S_GMU); /* mute */
-       tea6300_set(client);
-}
-
-static void tea6300_audio(struct i2c_client *client, int mode)
-{
-       struct tea6300 *tea = client->data;
-       
-       /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */
-       dprintk(KERN_DEBUG "tea6300_audio:%d (T,R,E,I,O)\n",mode);
-       tea->mode=mode;
-       if (mode==AUDIO_OFF) {  /* just mute it */
-               tea6300_write(client, TEA6300_S, TEA6300_S_GMU);
-               return;
-       }
-       switch(mode) {
-               case AUDIO_TUNER:
-                       tea6300_write(client, TEA6300_S, TEA6300_S_SA);
-                       break;
-               case AUDIO_RADIO:
-                       tea6300_write(client, TEA6300_S, TEA6300_S_SB);
-                       break;
-               case AUDIO_EXTERN:
-                       tea6300_write(client, TEA6300_S, TEA6300_S_SC);
-                       break;
-       }
-}
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tea6300_attach(struct i2c_adapter *adap, int addr,
-                         unsigned short flags, int kind)
-{
-       struct tea6300 *tea;
-       struct i2c_client *client;
-
-       client = kmalloc(sizeof *client,GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;         
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
-
-       client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL);
-       if (!tea) {
-               kfree(client);
-               return -ENOMEM;
-       }
-       memset(tea,0,sizeof *tea);
-       do_tea6300_init(client);
-
-       MOD_INC_USE_COUNT;
-       strcpy(client->name,"TEA6300T");
-       printk(KERN_INFO "tea6300: initialized\n");
-
-       i2c_attach_client(client);
-       return 0;
-}
-
-static int tea6300_probe(struct i2c_adapter *adap)
-{      
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
-               return i2c_probe(adap, &addr_data, tea6300_attach);
-       return 0;
-}
-
-static int tea6300_detach(struct i2c_client *client)
-{
-       struct tea6300 *tea  = client->data;
-    
-       do_tea6300_init(client);
-       i2c_detach_client(client);
-
-       kfree(tea);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-static int
-tea6300_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       struct tea6300 *tea = client->data;
-        __u16 *sarg = arg;
-
-       switch (cmd) {
-       case AUDC_SET_RADIO:
-               tea6300_audio(client,AUDIO_RADIO);
-               break;
-       case AUDC_SET_INPUT:
-               tea6300_audio(client,*sarg);
-               break;
-
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               va->flags |= VIDEO_AUDIO_VOLUME |
-                       VIDEO_AUDIO_BASS |
-                       VIDEO_AUDIO_TREBLE;
-               va->volume=MAX(tea->left,tea->right);
-               va->balance=(32768*MIN(tea->left,tea->right))/
-                       (va->volume ? va->volume : 1);
-               va->balance=(tea->left<tea->right)?
-                       (65535-va->balance) : va->balance;
-               va->bass = tea->bass;
-               va->treble = tea->treble;
-               break;
-       }
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               tea->left = (MIN(65536 - va->balance,32768) *
-                            va->volume) / 32768;
-               tea->right = (MIN(va->balance,32768) *
-                             va->volume) / 32768;
-               tea->bass = va->bass;
-               tea->treble = va->treble;
-               tea6300_set(client);
-               break;
-       }
-#if 0
-       /* --- old, obsolete interface --- */
-       case AUDC_GET_VOLUME_LEFT:
-               *sarg = tea->left;
-               break;
-       case AUDC_GET_VOLUME_RIGHT:
-               *sarg = tea->right;
-               break;
-       case AUDC_SET_VOLUME_LEFT:
-               tea->left = *sarg;
-               tea6300_set(client);
-               break;
-       case AUDC_SET_VOLUME_RIGHT:
-               tea->right = *sarg;
-               tea6300_set(client);
-               break;
-
-       case AUDC_GET_BASS:
-               *sarg = tea->bass;
-               break;
-       case AUDC_SET_BASS:
-               tea->bass = *sarg;
-               tea6300_set(client);
-               break;
-
-       case AUDC_GET_TREBLE:
-               *sarg = tea->treble;
-               break;
-       case AUDC_SET_TREBLE:
-               tea->treble = *sarg;
-               tea6300_set(client);
-               break;
-
-       case AUDC_GET_STEREO:
-               *sarg = tea->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO;
-               break;
-       case AUDC_SET_STEREO:
-               tea->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1;
-               /* TODO: make this write to the TDA9850? */
-               break;
-
-/*     case AUDC_SWITCH_MUTE:  someday, maybe -- not a lot of point to
-       case AUDC_NEWCHANNEL:   it and it would require preserving state
-       case AUDC_GET_DC:       huh?? (not used by bttv.c)
-*/
-#endif
-       default:
-               /* nothing */
-       }
-       return 0;
-}
-
-static struct i2c_driver driver = {
-        "i2c tea6300 driver",
-        I2C_DRIVERID_TEA6300,
-        I2C_DF_NOTIFY,
-       tea6300_probe,
-        tea6300_detach,
-        tea6300_command,
-};
-
-static struct i2c_client client_template =
-{
-        "(unset)",             /* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tea6300_init(void)
-#endif
-{
-       i2c_add_driver(&driver);
-       return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-       i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
deleted file mode 100644 (file)
index 3a1d635..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * for the TEA6420 chip (only found on 3DFX (STB) TV/FM cards to the best
- * of my knowledge)
- * Copyright (C) 2000 Dave Stuart <justdave@ynn.com>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from tea6300 by . . .
- *
- * Copyright (c) 1998 Greg Alexander <galexand@acm.org>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from msp3400.c, which is by Gerd Knorr
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- * - resource allocation fixes in tea6300_attach
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-
-/* Addresses to scan */
-#define I2C_TEA6420    0x98
-static unsigned short normal_i2c[] = {
-    I2C_TEA6420 >> 1,
-    I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-       normal_i2c, normal_i2c_range, 
-       probe, probe_range, 
-       ignore, ignore_range, 
-       force
-};
-
-
-MODULE_PARM(debug,"i");
-static int debug = 0; /* insmod parameter */
-
-#define dprintk  if (debug) printk
-
-
-struct tea6420 {
-       int mode;               /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */
-       int stereo;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-#define TEA6420_S_SA       0x00  /* stereo A input */
-#define TEA6420_S_SB       0x01  /* stereo B */
-#define TEA6420_S_SC       0x02  /* stereo C */
-#define TEA6420_S_SD       0x03  /* stereo D */
-#define TEA6420_S_SE       0x04  /* stereo E */
-#define TEA6420_S_GMU      0x05  /* general mute */
-
-
-/* ******************************** *
- * functions for talking to TEA6420 *
- * ******************************** */
-
-static int tea6420_write(struct i2c_client *client, int val)
-{
-       unsigned char buffer[2];
-       int result;
-
-/*     buffer[0] = addr; */
-       buffer[0] = val;
-       result = i2c_master_send(client,buffer,1);
-       if (1 != result) {
-               printk(KERN_WARNING "tea6420: I/O error, trying (write
-0x%x) result = %d\n", val, result);
-               return -1;
-       }
-       return 0;
-}
-
-
-static void do_tea6420_init(struct i2c_client *client)
-{
-       struct tea6420 *tea = client->data;
-       
-       tea->mode=AUDIO_OFF;
-       tea->stereo=1;
-       tea6420_write(client, TEA6420_S_GMU); /* mute */
-}
-
-static void tea6420_audio(struct i2c_client *client, int mode)
-{
-       struct tea6420 *tea = client->data;
-       
-       /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */
-       dprintk(KERN_DEBUG "tea6420_audio:%d (T,R,E,I,O)\n",mode);
-       tea->mode=mode;
-       if (mode==AUDIO_OFF) {  /* just mute it */
-               tea6420_write(client, TEA6420_S_GMU);
-               return;
-       }
-       switch(mode) {
-               case AUDIO_TUNER:
-                       tea6420_write(client, TEA6420_S_SA);
-                       break;
-               case AUDIO_RADIO:
-                       tea6420_write(client, TEA6420_S_SB);
-                       break;
-               case AUDIO_EXTERN:
-                       tea6420_write(client, TEA6420_S_SC);
-                       break;
-       }
-}
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tea6420_attach(struct i2c_adapter *adap, int addr,
-                         unsigned short flags, int kind)
-{
-       struct tea6420 *tea;
-       struct i2c_client *client;
-
-       client = kmalloc(sizeof *client,GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;         
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
-
-       client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL);
-       if (!tea) {
-               kfree(client);
-               return -ENOMEM;
-       }
-       memset(tea,0,sizeof *tea);
-       do_tea6420_init(client);
-
-       MOD_INC_USE_COUNT;
-       strcpy(client->name,"TEA6420");
-       printk(KERN_INFO "tea6420: initialized\n");
-
-       i2c_attach_client(client);
-       return 0;
-}
-
-static int tea6420_probe(struct i2c_adapter *adap)
-{      
-       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
-               return i2c_probe(adap, &addr_data, tea6420_attach);
-       return 0;
-}
-
-static int tea6420_detach(struct i2c_client *client)
-{
-       struct tea6420 *tea  = client->data;
-    
-       do_tea6420_init(client);
-       i2c_detach_client(client);
-
-       kfree(tea);
-       kfree(client);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-static int
-tea6420_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-        __u16 *sarg = arg;
-
-       switch (cmd) {
-       case AUDC_SET_RADIO:
-               tea6420_audio(client,AUDIO_RADIO);
-               break;
-       case AUDC_SET_INPUT:
-               tea6420_audio(client,*sarg);
-               break;
-
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *va = arg;
-
-               va->flags |= VIDEO_AUDIO_VOLUME |
-                       VIDEO_AUDIO_BASS |
-                       VIDEO_AUDIO_TREBLE;
-/*             va->volume=MAX(tea->left,tea->right);
-               va->balance=(32768*MIN(tea->left,tea->right))/
-                       (va->volume ? va->volume : 1);
-               va->balance=(tea->left<tea->right)?
-                       (65535-va->balance) : va->balance;
-               va->bass = tea->bass;
-               va->treble = tea->treble;
-*/             break;
-       }
-       case VIDIOCSAUDIO:
-       {
-
-/*             tea->left = (MIN(65536 - va->balance,32768) *
-                            va->volume) / 32768;
-               tea->right = (MIN(va->balance,32768) *
-                             va->volume) / 32768;
-               tea->bass = va->bass;
-               tea->treble = va->treble;
-               tea6420_set(client);
-*/             break;
-       }
-
-default:
-               /* nothing */
-       }
-       return 0;
-}
-
-static struct i2c_driver driver = {
-        "i2c tea6420 driver",
-        I2C_DRIVERID_TEA6420,
-        I2C_DF_NOTIFY,
-       tea6420_probe,
-        tea6420_detach,
-        tea6420_command,
-};
-
-static struct i2c_client client_template =
-{
-        "(unset)",             /* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tea6420_init(void)
-#endif
-{
-       i2c_add_driver(&driver);
-       return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-       i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index dfbf0f6af6d99575e37551ba28eab31195587813..9316ef72ffefd362a1599c7a8886ef1e5e49eb8a 100644 (file)
@@ -113,6 +113,8 @@ static struct tunertype tuners[] = {
          16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
        { "Temic 4006FH5", TEMIC, PAL_I,
          16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, 
+       { "Alps TSCH6",Alps,NTSC,
+         16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -132,6 +134,20 @@ static int tuner_getstatus(struct i2c_client *c)
 #define TUNER_MODE      0x38
 #define TUNER_AFC       0x07
 
+#define TUNER_STEREO    0x10 /* radio mode */
+#define TUNER_SIGNAL    0x07 /* radio mode */
+
+static int tuner_signal(struct i2c_client *c)
+{
+       return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
+}
+
+static int tuner_stereo(struct i2c_client *c)
+{
+       return (tuner_getstatus (c) & TUNER_STEREO);
+}
+
+
 static int tuner_islocked (struct i2c_client *c)
 {
         return (tuner_getstatus (c) & TUNER_FL);
@@ -229,7 +245,7 @@ static void set_radio_freq(struct i2c_client *c, int freq)
        }
 
        tun=&tuners[t->type];
-       config = 0xa5;
+       config = 0xa4 /* 0xa5 */; /* bit 0 is AFC (set) vs. RF-Signal (clear) */
        div=freq + (int)(16*10.7);
        div&=0x7fff;
 
@@ -248,8 +264,12 @@ static void set_radio_freq(struct i2c_client *c, int freq)
                        printk ("tuner: PLL locked\n");
                else
                        printk ("tuner: PLL not locked\n");
-               
-               printk ("tuner: AFC: %d\n", tuner_afcstatus (c));
+
+               if (config & 1) {
+                       printk ("tuner: AFC: %d\n", tuner_afcstatus(c));
+               } else {
+                       printk ("tuner: Signal: %d\n", tuner_signal(c));
+               }
        }
 }
 /* ---------------------------------------------------------------------- */
@@ -370,6 +390,22 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                }
                return 0;
        }
+       case VIDIOCGTUNER:
+       {
+               struct video_tuner *vt = arg;
+
+               if (t->radio)
+                       vt->signal = tuner_signal(client);
+               return 0;
+       }
+       case VIDIOCGAUDIO:
+       {
+               struct video_audio *va = arg;
+               if (t->radio)
+                       va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);
+               return 0;
+       }
+       
 #if 0
        /* --- old, obsolete interface --- */
        case TUNER_SET_TVFREQ:
index 96fcd3021b4bea64fe33be278ec8aeba3131810f..1929afe0442ab4b6de0a2a79dfb4e1a220687f35 100644 (file)
@@ -36,6 +36,8 @@
 #define TUNER_ALPS_TSBB5_PAL_I         11
 #define TUNER_ALPS_TSBE5_PAL   12
 #define TUNER_ALPS_TSBC5_PAL   13
+#define TUNER_TEMIC_4006FH5_PAL        14
+#define TUNER_ALPS_TSHC6_NTSC  15
 
 #define NOTUNER 0
 #define PAL     1
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
new file mode 100644 (file)
index 0000000..5ed1a10
--- /dev/null
@@ -0,0 +1,1107 @@
+/*
+ * experimental driver for simple i2c audio chips.
+ *
+ * Copyright (c) 2000 Gerd Knorr
+ * based on code by:
+ *   Eric Sandeen (eric_sandeen@bigfoot.com) 
+ *   Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ *   Greg Alexander (galexand@acm.org)
+ *
+ * This code is placed under the terms of the GNU General Public License
+ * 
+ * OPTIONS:
+ *   debug - set to 1 if you'd like to see debug messages
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+
+#include "audiochip.h"
+#include "tvaudio.h"
+#include "id.h"
+
+
+/* ---------------------------------------------------------------------- */
+/* insmod args                                                            */
+
+MODULE_PARM(debug,"i");
+static int debug = 0;  /* insmod parameter */
+
+#define dprintk  if (debug) printk
+
+
+/* ---------------------------------------------------------------------- */
+/* our structs                                                            */
+
+#define MAXREGS 64
+
+struct CHIPSTATE;
+typedef int  (*getvalue)(int);
+typedef int  (*checkit)(struct CHIPSTATE*);
+typedef int  (*getmode)(struct CHIPSTATE*);
+typedef void (*setmode)(struct CHIPSTATE*, int mode);
+typedef void (*checkmode)(struct CHIPSTATE*);
+
+/* i2c command */
+typedef struct AUDIOCMD {
+       int             count;             /* # of bytes to send */
+       unsigned char   bytes[MAXREGS+1];  /* addr, data, data, ... */
+} audiocmd;
+
+/* chip description */
+struct CHIPDESC {
+       char       *name;             /* chip name         */
+       int        id;                /* ID */
+       int        addr_lo, addr_hi;  /* i2c address range */
+       int        registers;         /* # of registers    */
+
+       int        *insmodopt;
+       checkit    checkit;
+       int        flags;
+#define CHIP_HAS_VOLUME      1
+#define CHIP_HAS_BASSTREBLE  2
+#define CHIP_HAS_INPUTSEL    4
+
+       /* various i2c command sequences */
+       audiocmd   init;
+
+       /* which register has which value */
+       int    leftreg,rightreg,treblereg,bassreg;
+
+       /* initialize with (defaults to 65535/65535/32768/32768 */
+       int    leftinit,rightinit,trebleinit,bassinit;
+
+       /* functions to convert the values (v4l -> chip) */
+       getvalue volfunc,treblefunc,bassfunc;
+
+       /* get/set mode */
+       getmode  getmode;
+       setmode  setmode;
+
+       /* check / autoswitch audio after channel switches */
+       checkmode  checkmode;
+
+       /* input switch register + values for v4l inputs */
+       int  inputreg;
+       int  inputmap[8];
+       int  inputmute;
+};
+static struct CHIPDESC chiplist[];
+
+/* current state of the chip */
+struct CHIPSTATE {
+       struct i2c_client c;
+
+       /* index into CHIPDESC array */
+       int type;
+
+       /* shadow register set */
+       audiocmd   shadow;
+
+       /* current settings */
+       __u16 left,right,treble,bass;
+
+       /* thread */
+       struct task_struct  *thread;
+       struct semaphore    *notify;
+       wait_queue_head_t    wq;
+       int                  wake,done;
+};
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c adresses                                                           */
+
+static unsigned short normal_i2c[] = {
+       I2C_TDA8425   >> 1,
+       I2C_TEA6300   >> 1,
+       I2C_TEA6420   >> 1,
+       I2C_TDA9840   >> 1,
+       I2C_TDA985x_L >> 1,
+       I2C_TDA985x_H >> 1,
+       I2C_PIC16C54  >> 1,
+       I2C_CLIENT_END };
+static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe[2]            = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2]      = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2]           = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2]     = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2]            = { I2C_CLIENT_END, I2C_CLIENT_END };
+static struct i2c_client_address_data addr_data = {
+       normal_i2c, normal_i2c_range, 
+       probe, probe_range, 
+       ignore, ignore_range, 
+       force
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c I/O functions                                                      */
+
+static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
+{
+       unsigned char buffer[2];
+
+       if (-1 == subaddr) {
+               dprintk("%s: chip_write: 0x%x\n", chip->c.name, val);
+               chip->shadow.bytes[1] = val;
+               buffer[0] = val;
+               if (1 != i2c_master_send(&chip->c,buffer,1)) {
+                       printk(KERN_WARNING "%s: I/O error (write 0x%x)\n",
+                              chip->c.name, val);
+                       return -1;
+               }
+       } else {
+               dprintk("%s: chip_write: reg%d=0x%x\n", chip->c.name, subaddr, val);
+               chip->shadow.bytes[subaddr+1] = val;
+               buffer[0] = subaddr;
+               buffer[1] = val;
+               if (2 != i2c_master_send(&chip->c,buffer,2)) {
+                       printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n",
+                              chip->c.name, subaddr, val);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static int chip_read(struct CHIPSTATE *chip)
+{
+       unsigned char buffer;
+
+       if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
+               printk(KERN_WARNING "%s: I/O error (read)\n",
+                      chip->c.name);
+               return -1;
+       }
+       dprintk("%s: chip_read: 0x%x\n",chip->c.name,buffer); 
+       return buffer;
+}
+
+static int chip_read2(struct CHIPSTATE *chip, int subaddr)
+{
+        unsigned char write[1];
+        unsigned char read[1];
+        struct i2c_msg msgs[2] = {
+                { chip->c.addr, 0,        1, write },
+                { chip->c.addr, I2C_M_RD, 1, read  }
+        };
+        write[1] = subaddr;
+
+       if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
+               printk(KERN_WARNING "%s: I/O error (read2)\n",
+                      chip->c.name);
+               return -1;
+       }
+       dprintk("%s: chip_read2: reg%d=0x%x\n",
+               chip->c.name,subaddr,read[0]); 
+       return read[0];
+}
+
+static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
+{
+       int i;
+       
+       if (0 == cmd->count)
+               return 0;
+
+       /* update our shadow register set; print bytes if (debug > 0) */
+       dprintk("%s: chip_cmd(%s): reg=%d, data:",
+               chip->c.name,name,cmd->bytes[0]);
+       for (i = 1; i < cmd->count; i++) {
+               dprintk(" 0x%x",cmd->bytes[i]);
+               chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
+       }
+       dprintk("\n");
+
+       /* send data to the chip */
+       if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
+               printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.name, name);
+               return -1;
+       }
+       return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* kernel thread for doing i2c stuff asyncronly
+ *   right now it is used only to check the audio mode (mono/stereo/whatever)
+ *   some time after switching to another TV channel, then turn on stereo
+ *   if available, ...
+ */
+
+static int chip_thread(void *data)
+{
+        struct CHIPSTATE *chip = data;
+       struct CHIPDESC  *desc = chiplist + chip->type;
+       
+#ifdef CONFIG_SMP
+       lock_kernel();
+#endif
+       daemonize();
+       sigfillset(&current->blocked);
+       strcpy(current->comm,chip->c.name);
+       chip->thread = current;
+#ifdef CONFIG_SMP
+       unlock_kernel();
+#endif
+
+       dprintk("%s: thread started\n", chip->c.name);
+       if(chip->notify != NULL)
+               up(chip->notify);
+
+       for (;;) {
+               if (chip->done)
+                       break;
+               if (!chip->wake) {
+                       interruptible_sleep_on(&chip->wq);
+                       dprintk("%s: thread wakeup\n", chip->c.name);
+                       if (chip->done || signal_pending(current))
+                               break;
+               }
+               chip->wake = 0;
+
+               /* wait some time -- let the audio hardware
+                  figure the current mode */
+               current->state   = TASK_INTERRUPTIBLE;
+               schedule_timeout(HZ);
+               if (signal_pending(current))
+                       break;
+               if (chip->wake)
+                       continue;
+
+               dprintk("%s: thread checkmode\n", chip->c.name);
+               desc->checkmode(chip);
+       }
+
+       chip->thread = NULL;
+       dprintk("%s: thread exiting\n", chip->c.name);
+       if(chip->notify != NULL)
+               up(chip->notify);
+
+       return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda9840                */
+
+#define TDA9840_SW         0x00
+#define TDA9840_LVADJ      0x02
+#define TDA9840_STADJ      0x03
+#define TDA9840_TEST       0x04
+
+#define TDA9840_MONO       0x10
+#define TDA9840_STEREO     0x2a
+#define TDA9840_DUALA      0x12
+#define TDA9840_DUALB      0x1e
+#define TDA9840_DUALAB     0x1a
+#define TDA9840_DUALBA     0x16
+#define TDA9840_EXTERNAL   0x7a
+
+int  tda9840_getmode(struct CHIPSTATE *chip)
+{
+       return VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+               VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+}
+
+void tda9840_setmode(struct CHIPSTATE *chip, int mode)
+{
+       int update = 1;
+       int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
+       
+       switch (mode) {
+       case VIDEO_SOUND_MONO:
+               t |= TDA9840_MONO;
+               break;
+       case VIDEO_SOUND_STEREO:
+               t |= TDA9840_STEREO;
+               break;
+       case VIDEO_SOUND_LANG1:
+               t |= TDA9840_DUALA;
+               break;
+       case VIDEO_SOUND_LANG2:
+               t |= TDA9840_DUALB;
+               break;
+       default:
+               update = 0;
+       }
+
+       if (update)
+               chip_write(chip, TDA9840_SW, t);
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda985x                */
+
+/* subaddresses for TDA9855 */
+#define TDA9855_VR     0x00 /* Volume, right */
+#define TDA9855_VL     0x01 /* Volume, left */
+#define TDA9855_BA     0x02 /* Bass */
+#define TDA9855_TR     0x03 /* Treble */
+#define TDA9855_SW     0x04 /* Subwoofer - not connected on DTV2000 */
+
+/* subaddresses for TDA9850 */
+#define TDA9850_C4     0x04 /* Control 1 for TDA9850 */
+
+/* subaddesses for both chips */
+#define TDA985x_C5     0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
+#define TDA985x_C6     0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
+#define TDA985x_C7     0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
+#define TDA985x_A1     0x08 /* Alignment 1 for both chips */
+#define TDA985x_A2     0x09 /* Alignment 2 for both chips */
+#define TDA985x_A3     0x0a /* Alignment 3 for both chips */
+
+/* Masks for bits in TDA9855 subaddresses */
+/* 0x00 - VR in TDA9855 */
+/* 0x01 - VL in TDA9855 */
+/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
+ * in 1dB steps - mute is 0x27 */
+
+
+/* 0x02 - BA in TDA9855 */ 
+/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
+ * in .5dB steps - 0 is 0x0E */
+
+
+/* 0x03 - TR in TDA9855 */
+/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
+ * in 3dB steps - 0 is 0x7 */
+
+/* Masks for bits in both chips' subaddresses */
+/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
+/* Unique to TDA9855: */
+/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
+ * in 3dB steps - mute is 0x0 */
+/* Unique to TDA9850: */
+/* lower 4 bits control stereo noise threshold, over which stereo turns off
+ * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
+
+
+/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
+/* Unique to TDA9855: */
+#define TDA9855_MUTE   1<<7 /* GMU, Mute at outputs */
+#define TDA9855_AVL    1<<6 /* AVL, Automatic Volume Level */
+#define TDA9855_LOUD   1<<5 /* Loudness, 1==off */
+#define TDA9855_SUR    1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
+                            /* Bits 0 to 3 select various combinations
+                              * of line in and line out, only the 
+                              * interesting ones are defined */
+#define TDA9855_EXT    1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
+#define TDA9855_INT    0    /* Selects inputs LOR and LOL.  (internal) */
+
+/* Unique to TDA9850:  */
+/* lower 4 bits contol SAP noise threshold, over which SAP turns off
+ * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
+
+
+/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
+/* Common to TDA9855 and TDA9850: */
+#define TDA985x_SAP    3<<6 /* Selects SAP output, mute if not received */
+#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */
+#define TDA985x_MONO   0    /* Forces Mono output */
+#define TDA985x_LMU    1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
+
+/* Unique to TDA9855: */
+#define TDA9855_TZCM   1<<5 /* If set, don't mute till zero crossing */
+#define TDA9855_VZCM   1<<4 /* If set, don't change volume till zero crossing*/
+#define TDA9855_LINEAR 0    /* Linear Stereo */
+#define TDA9855_PSEUDO 1    /* Pseudo Stereo */
+#define TDA9855_SPAT_30        2    /* Spatial Stereo, 30% anti-phase crosstalk */
+#define TDA9855_SPAT_50        3    /* Spatial Stereo, 52% anti-phase crosstalk */
+#define TDA9855_E_MONO 7    /* Forced mono - mono select elseware, so useless*/
+
+/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
+ * in .5dB steps -  0dB is 0x7 */
+
+/* 0x08, 0x09 - A1 and A2 (read/write) */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 5 bites are wideband and spectral expander alignment
+ * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
+#define TDA985x_STP    1<<5 /* Stereo Pilot/detect (read-only) */
+#define TDA985x_SAPP   1<<6 /* SAP Pilot/detect (read-only) */
+#define TDA985x_STS    1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
+
+/* 0x0a - A3 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
+ * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
+#define TDA985x_ADJ    1<<7 /* Stereo adjust on/off (wideband and spectral */
+
+int tda9855_volume(int val) { return val/0x2e8+0x27; }
+int tda9855_bass(int val)   { return val/0xccc+0x06; }
+int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; }
+
+int  tda985x_getmode(struct CHIPSTATE *chip)
+{
+       int mode;
+
+       mode = ((TDA985x_STP | TDA985x_SAPP) & 
+               chip_read(chip)) >> 4;
+       /* Add mono mode regardless of SAP and stereo */
+       /* Allows forced mono */
+       return mode | VIDEO_SOUND_MONO;
+}
+
+void tda985x_setmode(struct CHIPSTATE *chip, int mode)
+{
+       int update = 1;
+       int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
+       
+       switch (mode) {
+       case VIDEO_SOUND_MONO:
+               c6 |= TDA985x_MONO;
+               break;
+       case VIDEO_SOUND_STEREO:
+               c6 |= TDA985x_STEREO;
+               break;
+       case VIDEO_SOUND_LANG1:
+               c6 |= TDA985x_SAP;
+               break;
+       default:
+               update = 0;
+       }
+       if (update)
+               chip_write(chip,TDA985x_C6,c6);
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda9873h               */
+
+/* Subaddresses for TDA9873H */
+
+#define TDA9873_SW     0x00 /* Switching                    */
+#define TDA9873_AD     0x01 /* Adjust                       */
+#define TDA9873_PT     0x02 /* Port                         */
+
+/* Subaddress 0x00: Switching Data 
+ * B7..B0:
+ *
+ * B1, B0: Input source selection
+ *  0,  0  internal
+ *  1,  0  external stereo
+ *  0,  1  external mono
+ */
+#define TDA9873_INTERNAL    0
+#define TDA9873_EXT_STEREO  2
+#define TDA9873_EXT_MONO    1
+
+/*    B3, B2: output signal select
+ * B4    : transmission mode 
+ *  0, 0, 1   Mono
+ *  1, 0, 0   Stereo
+ *  1, 1, 1   Stereo (reversed channel)    
+ *  0, 0, 0   Dual AB
+ *  0, 0, 1   Dual AA
+ *  0, 1, 0   Dual BB
+ *  0, 1, 1   Dual BA
+ */
+
+#define TDA9873_TR_MONO     4
+#define TDA9873_TR_STEREO   1 << 4
+#define TDA9873_TR_REVERSE  (1 << 3) & (1 << 2)
+#define TDA9873_TR_DUALA    1 << 2
+#define TDA9873_TR_DUALB    1 << 3
+
+/* output level controls
+ * B5:  output level switch (0 = reduced gain, 1 = normal gain)
+ * B6:  mute                (1 = muted)
+ * B7:  auto-mute           (1 = auto-mute enabled)
+ */
+
+#define TDA9873_GAIN_NORMAL 1 << 5
+#define TDA9873_MUTE        1 << 6
+#define TDA9873_AUTOMUTE    1 << 7
+
+/* Subaddress 0x01:  Adjust/standard */
+
+/* Lower 4 bits (C3..C0) control stereo adjustment on R channel (-0.6 - +0.7 dB)
+ * Recommended value is +0 dB
+ */
+
+#define        TDA9873_STEREO_ADJ      0x06 /* 0dB gain */
+
+/* Bits C6..C4 control FM stantard  
+ * C6, C5, C4
+ *  0,  0,  0   B/G (PAL FM)
+ *  0,  0,  1   M
+ *  0,  1,  0   D/K(1)
+ *  0,  1,  1   D/K(2)
+ *  1,  0,  0   D/K(3)
+ *  1,  0,  1   I
+ */
+#define TDA9873_BG             0
+#define TDA9873_M       1
+#define TDA9873_DK1     2
+#define TDA9873_DK2     3
+#define TDA9873_DK3     4
+#define TDA9873_I       5
+
+/* C7 controls identification response time (1=fast/0=normal)
+ */
+#define TDA9873_IDR_NORM 0
+#define TDA9873_IDR_FAST 1 << 7
+
+
+/* Subaddress 0x02: Port data */ 
+
+/* E1, E0   free programmable ports P1/P2
+    0,  0   both ports low
+    0,  1   P1 high
+    1,  0   P2 high
+    1,  1   both ports high
+*/
+
+#define TDA9873_PORTS    3
+
+/* E2: test port */
+#define TDA9873_TST_PORT 1 << 2
+
+/* E5..E3 control mono output channel (together with transmission mode bit B4)
+ *
+ * E5 E4 E3 B4     OUTM
+ *  0  0  0  0     mono
+ *  0  0  1  0     DUAL B
+ *  0  1  0  1     mono (from stereo decoder)
+ */
+#define TDA9873_MOUT_MONO   0
+#define TDA9873_MOUT_FMONO  0
+#define TDA9873_MOUT_DUALA  0 
+#define TDA9873_MOUT_DUALB  1 << 3 
+#define TDA9873_MOUT_ST     1 << 4 
+#define TDA9873_MOUT_EXTM   (1 << 4 ) & (1 << 3)
+#define TDA9873_MOUT_EXTL   1 << 5 
+#define TDA9873_MOUT_EXTR   (1 << 5 ) & (1 << 3)
+#define TDA9873_MOUT_EXTLR  (1 << 5 ) & (1 << 4)
+#define TDA9873_MOUT_MUTE   (1 << 5 ) & (1 << 4) & (1 << 3)
+
+/* Status bits: (chip read) */
+#define TDA9873_PONR        0 /* Power-on reset detected if = 1 */
+#define TDA9873_STEREO      2 /* Stereo sound is identified     */
+#define TDA9873_DUAL        4 /* Dual sound is identified       */
+
+int tda9873_getmode(struct CHIPSTATE *chip)
+{
+       int val,mode;
+
+       val = chip_read(chip);
+       mode = VIDEO_SOUND_MONO;
+       if (val & TDA9873_STEREO)
+               mode |= VIDEO_SOUND_STEREO;
+       if (val & TDA9873_DUAL)
+               mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       dprintk ("tda9873_getmode(): raw chip read: %d, return: %d\n",
+                val, mode);
+       return mode;
+}
+
+void tda9873_setmode(struct CHIPSTATE *chip, int mode)
+{
+       int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & 0xe3;
+       /*      int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
+       dprintk("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+       dprintk("tda9873_setmode(): sw_data  = %d\n", sw_data);
+
+       switch (mode) {
+       case VIDEO_SOUND_MONO:
+               sw_data |= TDA9873_TR_MONO;   
+               break;
+       case VIDEO_SOUND_STEREO:
+               sw_data |= TDA9873_TR_STEREO;
+               break;
+       case VIDEO_SOUND_LANG1:
+               sw_data |= TDA9873_TR_DUALA;
+               break;
+       case VIDEO_SOUND_LANG2:
+               sw_data |= TDA9873_TR_DUALB;
+               break;
+       }
+       dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data);
+       chip_write(chip,TDA9873_SW,sw_data);
+}
+
+void tda9873_checkmode(struct CHIPSTATE *chip)
+{
+       int mode = tda9873_getmode(chip);
+
+       if (mode & VIDEO_SOUND_STEREO)
+               tda9873_setmode(chip,VIDEO_SOUND_STEREO);
+       if (mode & VIDEO_SOUND_LANG1)
+               tda9873_setmode(chip,VIDEO_SOUND_LANG1);
+}
+
+int tda9873_checkit(struct CHIPSTATE *chip)
+{
+       int rc;
+
+       if (-1 == (rc = chip_read2(chip,254)))
+               return 0;
+       return (rc & ~0x1f) == 0x80;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tea6420                */
+
+#define TEA6300_VL         0x00  /* volume left */
+#define TEA6300_VR         0x01  /* volume right */
+#define TEA6300_BA         0x02  /* bass */
+#define TEA6300_TR         0x03  /* treble */
+#define TEA6300_FA         0x04  /* fader control */
+#define TEA6300_S          0x05  /* switch register */
+                                 /* values for those registers: */
+#define TEA6300_S_SA       0x01  /* stereo A input */
+#define TEA6300_S_SB       0x02  /* stereo B */
+#define TEA6300_S_SC       0x04  /* stereo C */
+#define TEA6300_S_GMU      0x80  /* general mute */
+
+#define TEA6420_S_SA       0x00  /* stereo A input */
+#define TEA6420_S_SB       0x01  /* stereo B */
+#define TEA6420_S_SC       0x02  /* stereo C */
+#define TEA6420_S_SD       0x03  /* stereo D */
+#define TEA6420_S_SE       0x04  /* stereo E */
+#define TEA6420_S_GMU      0x05  /* general mute */
+
+int tea6300_shift10(int val) { return val >> 10; }
+int tea6300_shift12(int val) { return val >> 12; }
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda8425                */
+
+#define TDA8425_VL         0x00  /* volume left */
+#define TDA8425_VR         0x01  /* volume right */
+#define TDA8425_BA         0x02  /* bass */
+#define TDA8425_TR         0x03  /* treble */
+#define TDA8425_S1         0x08  /* switch functions */
+                                 /* values for those registers: */
+#define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
+#define TDA8425_S1_ON      0xCE  /* audio on (mute off) - "linear stereo" mode */
+
+int tda8425_shift10(int val) { return val >> 10 | 0xc0; }
+int tda8425_shift12(int val) { return val >> 12 | 0xf0; }
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for pic16c54 (PV951)       */
+
+/* the registers of 16C54, I2C sub address. */
+#define PIC16C54_REG_KEY_CODE     0x01        /* Not use. */
+#define PIC16C54_REG_MISC         0x02
+
+/* bit definition of the RESET register, I2C data. */
+#define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
+                                            /*        code of remote controller */
+#define PIC16C54_MISC_MTS_MAIN         0x02 /* bit 1 */
+#define PIC16C54_MISC_MTS_SAP          0x04 /* bit 2 */
+#define PIC16C54_MISC_MTS_BOTH         0x08 /* bit 3 */
+#define PIC16C54_MISC_SND_MUTE         0x10 /* bit 4, Mute Audio(Line-in and Tuner) */
+#define PIC16C54_MISC_SND_NOTMUTE      0x20 /* bit 5 */
+#define PIC16C54_MISC_SWITCH_TUNER     0x40 /* bit 6   , Switch to Line-in */
+#define PIC16C54_MISC_SWITCH_LINE      0x80 /* bit 7   , Switch to Tuner */
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - struct CHIPDESC                              */
+
+/* insmod options to enable/disable individual audio chips */
+int tda8425  = 1;
+int tda9840  = 1;
+int tda9850  = 1;
+int tda9855  = 1;
+int tda9873  = 1;
+int tea6300  = 0;
+int tea6420  = 1;
+int pic16c54 = 1;
+MODULE_PARM(tda8425,"i");
+MODULE_PARM(tda9840,"i");
+MODULE_PARM(tda9850,"i");
+MODULE_PARM(tda9855,"i");
+MODULE_PARM(tda9873,"i");
+MODULE_PARM(tea6300,"i");
+MODULE_PARM(tea6420,"i");
+MODULE_PARM(pic16c54,"i");
+
+static struct CHIPDESC chiplist[] = {
+       {
+               name:       "tda9840",
+               id:         I2C_DRIVERID_TDA9840,
+               insmodopt:  &tda9840,
+               addr_lo:    I2C_TDA9840 >> 1,
+               addr_hi:    I2C_TDA9840 >> 1,
+               registers:  5,
+
+               getmode:    tda9840_getmode,
+               setmode:    tda9840_setmode,
+
+               init:       { 2, { TDA9840_SW, 0x2a } }
+       },
+       {
+               name:       "tda9873h",
+               id:         I2C_DRIVERID_TDA9873,
+               checkit:    tda9873_checkit,
+               insmodopt:  &tda9873,
+               addr_lo:    I2C_TDA985x_L >> 1,
+               addr_hi:    I2C_TDA985x_H >> 1,
+               registers:  3,
+
+               getmode:    tda9873_getmode,
+               setmode:    tda9873_setmode,
+               checkmode:  tda9873_checkmode,
+
+               init:       { 4, { TDA9873_SW, 0xa0, 0x06, 0x03 } }
+       },
+       {
+               name:       "tda9850",
+               id:         I2C_DRIVERID_TDA9850,
+               insmodopt:  &tda9850,
+               addr_lo:    I2C_TDA985x_L >> 1,
+               addr_hi:    I2C_TDA985x_H >> 1,
+               registers:  11,
+
+               getmode:    tda985x_getmode,
+               setmode:    tda985x_setmode,
+
+               init:       { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
+       },
+       {
+               name:       "tda9855",
+               id:         I2C_DRIVERID_TDA9855,
+               insmodopt:  &tda9855,
+               addr_lo:    I2C_TDA985x_L >> 1,
+               addr_hi:    I2C_TDA985x_H >> 1,
+               registers:  11,
+               flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+               leftreg:    TDA9855_VR,
+               rightreg:   TDA9855_VL,
+               bassreg:    TDA9855_BA,
+               treblereg:  TDA9855_TR,
+               volfunc:    tda9855_volume,
+               bassfunc:   tda9855_bass,
+               treblefunc: tda9855_treble,
+
+               getmode:    tda985x_getmode,
+               setmode:    tda985x_setmode,
+
+               init:       { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
+                                   TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT,
+                                   TDA985x_STEREO | TDA9855_LINEAR | TDA9855_TZCM | TDA9855_VZCM,
+                                   0x07, 0x10, 0x10, 0x03 }}
+       },
+       {
+               name:       "tea6300",
+               id:         I2C_DRIVERID_TEA6300,
+               insmodopt:  &tea6300,
+               addr_lo:    I2C_TEA6300 >> 1,
+               addr_hi:    I2C_TEA6300 >> 1,
+               registers:  6,
+               flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+               leftreg:    TEA6300_VR,
+               rightreg:   TEA6300_VL,
+               bassreg:    TEA6300_BA,
+               treblereg:  TEA6300_TR,
+               volfunc:    tea6300_shift10,
+               bassfunc:   tea6300_shift12,
+               treblefunc: tea6300_shift12,
+
+               inputreg:   TEA6300_S,
+               inputmap:   { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
+               inputmute:  TEA6300_S_GMU,
+       },
+       {
+               name:       "tea6420",
+               id:         I2C_DRIVERID_TEA6420,
+               insmodopt:  &tea6420,
+               addr_lo:    I2C_TEA6420 >> 1,
+               addr_hi:    I2C_TEA6420 >> 1,
+               registers:  1,
+               flags:      CHIP_HAS_INPUTSEL,
+
+               inputreg:   -1,
+               inputmap:   { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
+               inputmute:  TEA6300_S_GMU,
+       },
+       {
+               name:       "tda8425",
+               id:         I2C_DRIVERID_TDA8425,
+               insmodopt:  &tda8425,
+               addr_lo:    I2C_TDA8425 >> 1,
+               addr_hi:    I2C_TDA8425 >> 1,
+               registers:  9,
+               flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+               leftreg:    TDA8425_VR,
+               rightreg:   TDA8425_VL,
+               bassreg:    TDA8425_BA,
+               treblereg:  TDA8425_TR,
+               volfunc:    tda8425_shift10,
+               bassfunc:   tda8425_shift12,
+               treblefunc: tda8425_shift12,
+
+               inputreg:   TDA8425_S1,
+               inputmap:   { TDA8425_S1_ON, TDA8425_S1_ON, TDA8425_S1_ON },
+               inputmute:  TDA8425_S1_OFF,
+       },
+       {
+               name:       "pic16c54 (PV951)",
+               id:         I2C_DRIVERID_PIC16C54_PV951,
+               insmodopt:  &pic16c54,
+               addr_lo:    I2C_PIC16C54 >> 1,
+               addr_hi:    I2C_PIC16C54>> 1,
+               registers:  2,
+               flags:      CHIP_HAS_INPUTSEL,
+
+               inputreg:   PIC16C54_REG_MISC,
+               inputmap:   {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
+                            PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE},
+               inputmute:  PIC16C54_MISC_SND_MUTE,
+       },
+       { name: NULL } /* EOF */
+};
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c registration                                                       */
+
+static int chip_attach(struct i2c_adapter *adap, int addr,
+                      unsigned short flags, int kind)
+{
+       struct CHIPSTATE *chip;
+       struct CHIPDESC  *desc;
+
+       chip = kmalloc(sizeof(*chip),GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+       memset(chip,0,sizeof(*chip));
+       memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
+        chip->c.adapter = adap;
+        chip->c.addr = addr;
+       chip->c.data = chip;
+
+       /* find description for the chip */
+       dprintk("tvaudio: chip @ addr=0x%x\n",addr<<1);
+       for (desc = chiplist; desc->name != NULL; desc++) {
+               if (0 == *(desc->insmodopt))
+                       continue;
+               if (addr < desc->addr_lo ||
+                   addr > desc->addr_hi)
+                       continue;
+               if (desc->checkit && !desc->checkit(chip))
+                       continue;
+               break;
+       }
+       if (desc->name == NULL) {
+               dprintk("tvaudio: no matching chip description found\n");
+               return -EIO;
+       }
+       dprintk("tvaudio: %s matches:%s%s%s\n",desc->name,
+               (desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
+               (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
+               (desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
+
+       /* fill required data structures */
+       strcpy(chip->c.name,desc->name);
+       chip->type = desc-chiplist;
+       chip->shadow.count = desc->registers+1;
+
+       /* register */
+       MOD_INC_USE_COUNT;
+       i2c_attach_client(&chip->c);
+
+       /* initialization  */
+       chip_cmd(chip,"init",&desc->init);
+       if (desc->flags & CHIP_HAS_VOLUME) {
+               chip->left   = desc->leftinit   ? desc->leftinit   : 65536;
+               chip->right  = desc->rightinit  ? desc->rightinit  : 65536;
+               chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+               chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+       }
+       if (desc->flags & CHIP_HAS_BASSTREBLE) {
+               chip->treble = desc->trebleinit ? desc->trebleinit : 32768;
+               chip->bass   = desc->bassinit   ? desc->bassinit   : 32768;
+               chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+               chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+       }
+
+       if (desc->checkmode) {
+               /* start async thread */
+               DECLARE_MUTEX_LOCKED(sem);
+               chip->notify = &sem;
+               init_waitqueue_head(&chip->wq);
+               kernel_thread(chip_thread,(void *)chip,0);
+               down(&sem);
+               chip->notify = NULL;
+               chip->wake++;
+               wake_up_interruptible(&chip->wq);
+       }
+       return 0;
+}
+
+static int chip_probe(struct i2c_adapter *adap)
+{
+       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+               return i2c_probe(adap, &addr_data, chip_attach);
+       return 0;
+}
+
+static int chip_detach(struct i2c_client *client)
+{
+       struct CHIPSTATE *chip = client->data;
+
+       if (NULL != chip->thread) {
+               /* shutdown async thread */
+               DECLARE_MUTEX_LOCKED(sem);
+               chip->notify = &sem;
+               chip->done = 1;
+               wake_up_interruptible(&chip->wq);
+               down(&sem);
+               chip->notify = NULL;
+       }
+       
+       i2c_detach_client(&chip->c);
+       kfree(chip);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* video4linux interface                                                  */
+
+static int chip_command(struct i2c_client *client,
+                       unsigned int cmd, void *arg)
+{
+        __u16 *sarg = arg;
+       struct CHIPSTATE *chip = client->data;
+       struct CHIPDESC  *desc = chiplist + chip->type;
+
+       dprintk("%s: chip_command 0x%x\n",chip->c.name,cmd);
+
+       switch (cmd) {
+       case AUDC_SET_INPUT:
+               if (desc->flags & CHIP_HAS_INPUTSEL) {
+                       if (*sarg & 0x80)
+                               chip_write(chip,desc->inputreg,desc->inputmute);
+                       else
+                               chip_write(chip,desc->inputreg,desc->inputmap[*sarg]);
+               }
+               break;
+       /* --- v4l ioctls --- */
+       /* take care: bttv does userspace copying, we'll get a
+          kernel pointer here... */
+       case VIDIOCGAUDIO:
+       {
+               struct video_audio *va = arg;
+
+               if (desc->flags & CHIP_HAS_VOLUME) {
+                       va->flags  |= VIDEO_AUDIO_VOLUME;
+                       va->volume  = MAX(chip->left,chip->right);
+                       va->balance = (32768*MIN(chip->left,chip->right))/
+                               (va->volume ? va->volume : 1);
+               }
+               if (desc->flags & CHIP_HAS_BASSTREBLE) {
+                       va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+                       va->bass   = chip->bass;
+                       va->treble = chip->treble;
+               }
+               if (desc->getmode)
+                       va->mode = desc->getmode(chip);
+               else
+                       va->mode = VIDEO_SOUND_MONO;
+               break;
+       }
+
+       case VIDIOCSAUDIO:
+       {
+               struct video_audio *va = arg;
+               
+               if (desc->flags & CHIP_HAS_VOLUME) {
+                       chip->left = (MIN(65536 - va->balance,32768) *
+                                     va->volume) / 32768;
+                       chip->right = (MIN(va->balance,32768) *
+                                      va->volume) / 32768;
+                       chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+                       chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+               }
+               if (desc->flags & CHIP_HAS_BASSTREBLE) {
+                       chip->bass = va->bass;
+                       chip->treble = va->treble;
+                       chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+                       chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+               }
+               if (desc->setmode && va->mode)
+                       desc->setmode(chip,va->mode);
+               break;
+       }
+       case VIDIOCSFREQ:
+       {
+               if (desc->checkmode) {
+                       desc->setmode(chip,VIDEO_SOUND_MONO);
+                       chip->wake++;
+                       wake_up_interruptible(&chip->wq);
+                       /* the thread will call checkmode() a second later */
+               }
+       }
+       }
+       return 0;
+}
+
+
+static struct i2c_driver driver = {
+        name:            "generic i2c audio driver",
+        id:              I2C_DRIVERID_TVAUDIO, /* FIXME */
+        flags:           I2C_DF_NOTIFY,
+        attach_adapter:  chip_probe,
+        detach_client:   chip_detach,
+        command:         chip_command,
+};
+
+static struct i2c_client client_template =
+{
+        name:   "(unset)",
+        driver: &driver,
+};
+
+int audiochip_init_module(void)
+{
+       struct CHIPDESC  *desc;
+       printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+       printk(KERN_INFO "tvaudio: known chips: ");
+       for (desc = chiplist; desc->name != NULL; desc++)
+               printk("%s%s", (desc == chiplist) ? "" : ",",desc->name);
+       printk("\n");
+       i2c_add_driver(&driver);
+       return 0;
+}
+
+void audiochip_cleanup_module(void)
+{
+       i2c_del_driver(&driver);
+}
+
+module_init(audiochip_init_module);
+module_exit(audiochip_cleanup_module);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tvaudio.h b/drivers/media/video/tvaudio.h
new file mode 100644 (file)
index 0000000..702d249
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * i2c bus addresses for the chips supported by tvaudio.c
+ */
+
+#define I2C_TDA8425        0x82
+#define I2C_TDA9840        0x84
+#define I2C_TDA985x_L      0xb4 /* also used by 9873 */
+#define I2C_TDA985x_H      0xb6
+
+#define I2C_TEA6300        0x80
+#define I2C_TEA6420       0x98
+
+#define I2C_PIC16C54       0x96 /* PV951 */
index e1034a152c81b0407843a96ab83085f6dc459d5b..1e406921ec3e9e2c513655c609a9dd4100203345 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/uaccess.h>
 
 #include "audiochip.h"
+#include "id.h"
 
 #define DEV_MAX  4
 
@@ -45,11 +46,11 @@ static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin);
 
 
 static struct i2c_driver driver = {
-       "tv card mixer driver",
-        42 /* I2C_DRIVERID_FIXME */,
-       I2C_DF_DUMMY,
-        tvmixer_adapters,
-        tvmixer_clients,
+       name:            "tv card mixer driver",
+        id:              I2C_DRIVERID_TVMIXER,
+       flags:           I2C_DF_DUMMY,
+        attach_adapter:  tvmixer_adapters,
+        detach_client:   tvmixer_clients,
 };
 
 static struct file_operations tvmixer_fops = {
@@ -241,6 +242,15 @@ static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin)
 
 static int tvmixer_adapters(struct i2c_adapter *adap)
 {
+       int i;
+
+       if (debug)
+               printk("tvmixer: adapter %s\n",adap->name);
+       for (i=0; i<I2C_CLIENT_MAX; i++) {
+               if (!adap->clients[i])
+                       continue;
+               tvmixer_clients(adap->clients[i]);
+       }
        return 0;
 }
 
index 3dce6dc97c0fc1c0f7f362d2ad752335d8cb97be..b38b4352dbcf55922a983282e1f5e8fa5956dc7a 100644 (file)
@@ -26,8 +26,6 @@
 #define DOC_PASSIVE_PROBE
 */
 
-
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <asm/errno.h>
index ca71e15909d3e15425455ee6dc05541d6851ec49..c9be23bf672b5aa08b937629c78b73f7e055cf59 100644 (file)
@@ -234,7 +234,9 @@ struct net_local
 int __init el1_probe(struct net_device *dev)
 {
        int i;
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
 
        if (base_addr > 0x1ff)  /* Check a single specified location. */
                return el1_probe1(dev, base_addr);
@@ -403,15 +405,11 @@ static int el_open(struct net_device *dev)
        struct net_local *lp = (struct net_local *)dev->priv;
        unsigned long flags;
 
-       MOD_INC_USE_COUNT;
-
        if (el_debug > 2)
                printk("%s: Doing el_open()...", dev->name);
 
-       if ((retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev))) {
-               MOD_DEC_USE_COUNT;
+       if ((retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev)))
                return retval;
-       }
 
        spin_lock_irqsave(&lp->lock, flags);
        el_reset(dev);
@@ -863,7 +861,6 @@ static int el1_close(struct net_device *dev)
        free_irq(dev->irq, dev);
        outb(AX_RESET, AX_CMD);         /* Reset the chip */
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -917,12 +914,10 @@ static void set_multicast_list(struct net_device *dev)
 
 #ifdef MODULE
 
-static struct net_device dev_3c501 =
-{
-       "", /* device name is inserted by linux/drivers/net/net_init.c */
-       0, 0, 0, 0,
-       0x280, 5,
-       0, 0, 0, NULL, el1_probe
+static struct net_device dev_3c501 = {
+       init:           el1_probe,
+       base_addr:      0x280,
+       irq:            5,
 };
 
 static int io=0x280;
index 7975d3c58153d92ebd7a5d29a278613fcbd44236..6db67d8179419adba2d0a5a73365b8b0722be6f5 100644 (file)
@@ -87,6 +87,8 @@ el2_probe(struct net_device *dev)
     int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
     int base_addr = dev->base_addr;
 
+    SET_MODULE_OWNER(dev);
+
     if (base_addr > 0x1ff)     /* Check a single specified location. */
        return el2_probe1(dev, base_addr);
     else if (base_addr != 0)           /* Don't probe at all. */
@@ -346,7 +348,6 @@ el2_open(struct net_device *dev)
 
     el2_init_card(dev);
     ei_open(dev);
-    MOD_INC_USE_COUNT;
     return 0;
 }
 
@@ -358,7 +359,6 @@ el2_close(struct net_device *dev)
     outb(EGACFR_IRQOFF, E33G_GACFR);   /* disable interrupts. */
 
     ei_close(dev);
-    MOD_DEC_USE_COUNT;
     return 0;
 }
 
@@ -604,18 +604,10 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
 #ifdef MODULE
 #define MAX_EL2_CARDS  4       /* Max number of EL2 cards per module */
 
-static struct net_device dev_el2[MAX_EL2_CARDS] = {
-       {
-               "",
-               0, 0, 0, 0,
-               0, 0,
-               0, 0, 0, NULL, NULL
-       },
-};
-
-static int io[MAX_EL2_CARDS] = { 0, };
-static int irq[MAX_EL2_CARDS]  = { 0, };
-static int xcvr[MAX_EL2_CARDS] = { 0, };       /* choose int. or ext. xcvr */
+static struct net_device dev_el2[MAX_EL2_CARDS];
+static int io[MAX_EL2_CARDS];
+static int irq[MAX_EL2_CARDS];
+static int xcvr[MAX_EL2_CARDS];        /* choose int. or ext. xcvr */
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
index 73318d229183fa55ff7bddf934434369bdb4dd94..d967bb17640d05dab7ded3e810ca86abf036a838 100644 (file)
@@ -973,10 +973,8 @@ static int elp_open(struct net_device *dev)
         * device is now officially open!
         */
 
-       netif_wake_queue(dev);
-       MOD_INC_USE_COUNT;
-
-       return 0;               /* Always succeed */
+       netif_start_queue(dev);
+       return 0;
 }
 
 
@@ -1184,8 +1182,6 @@ static int elp_close(struct net_device *dev)
        free_dma(dev->dma);
        free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
@@ -1420,6 +1416,8 @@ int __init elplus_probe(struct net_device *dev)
        int i, tries, tries1, timeout, okay;
        unsigned long cookie = 0;
 
+       SET_MODULE_OWNER(dev);
+
        /*
         *  setup adapter structure
         */
index b792c4dd121179c2effd944593a304e0152f775d..8d7e1a1631cd32052a580f7369c8faa4bfebe97a 100644 (file)
@@ -304,9 +304,11 @@ static void init_82586_mem(struct net_device *dev);
 
 int __init el16_probe(struct net_device *dev)
 {
-       int base_addr = dev ? dev->base_addr : 0;
+       int base_addr = dev->base_addr;
        int i;
 
+       SET_MODULE_OWNER(dev);
+
        if (base_addr > 0x1ff)  /* Check a single specified location. */
                return el16_probe1(dev, base_addr);
        else if (base_addr != 0)
@@ -339,7 +341,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
                init_ID_done = 1;
        }
 
-       if (!request_region(ioaddr, EL16_IO_EXTENT, "3c507"))
+       if (!request_region(ioaddr, EL16_IO_EXTENT, dev->name))
                return -ENODEV;
 
        if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') || 
@@ -358,7 +360,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
 
        irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
 
-       irqval = request_irq(irq, &el16_interrupt, 0, "3c507", dev);
+       irqval = request_irq(irq, &el16_interrupt, 0, dev->name, dev);
        if (irqval) {
                printk ("unable to get IRQ %d (irqval=%d).\n", irq, irqval);
                retval = -EAGAIN;
@@ -439,9 +441,6 @@ static int el16_open(struct net_device *dev)
        init_82586_mem(dev);
 
        netif_start_queue(dev);
-
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -624,8 +623,6 @@ static int el16_close(struct net_device *dev)
 
        /* Update the statistics here. */
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
@@ -857,8 +854,7 @@ static void el16_rx(struct net_device *dev)
        lp->rx_tail = rx_tail;
 }
 #ifdef MODULE
-static struct net_device dev_3c507 = { init: el16_probe };
-
+static struct net_device dev_3c507;
 static int io = 0x300;
 static int irq = 0;
 MODULE_PARM(io, "i");
@@ -870,6 +866,7 @@ int init_module(void)
                printk("3c507: You should not use auto-probing with insmod!\n");
        dev_3c507.base_addr = io;
        dev_3c507.irq       = irq;
+       dev_3c507.init      = el16_probe;
        if (register_netdev(&dev_3c507) != 0) {
                printk("3c507: register_netdev() returned non-zero.\n");
                return -EIO;
index 02af4f34a0a4cfeb22c81a2f303c164f1054c7c9..7cb2ff7beae778f9959355d411f8b1e5cbc0b48b 100644 (file)
@@ -200,6 +200,8 @@ int el3_probe(struct net_device *dev)
        static int pnp_cards = 0;
 #endif /* __ISAPNP__ */
 
+       if (dev) SET_MODULE_OWNER(dev);
+
        /* First check all slots of the EISA bus.  The next slot address to
           probe is kept in 'eisa_addr' to support multiple probe() calls. */
        if (EISA_bus) {
@@ -440,6 +442,7 @@ no_pnp:
                        release_region(ioaddr, EL3_IO_EXTENT);
                        return -ENOMEM;
                }
+               SET_MODULE_OWNER(dev);
        }
        memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
        dev->base_addr = ioaddr;
@@ -530,9 +533,8 @@ el3_open(struct net_device *dev)
        outw(RxReset, ioaddr + EL3_CMD);
        outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
-       if (request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev)) {
-               return -EAGAIN;
-       }
+       i = request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev);
+       if (i) return i;
 
        EL3WINDOW(0);
        if (el3_debug > 3)
@@ -591,8 +593,7 @@ el3_open(struct net_device *dev)
                printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
                           dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
 
-       MOD_INC_USE_COUNT;
-       return 0;                                       /* Always succeed */
+       return 0;
 }
 
 static void
@@ -969,7 +970,6 @@ el3_close(struct net_device *dev)
        outw(0x0f00, ioaddr + WN0_IRQ);
 
        update_stats(dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
index da7d27ac517406e917e1cb477ae831b4390bebca..df9786b81459b3fe5b7f40e7f7c9d8d624bfd264 100644 (file)
@@ -428,6 +428,8 @@ int tc515_probe(struct net_device *dev)
 {
        int cards_found = 0;
 
+       SET_MODULE_OWNER(dev);
+
        cards_found = corkscrew_scan(dev);
 
        if (corkscrew_debug > 0 && cards_found)
@@ -561,6 +563,8 @@ static struct net_device *corkscrew_found_device(struct net_device *dev,
            sizeof(struct corkscrew_private) + 15;      /* Pad for alignment */
 
        dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL);
+       if (!dev)
+               return NULL;
        memset(dev, 0, dev_size);
        /* Align the Rx and Tx ring entries.  */
        dev->priv =
@@ -586,15 +590,16 @@ static struct net_device *corkscrew_found_device(struct net_device *dev,
        ether_setup(dev);
        vp->next_module = root_corkscrew_dev;
        root_corkscrew_dev = dev;
-       if (register_netdev(dev) != 0)
-               return 0;
-#else                          /* not a MODULE */
-       if (dev) {
-               /* Caution: quad-word alignment required for rings! */
-               dev->priv =
-                   kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL);
-               memset(dev->priv, 0, sizeof(struct corkscrew_private));
+       if (register_netdev(dev) != 0) {
+               kfree(dev);
+               return NULL;
        }
+       SET_MODULE_OWNER(dev);
+#else                          /* not a MODULE */
+       /* Caution: quad-word alignment required for rings! */
+       dev->priv =
+           kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL);
+       memset(dev->priv, 0, sizeof(struct corkscrew_private));
        dev = init_etherdev(dev, sizeof(struct corkscrew_private));
        dev->base_addr = ioaddr;
        dev->irq = irq;
@@ -874,8 +879,6 @@ static int corkscrew_open(struct net_device *dev)
             | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
             ioaddr + EL3_CMD);
 
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -1500,8 +1503,6 @@ static int corkscrew_close(struct net_device *dev)
                        }
        }
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index 7703e141560bc1087e1dc50abb3ffb21a4ac8895..12f9f0a9d1b212ffd6d5f051488daa2458b8abca 100644 (file)
@@ -271,7 +271,6 @@ static int elmc_close(struct net_device *dev)
        netif_stop_queue(dev);
        elmc_id_reset586();     /* the hard way to stop the receiver */
        free_irq(dev->irq, dev);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -281,21 +280,21 @@ static int elmc_close(struct net_device *dev)
 
 static int elmc_open(struct net_device *dev)
 {
+       int ret;
 
        elmc_id_attn586();      /* disable interrupts */
 
-       if (request_irq(dev->irq, &elmc_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM,
-                       "3c523", dev)
-           ) {
+       ret = request_irq(dev->irq, &elmc_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM,
+                         dev->name, dev);
+       if (ret) {
                printk(KERN_ERR "%s: couldn't get irq %d\n", dev->name, dev->irq);
                elmc_id_reset586();
-               return -EAGAIN;
+               return ret;
        }
        alloc586(dev);
        init586(dev);
        startrecv586(dev);
        netif_start_queue(dev);
-       MOD_INC_USE_COUNT;
        return 0;               /* most done by init */
 }
 
@@ -409,13 +408,14 @@ static int elmc_getinfo(char *buf, int slot, void *d)
 int __init elmc_probe(struct net_device *dev)
 {
        static int slot = 0;
-       int base_addr = dev ? dev->base_addr : 0;
-       int irq = dev ? dev->irq : 0;
+       int base_addr = dev->base_addr;
+       int irq = dev->irq;
        u_char status = 0;
        u_char revision = 0;
        int i = 0;
        unsigned int size = 0;
 
+       SET_MODULE_OWNER(dev);
        if (MCA_bus == 0) {
                return -ENODEV;
        }
@@ -1208,15 +1208,9 @@ static void set_multicast_list(struct net_device *dev)
 /* Increase if needed ;) */
 #define MAX_3C523_CARDS 4
 
-static struct net_device dev_elmc[MAX_3C523_CARDS] =
-{      
-       {
-       "", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL
-       },
-};
-
-static int irq[MAX_3C523_CARDS] = {0,};
-static int io[MAX_3C523_CARDS] = {0,};
+static struct net_device dev_elmc[MAX_3C523_CARDS];
+static int irq[MAX_3C523_CARDS];
+static int io[MAX_3C523_CARDS];
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
 
index 2a8f82e834da576fbc4c9c4e5a909e47e022c9b1..73d3a35b312cf23f2b139b5a17e9af4441ce2971 100644 (file)
@@ -184,6 +184,8 @@ int __init mc32_probe(struct net_device *dev)
        int i;
        int adapter_found = 0;
 
+       SET_MODULE_OWNER(dev);
+
        /* Do not check any supplied i/o locations. 
           POS registers usually don't fail :) */
 
@@ -347,25 +349,22 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
         *      Grab the IRQ
         */
 
-       if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev))
-       {
-               printk("%s: unable to get IRQ %d.\n",
-                                  dev->name, dev->irq);
-               return -EAGAIN;
+       i = request_irq(dev->irq, &mc32_interrupt, 0, dev->name, dev);
+       if (i) {
+               printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+               return i;
        }
 
        /* Initialize the device structure. */
-       if (dev->priv == NULL) {
-               dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
-               if (dev->priv == NULL)
-               {
-                       free_irq(dev->irq, dev);
-                       return -ENOMEM;
-               }
+       dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
+       if (dev->priv == NULL)
+       {
+               free_irq(dev->irq, dev);
+               return -ENOMEM;
        }
 
        memset(dev->priv, 0, sizeof(struct mc32_local));
-       lp = (struct mc32_local *)dev->priv;
+       lp = dev->priv;
        lp->slot = slot;
 
        i=0;
@@ -897,8 +896,6 @@ static int mc32_open(struct net_device *dev)
        mc32_tx_begin(dev);
 
        netif_start_queue(dev); 
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -1318,8 +1315,6 @@ static int mc32_close(struct net_device *dev)
        
        /* Update the statistics here. */
 
-       MOD_DEC_USE_COUNT;
-
        return 0;
 
 }
@@ -1444,7 +1439,7 @@ static void mc32_reset_multicast_list(struct net_device *dev)
 
 #ifdef MODULE
 
-static struct net_device this_device = { init: mc32_probe };
+static struct net_device this_device;
 
 
 /**
@@ -1459,6 +1454,7 @@ int init_module(void)
 {
        int result;
 
+       this_device.init = mc32_probe;
        if ((result = register_netdev(&this_device)) != 0)
                return result;
 
index 8e6379e3856384c42e49b1963bbbe8b617d6d445..ae4054d351448f61d529af9af4011beb9a5693a1 100644 (file)
     - Added experimental support for the 3c556B Laptop Hurricane (Louis Gerbarg)
     - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO"
 
+   LK1.1.11 13 Nov 2000 andrewm
+    - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER
+
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
     - Also see Documentation/networking/vortex.txt
 */
@@ -200,7 +203,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
 #include <linux/delay.h>
 
 static char version[] __devinitdata =
-"3c59x.c:LK1.1.10 17 Sep 2000  Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.40 $\n";
+"3c59x.c:LK1.1.11 13 Nov 2000  Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.46 $\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
@@ -878,7 +881,8 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
                retval = -ENOMEM;
                goto out;
        }
-       
+       SET_MODULE_OWNER(dev);
+
        printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
               dev->name,
               pdev ? "PCI" : "EISA",
@@ -1355,8 +1359,6 @@ vortex_open(struct net_device *dev)
        int i;
        int retval;
 
-       MOD_INC_USE_COUNT;
-
        /* Use the now-standard shared IRQ implementation. */
        if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
                                &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) {
@@ -1405,7 +1407,6 @@ out_free_irq:
 out:
        if (vortex_debug > 1)
                printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval);
-       MOD_DEC_USE_COUNT;
        return retval;
 }
 
@@ -2282,7 +2283,6 @@ vortex_close(struct net_device *dev)
                        }
        }
 
-       MOD_DEC_USE_COUNT;
        vp->open = 0;
        return 0;
 }
@@ -2567,7 +2567,6 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev)
 
        vp = (void *)(dev->priv);
 
-       /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
        /* AKPM: FIXME: we should have
         *      if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
         * here
index 24cad4416537e52904d870d1cbc3d9f9477cf7be..eb3253b822b5e351dc46f8237925580610f8cac3 100644 (file)
@@ -1092,7 +1092,7 @@ int __init i82596_probe(struct net_device *dev)
 {
        int i;
        struct i596_private *lp;
-       char eth_addr[6];
+       char eth_addr[8];
        static int probed = 0;
 
        if (probed)
index c6233870749b6da2508ad295609f03fe2f79d66d..ddc4b9ac5f118077bcdea48413c67c57d0ba66b6 100644 (file)
@@ -76,7 +76,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
          tristate '    3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
       fi
    fi
-   tristate '  AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+   dep_tristate '  AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE $CONFIG_ISA
    bool '  Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
    if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
       tristate '    WD80*3 support' CONFIG_WD80x3
@@ -127,52 +127,45 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
    fi
    bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
    if [ "$CONFIG_NET_PCI" = "y" ]; then
-      tristate '    AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
+      dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
       dep_tristate '    Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        tristate '    Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
+      if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then
+        dep_tristate '    Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL
       fi
 
       tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT
-      tristate '    CS89x0 support' CONFIG_CS89x0
-      tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+      dep_tristate '    CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
       dep_tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
-      tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-         tristate '    DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
+      if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
+         tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+         tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
       fi
+      dep_tristate '    DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 $CONFIG_PCI $CONFIG_EXPERIMENTAL
       dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-         if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then
-           bool '      Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM
-        fi
-        tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
-      fi
+      dep_mbool '      Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL
+      dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
       dep_tristate '    PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
-      fi
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
-         dep_tristate '    RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI
-      fi
+      dep_tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
+      dep_tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI
+      dep_tristate '    RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI $CONFIG_EXPERIMENTAL
       dep_tristate '    SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
       dep_tristate '    SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
       dep_tristate '    Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
-      tristate '    TI ThunderLAN support' CONFIG_TLAN
+      if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
+         tristate '    TI ThunderLAN support' CONFIG_TLAN
+      fi
       dep_tristate '    VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
       dep_tristate '    Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
+      dep_tristate '    Sun Happy Meal 10/100baseT PCI support' CONFIG_HAPPYMEAL $CONFIG_PCI
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
         bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
       fi
    fi
    bool '  Pocket and portable adapters' CONFIG_NET_POCKET
    if [ "$CONFIG_NET_POCKET" = "y" ]; then
-      if [ "$CONFIG_X86" = "y" ]; then
-         tristate '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
-      fi
+      dep_tristate '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP $CONFIG_ISA
       tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600
       tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620
    fi
index 498bd523f9e86640bf08b45492eeeec957e4c7de..2a3ae2aa867678f8a7dc58d663003dc3214ec48b 100644 (file)
@@ -261,7 +261,7 @@ static int init_restart_lance (struct lance_private *lp)
                barrier();
        if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
                printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
-               return -1;
+               return -EIO;
        }
 
        /* Clear IDON by writing a "1", enable interrupts and start lance */
@@ -488,14 +488,19 @@ static int lance_open (struct net_device *dev)
 {
        struct lance_private *lp = (struct lance_private *)dev->priv;
        volatile struct lance_regs *ll = lp->ll;
-       int status = 0;
+       int ret;
+
+       MOD_INC_USE_COUNT;
 
        last_dev = dev;
 
        /* Install the Interrupt handler */
-       if (request_irq(IRQ_AMIGA_PORTS, lance_interrupt, SA_SHIRQ,
-                       "a2065 Ethernet", dev))
-               return -EAGAIN;
+       ret = request_irq(IRQ_AMIGA_PORTS, lance_interrupt, SA_SHIRQ,
+                         dev->name, dev);
+       if (ret) {
+               MOD_DEC_USE_COUNT;
+               return ret;
+       }
 
        /* Stop the Lance */
        ll->rap = LE_CSR0;
@@ -506,11 +511,7 @@ static int lance_open (struct net_device *dev)
 
        netif_start_queue(dev);
 
-       status = init_restart_lance (lp);
-
-       MOD_INC_USE_COUNT;
-
-       return status;
+       return init_restart_lance (lp);
 }
 
 static int lance_close (struct net_device *dev)
@@ -727,6 +728,7 @@ static int __init a2065_probe(void)
 
        while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
                unsigned long board, base_addr, mem_start;
+               struct resource *r1, *r2;
                int is_cbm;
 
                if (z->id == ZORRO_PROD_CBM_A2065_1 ||
@@ -741,25 +743,26 @@ static int __init a2065_probe(void)
                base_addr = board+A2065_LANCE;
                mem_start = board+A2065_RAM;
 
-               if (!request_mem_region(base_addr, sizeof(struct lance_regs),
-                                       "Am7990"))
-                       continue;
-               if (!request_mem_region(mem_start, A2065_RAM_SIZE, "RAM")) {
-                       release_mem_region(base_addr,
-                                          sizeof(struct lance_regs));
+               r1 = request_mem_region(base_addr, sizeof(struct lance_regs),
+                                       "Am7990");
+               if (!r1) continue;
+               r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM");
+               if (!r2) {
+                       release_resource(r1);
                        continue;
                }
 
                dev = init_etherdev(NULL, sizeof(struct lance_private));
 
                if (dev == NULL) {
-                       release_mem_region(base_addr,
-                                          sizeof(struct lance_regs));
-                       release_mem_region(mem_start, A2065_RAM_SIZE);
+                       release_resource(r1);
+                       release_resource(r2);
                        return -ENOMEM;
                }
                priv = (struct lance_private *)dev->priv;
-               memset(priv, 0, sizeof(struct lance_private));
+
+               r1->name = dev->name;
+               r2->name = dev->name;
 
                priv->dev = dev;
                dev->dev_addr[0] = 0x00;
index c883d6d284c108441d1b44eb15f94f933fdb067d..c070fda58969ddde0b888d21a32c2faff3657f65 100644 (file)
@@ -99,6 +99,8 @@ int __init ac3200_probe(struct net_device *dev)
 {
        unsigned short ioaddr = dev->base_addr;
 
+       SET_MODULE_OWNER(dev);
+
        if (ioaddr > 0x1ff)             /* Check a single specified location. */
                return ac_probe1(ioaddr, dev);
        else if (ioaddr > 0)            /* Don't probe at all. */
@@ -262,9 +264,6 @@ static int ac_open(struct net_device *dev)
 #endif
 
        ei_open(dev);
-
-       MOD_INC_USE_COUNT;
-
        return 0;
 }
 
@@ -333,9 +332,6 @@ static int ac_close_card(struct net_device *dev)
 #endif
 
        ei_close(dev);
-
-       MOD_DEC_USE_COUNT;
-
        return 0;
 }
 
index dc315ec124dfd1e56e39f4a0a6dfbe33113e7984..b419dd0b7db17893b57c8351f070962ad853570e 100644 (file)
                     :   abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch
                     :   (Jason Gunthorpe <jgg@ualberta.ca>)
 
+  Andrew Morton     : Kernel 2.4.0-test11-pre4
+                    : Use dev->name in request_*() (Andrey Panin)
+                    : Fix an error-path memleak in init_module()
+                    : Preserve return value from request_irq()
+                    : Fix type of `media' module parm (Keith Owens)
+                    : Use SET_MODULE_OWNER()
+                    : Tidied up strange request_irq() abuse in net_open().
+
 */
 
-static char *version =
-"cs89x0.c: v2.3.99-pre1-2 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
+static char version[] =
+"cs89x0.c: v2.4.0-test11-pre4 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
 
 /* ======================= end of configuration ======================= */
 
@@ -77,13 +85,8 @@ static char *version =
 /* Always include 'config.h' first in case the user wants to turn on
    or override something. */
 #include <linux/config.h>
-#ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
 
 /*
  * Set this to zero to disable DMA code
@@ -97,7 +100,7 @@ static char *version =
  * Set this to zero to remove all the debug statements via
  * dead code elimination
  */
-#define DEBUGGING      0
+#define DEBUGGING      1
 
 /*
   Sources:
@@ -254,6 +257,8 @@ int __init cs89x0_probe(struct net_device *dev)
        int i;
        int base_addr = dev ? dev->base_addr : 0;
 
+       SET_MODULE_OWNER(dev);
+
        if (net_debug)
                printk("cs89x0:cs89x0_probe()\n");
 
@@ -378,8 +383,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr)
        lp = (struct net_local *)dev->priv;
 
        /* Grab the region so we can find another board if autoIRQ fails. */
-       if (!request_region(ioaddr, NETCARD_IO_EXTENT, "cs89x0")) {
-               retval = -ENODEV;
+       if (!request_region(ioaddr, NETCARD_IO_EXTENT, dev->name)) {
+               retval = -EBUSY;
                goto out1;
        }
 
@@ -985,7 +990,7 @@ write_irq(struct net_device *dev, int chip_type, int irq)
        int i;
 
        if (chip_type == CS8900) {
-               /* Search the mapping table for the corrisponding IRQ pin. */
+               /* Search the mapping table for the corresponding IRQ pin. */
                for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)
                        if (cs8900_irq_map[i] == irq)
                                break;
@@ -1016,8 +1021,6 @@ net_open(struct net_device *dev)
        int i;
        int ret;
 
-       MOD_INC_USE_COUNT;
-
        if (dev->irq < 2) {
                /* Allow interrupts to be generated by the chip */
 /* Cirrus' release had this: */
@@ -1027,20 +1030,20 @@ net_open(struct net_device *dev)
 /* And 2.3.47 had this: */
                writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
 
-               for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) {
-                       if (request_irq (i, NULL, 0, "cs89x0", dev) != -EBUSY) {
-                               write_irq(dev, lp->chip_type, i);
-                               writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
-                               if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev) == 0)
+               for (i = 2; i < CS8920_NO_INTS; i++) {
+                       if ((1 << dev->irq) & lp->irq_map) {
+                               if (request_irq(i, net_interrupt, 0, dev->name, dev) == 0) {
+                                       dev->irq = i;
+                                       write_irq(dev, lp->chip_type, i);
+                                       /* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */
                                        break;
+                               }
                        }
                }
 
-
                if (i >= CS8920_NO_INTS) {
                        writereg(dev, PP_BusCTL, 0);    /* disable interrupts. */
-                       if (net_debug)
-                               printk("cs89x0: can't get an interrupt\n");
+                       printk(KERN_ERR "cs89x0: can't get an interrupt\n");
                        ret = -EAGAIN;
                        goto bad_out;
                }
@@ -1061,7 +1064,7 @@ net_open(struct net_device *dev)
                ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);
                if (ret) {
                        if (net_debug)
-                               printk("cs89x0: request_irq(%d) failed\n", dev->irq);
+                               printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq);
                        goto bad_out;
                }
        }
@@ -1089,7 +1092,7 @@ net_open(struct net_device *dev)
                                goto release_irq;
                        }
                        memset(lp->dma_buff, 0, lp->dmasize * 1024);    /* Why? */
-                       if (request_dma(dev->dma, "cs89x0")) {
+                       if (request_dma(dev->dma, dev->name)) {
                                printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma);
                                goto release_irq;
                        }
@@ -1231,11 +1234,10 @@ net_open(struct net_device *dev)
 #endif
                  );
         netif_start_queue(dev);
-       if (net_debug)
+       if (net_debug > 1)
                printk("cs89x0: net_open() succeeded\n");
        return 0;
 bad_out:
-       MOD_DEC_USE_COUNT;
        return ret;
 }
 
@@ -1482,7 +1484,6 @@ net_close(struct net_device *dev)
 #endif
 
        /* Update the statistics here. */
-        MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1576,7 +1577,7 @@ static int dmasize=16;                    /* or 64 */
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(debug, "i");
-MODULE_PARM(media, "s");
+MODULE_PARM(media, "c8");
 MODULE_PARM(duplex, "i");
 MODULE_PARM(dma , "i");
 MODULE_PARM(dmasize , "i");
@@ -1616,6 +1617,7 @@ int
 init_module(void)
 {
        struct net_local *lp;
+       int ret = 0;
 
 #if DEBUGGING
        net_debug = debug;
@@ -1661,21 +1663,27 @@ init_module(void)
         if (io == 0) {
                 printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n");
                 printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n");
-                return -EPERM;
+                ret = -EPERM;
+               goto out;
         }
 
 #if ALLOW_DMA
        if (use_dma && dmasize != 16 && dmasize != 64) {
                printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize);
-               return -EPERM;
+               ret = -EPERM;
+               goto out;
        }
 #endif
 
         if (register_netdev(&dev_cs89x0) != 0) {
                 printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io);
-                return -ENXIO;
+                ret = -ENXIO;
+               goto out;
         }
-       return 0;
+out:
+       if (ret)
+               kfree(dev_cs89x0.priv);
+       return ret;
 }
 
 void
@@ -1695,7 +1703,6 @@ cleanup_module(void)
 \f
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS -c cs89x0.c"
  *  version-control: t
  *  kept-new-versions: 5
  *  c-indent-level: 8
index 70080e0055ec0be65d4b261bdb2a52aed7eedaee..d9c2edbc0cb092368afbb110816a590e3249f721 100644 (file)
@@ -230,7 +230,7 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
        dev->init            = irport_net_init;
        dev->hard_start_xmit = irport_hard_xmit;
        dev->tx_timeout      = irport_timeout;
-       dev->watchdog_timeo  = HZ/20;
+       dev->watchdog_timeo  = HZ;  /* Allow time enough for speed change */
        dev->open            = irport_net_open;
        dev->stop            = irport_net_close;
        dev->get_stats       = irport_net_get_stats;
@@ -496,7 +496,6 @@ static void irport_write_wakeup(struct irport_cb *self)
                self->tx_buff.data += actual;
                self->tx_buff.len  -= actual;
        } else {
-               
                /* 
                 *  Now serial buffer is almost free & we can start 
                 *  transmission of another packet. But first we must check
index 45e85b08c085a03399d9ce63841fcee0527a9a4d..480796f756de94a58821e33fbbf6168c9f73eb02 100644 (file)
@@ -7,7 +7,7 @@
  * Author:        Thomas Davis (tadavis@jps.net)
  * Created at:    
  * Modified at:   Tue Feb 22 10:05:06 2000
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * Modified by:   Dag Brattli <dag@brattli.net>
  * 
  *     Copyright (c) 1999-2000 Dag Brattli
  *     Copyright (c) 1998-1999 Thomas Davis, 
@@ -252,6 +252,7 @@ static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base)
                IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
 
        irport->qos.min_turn_time.bits = 0x07;
+       irport->qos.window_size.bits = 0x01;
        irda_qos_bits_to_value(&irport->qos);
 
        irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
@@ -508,6 +509,10 @@ static void ircc_change_speed(void *priv, __u32 speed)
        outb(0x00, iobase+IRCC_MASTER);
 
        switch (speed) {
+       default:
+               IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
+                          speed);
+               /* FALLTHROUGH */
        case 9600:
        case 19200:
        case 38400:
@@ -535,10 +540,6 @@ static void ircc_change_speed(void *priv, __u32 speed)
                fast = IRCC_LCR_A_FAST;
                IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
                break;
-       default:
-               IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
-                          speed);
-               return;
        }
        
        register_bank(iobase, 0);
@@ -620,7 +621,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        if ((speed = irda_get_speed(skb)) != self->io.speed) {
                /* Check for empty frame */
                if (!skb->len) {
-                       smc_ircc_change_speed(self, speed); 
+                       ircc_change_speed(self, speed); 
                        return 0;
                } else
                        self->new_speed = speed;
@@ -638,7 +639,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                int bofs;
 
                /* 
-                * Compute who many BOFS (STA or PA's) we need to waste the
+                * Compute how many BOFs (STA or PA's) we need to waste the
                 * min turn time given the speed of the link.
                 */
                bofs = mtt * (self->io.speed / 1000) / 8000;
@@ -650,7 +651,6 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                /* Transmit frame */
                ircc_dma_xmit(self, iobase, 0);
        }
-       
        spin_unlock_irqrestore(&self->lock, flags);
        dev_kfree_skb(skb);
 
@@ -767,6 +767,7 @@ static int ircc_dma_receive(struct ircc_cb *self, int iobase)
 
        setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
                  DMA_RX_MODE);
+
        /* Set max Rx frame size */
        register_bank(iobase, 4);
        outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
@@ -795,7 +796,6 @@ static int ircc_dma_receive(struct ircc_cb *self, int iobase)
  *
  *    Finished with receiving frames
  *
- *    
  */
 static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
 {
index 39a130436f12b72b183386d700230739d5ed1d17..04d91c232ad9b8ea4e5f9736d3edc15689b99f8f 100644 (file)
@@ -275,7 +275,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
   if ((speed = irda_get_speed(skb)) != self->io.speed) {
        /* Check for empty frame */
        if (!skb->len) {
-           toshoboe_change_speed(self, speed); 
+           toshoboe_setbaud(self, speed); 
            return 0;
        } else
            self->new_speed = speed;
index e4d5987963c1d98460809ede52bf2055b9e20e8c..af184f47294f4576efd720bc23f9949caa9d8204 100644 (file)
@@ -1,9 +1,16 @@
-/* $Id: sunhme.c,v 1.99 2000/11/10 05:44:33 davem Exp $
+/* $Id: sunhme.c,v 1.100 2000/11/12 10:23:30 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
  *
  * Copyright (C) 1996, 1998, 1999 David S. Miller (davem@redhat.com)
+ *
+ * Changes :
+ * 2000/11/11 Willy Tarreau <willy AT meta-x.org>
+ *   - port to non-sparc architectures. Tested only on x86 and
+ *     only currently works with QFE PCI cards.
+ *   - ability to specify the MAC address at module load time by passing this
+ *     argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50
  */
 
 static char *version =
@@ -32,17 +39,20 @@ static char *version =
 #include <linux/errno.h>
 #include <asm/byteorder.h>
 
+#ifdef __sparc__
 #include <asm/idprom.h>
 #include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
 #ifndef __sparc_v9__
 #include <asm/io-unit.h>
 #endif
 #include <asm/uaccess.h>
+#endif
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -50,14 +60,25 @@ static char *version =
 
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
+#ifdef __sparc__
 #include <asm/pbm.h>
 #endif
+#endif
 
 #include "sunhme.h"
 
+
+static int macaddr[6];
+
+/* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
+MODULE_PARM(macaddr, "6i");
+
 static struct happy_meal *root_happy_dev = NULL;
 
+#ifdef CONFIG_SBUS
 static struct quattro *qfe_sbus_list = NULL;
+#endif
+
 #ifdef CONFIG_PCI
 static struct quattro *qfe_pci_list = NULL;
 #endif
@@ -282,9 +303,25 @@ do {       (__txd)->tx_addr = cpu_to_le32(__addr); \
 #endif
 #endif
 
-#define DMA_BIDIRECTIONAL      SBUS_DMA_BIDIRECTIONAL
-#define DMA_FROMDEVICE         SBUS_DMA_FROMDEVICE
-#define DMA_TODEVICE           SBUS_DMA_TODEVICE
+
+#ifdef SBUS_DMA_BIDIRECTIONAL
+#      define DMA_BIDIRECTIONAL        SBUS_DMA_BIDIRECTIONAL
+#else
+#      define DMA_BIDIRECTIONAL        0
+#endif
+
+#ifdef SBUS_DMA_FROMDEVICE
+#      define DMA_FROMDEVICE           SBUS_DMA_FROMDEVICE
+#else
+#      define DMA_TODEVICE             1
+#endif
+
+#ifdef SBUS_DMA_TODEVICE
+#      define DMA_TODEVICE             SBUS_DMA_TODEVICE
+#else
+#      define DMA_FROMDEVICE           2
+#endif
+
 
 /* Oh yes, the MIF BitBang is mighty fun to program.  BitBucket is more like it. */
 static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit)
@@ -2071,6 +2108,7 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        HMD(("done\n"));
 }
 
+#ifdef CONFIG_SBUS
 static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs)
 {
        struct quattro *qp = (struct quattro *) cookie;
@@ -2112,6 +2150,7 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
        }
        HMD(("done\n"));
 }
+#endif
 
 static int happy_meal_open(struct net_device *dev)
 {
@@ -2127,8 +2166,14 @@ static int happy_meal_open(struct net_device *dev)
                if (request_irq(dev->irq, &happy_meal_interrupt,
                                SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
                        HMD(("EAGAIN\n"));
+#ifdef __sparc__
                        printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
                               __irq_itoa(dev->irq));
+#else
+                       printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n",
+                              dev->irq);
+#endif
+
                        return -EAGAIN;
                }
        }
@@ -2168,6 +2213,7 @@ static int happy_meal_close(struct net_device *dev)
 #define SXD(x)
 #endif
 
+#ifdef CONFIG_SBUS
 static void happy_meal_tx_timeout(struct net_device *dev)
 {
        struct happy_meal *hp = (struct happy_meal *) dev->priv;
@@ -2181,6 +2227,7 @@ static void happy_meal_tx_timeout(struct net_device *dev)
        happy_meal_init(hp, 0);
        netif_wake_queue(dev);
 }
+#endif
 
 static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -2541,11 +2588,25 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
                printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
                       dev->name);
 
-       /* Quattro local-mac-address... */
-       if (qfe_slot != -1 && prom_getproplen(sdev->prom_node,"local-mac-address")==6)
-               prom_getproperty(sdev->prom_node,"local-mac-address",dev->dev_addr,6);
-       else
-               memcpy(dev->dev_addr,idprom->id_ethaddr,6);
+       /* If user did not specify a MAC address specifically, use
+        * the Quattro local-mac-address property...
+        */
+       for (i = 0; i < 6; i++) {
+               if (macaddr[i] != 0)
+                       break;
+       }
+       if (i < 6) { /* a mac address was given */
+               for (i = 0; i < 6; i++)
+                       dev->dev_addr[i] = macaddr[i];
+       } else if (qfe_slot != -1 &&
+                  prom_getproplen(sdev->prom_node,
+                                  "local-mac-address") == 6) {
+               prom_getproperty(sdev->prom_node, "local-mac-address",
+                                dev->dev_addr, 6);
+       } else {
+               memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+       }
+
        for (i = 0; i < 6; i++)
                printk("%2.2x%c",
                       dev->dev_addr[i], i == 5 ? ' ' : ':');
@@ -2683,13 +2744,17 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
 static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pdev)
 {
        struct quattro *qp = NULL;
+#ifdef __sparc__
        struct pcidev_cookie *pcp;
+       int node;
+#endif
        struct happy_meal *hp;
        unsigned long hpreg_base;
-       int i, node, qfe_slot = -1;
+       int i, qfe_slot = -1;
        char prom_name[64];
 
        /* Now make sure pci_dev cookie is there. */
+#ifdef __sparc__
        pcp = pdev->sysdata;
        if (pcp == NULL || pcp->prom_node == -1) {
                printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
@@ -2698,6 +2763,11 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
        node = pcp->prom_node;
        
        prom_getstring(node, "name", prom_name, sizeof(prom_name));
+#else
+#warning This needs to be corrected... -DaveM
+       strcpy(prom_name, "qfe");
+#endif
+
        if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) {
                qp = quattro_pci_find(pdev);
                if (qp == NULL)
@@ -2763,10 +2833,27 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
        }
        hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000);
 
-       if (qfe_slot != -1 && prom_getproplen(node, "local-mac-address") == 6)
-               prom_getproperty(node, "local-mac-address", dev->dev_addr, 6);
-       else
-               memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+       for (i = 0; i < 6; i++) {
+               if (macaddr[i] != 0)
+                       break;
+       }
+       if (i < 6) { /* a mac address was given */
+               for (i = 0; i < 6; i++)
+                       dev->dev_addr[i] = macaddr[i];
+       } else {
+#ifdef __sparc__
+               if (qfe_slot != -1 &&
+                   prom_getproplen(node, "local-mac-address") == 6) {
+                       prom_getproperty(node, "local-mac-address",
+                                        dev->dev_addr, 6);
+               } else {
+                       memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+               }
+#else
+               memset(dev->dev_addr, 0, 6);
+#endif
+       }
+       
        for (i = 0; i < 6; i++)
                printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
 
@@ -2779,9 +2866,14 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
        hp->bigmacregs = (hpreg_base + 0x6000UL);
        hp->tcvregs    = (hpreg_base + 0x7000UL);
 
+#ifdef __sparc__
        hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
        if (hp->hm_revision == 0xff)
                hp->hm_revision = 0xa0;
+#else
+       /* works with this on non-sparc hosts */
+       hp->hm_revision = 0x20;
+#endif
 
        /* Now enable the feature flags we can. */
        if (hp->hm_revision == 0x20 || hp->hm_revision == 0x21)
index 57b5d7f5e2b3c9ac8bafe63e62491e975d7f63b0..846a3744d9029b186f0f3ffe88805a6588bfa6d3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunhme.h,v 1.30 2000/02/18 13:49:26 davem Exp $
+/* $Id: sunhme.h,v 1.31 2000/11/12 10:23:30 davem Exp $
  * sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver.
  *           Also known as the "Happy Meal".
  *
@@ -9,6 +9,7 @@
 #define _SUNHME_H
 
 #include <linux/config.h>
+#include <linux/pci.h>
 
 /* Happy Meal global registers. */
 #define GREG_SWRESET   0x000UL /* Software Reset  */
@@ -589,7 +590,9 @@ struct quattro {
        struct quattro          *next;
 
        /* PROM ranges, if any. */
+#ifdef CONFIG_SBUS
        struct linux_prom_ranges  ranges[8];
+#endif
        int                       nranges;
 };
 
index 4edc3d0b9e2956139e968670056368578259fd1f..1b0e2161eed59067d8e15efecd07259ecb9ab791 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
index b0e5026fc7a5520c0c355ef231da3dba0906be74..88608c5f54a8a52dd7364bfa6dcdcac764ad1eeb 100644 (file)
@@ -12,7 +12,7 @@
    Copyright 1992 - 2000 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Tue Aug 15 16:56:35 2000 by makisara@kai.makisara.local
+   Last modified: Mon Nov 13 21:01:09 2000 by makisara@kai.makisara.local
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -976,7 +976,7 @@ static int st_flush(struct file *filp)
                     ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
                      (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
                       SRpnt->sr_sense_buffer[5] |
-                      SRpnt->sr_sense_buffer[6]) == 0))) {
+                      SRpnt->sr_sense_buffer[6]) != 0))) {
                        /* Filter out successful write at EOM */
                        scsi_release_request(SRpnt);
                        SRpnt = NULL;
@@ -2495,10 +2495,8 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                        STps->drv_block = 0;
                        STps->eof = ST_NOEOF;
                } else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
-                       if (fileno >= 0)
+                       if (STps->drv_file >= 0)
                                STps->drv_file = fileno + undone;
-                       else
-                               STps->drv_file = fileno;
                        STps->drv_block = 0;
                        STps->eof = ST_NOEOF;
                } else if (cmd_in == MTFSR) {
@@ -2519,10 +2517,8 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
                                STps->drv_file--;
                                STps->drv_block = (-1);
                        } else {
-                               if (blkno >= 0)
+                               if (STps->drv_block >= 0)
                                        STps->drv_block = blkno + undone;
-                               else
-                                       STps->drv_block = (-1);
                        }
                        STps->eof = ST_NOEOF;
                } else if (cmd_in == MTEOM) {
index a3005f6bc78b8e95cc36c23002605b791f31b696..6c3663a976b3bf1760ae805a7a3470e09310bacb 100644 (file)
@@ -84,8 +84,6 @@ EXPORT_NO_SYMBOLS;
 
 #define CS4281_MAGIC  ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)
 
-#include <linux/version.h>
-
 // Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG
 //
 #define CSDEBUG_INTERFACE 1
index f9fd75161e6832b39e938fef11a1f9685028a9c3..6fb1ac7627e06a3237f4cb7481287ff9ccd26d1f 100644 (file)
@@ -14,6 +14,8 @@
  * 11-10-2000  Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
  *             Added __init to gus_midi_init()
  */
+
+#include "linux/init.h"
 #include "sound_config.h"
 
 #include "gus.h"
index add5de9c22d485a9d7219f768ae007f85ddda725..30a5357a5d0821da990d20ba74fd7ce7318b690f 100644 (file)
@@ -17,7 +17,7 @@
  * Bartlomiej Zolnierkiewicz : added some __init/__exit
  */
  
+#include <linux/init.h> 
 #include <linux/config.h>
 
 #define GUSPNP_AUTODETECT
index 5c388ae8a088adfa965766112c55e47f04aa7e2b..8ed87ac386596e8a0e6ce3367ed03f8028d05cf5 100644 (file)
@@ -14,6 +14,7 @@
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
  * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
  */
+#include <linux/init.h>
 #include "sound_config.h"
 
 #include <linux/ultrasound.h>
index 93ee7da26dec694a06c0eb6cfe3165570493d5bb..66e36117ec1747ed26b324b16c6609e1feec446d 100644 (file)
@@ -13,6 +13,7 @@
  * Bartlomiej Zolnierkiewicz   : Added __init to pas_init_mixer()
  */
 
+#include <linux/init.h>
 #include "sound_config.h"
 
 #include "pas2.h"
index 92a918a2cdb18062892136a615dd4bf977fa1530..fdc8ef1f76b5a18ec25fb8b561bd577c7577cb14 100644 (file)
@@ -16,6 +16,7 @@
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
  * Bartlomiej Zolnierkiewicz : added __init to pas_init_mixer()
  */
+#include <linux/init.h>
 #include "sound_config.h"
 
 #include "pas2.h"
index f3be2c052390243f06a6ffaefbf19894ce26a002..50b53fa174e7cc649c00bdace0aec2b21a3c581a 100644 (file)
@@ -15,6 +15,7 @@
  * Bartlomiej Zolnierkiewicz : Added __init to pas_pcm_init()
  */
 
+#include <linux/init.h>
 #include "sound_config.h"
 
 #include "pas2.h"
index 78f946efef48bcf3d136553d778cc642b69b847c..e700400576d814431793ac9cf6ed4261f02c9178 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/init.h>
+
 unsigned char page_zero[] __initdata = {
 0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
 0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
index 11afdcfa2e4df4b43cbf33b8c23dc0cd6c5da4fa..5503e6e66644a2d95979beddf856537d891366f3 100644 (file)
@@ -51,6 +51,7 @@
  * patches, and shared their sucesses!
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
index 47c33826f9fa55c5e60ea0ede4c1ced810d24ad8..ef46e5b52226f6f6f192c381a9decffecdc78795 100644 (file)
@@ -588,7 +588,7 @@ static int proc_bulk(struct dev_state *ps, void *arg)
                return -EINVAL;
        len1 = bulk.len;
        if (len1 > PAGE_SIZE)
-               len1 = PAGE_SIZE;
+               return -EINVAL;
        if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
                return -ENOMEM;
        tmo = (bulk.timeout * HZ + 999) / 1000;
index e66f2e57a92ec48dc3b8ccba51c7a6d0e75f9330..2f88242f3d099d18b80be78658578f3fb850ca4d 100644 (file)
@@ -30,7 +30,7 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-static const char version[] = "1.25";
+static const char version[] = "1.28";
 
 #define __NO_VERSION__
 
@@ -51,23 +51,6 @@ static const char version[] = "1.25";
 
 #include "ov511.h"
 
-#undef OV511_GBR422            /* Experimental -- sets the 7610 to GBR422 */
-
-static struct usb_device_id ov511_table [] = {
-
-    { idVendor: 0x05a9, idProduct: 0x0511, bInterfaceClass: 0xFF },
-    { idVendor: 0x05a9, idProduct: 0xA511, bInterfaceClass: 0xFF },
-    { idVendor: 0x05a9, idProduct: 0x0002, bInterfaceClass: 0xFF },
-
-    { idVendor: 0x0813, idProduct: 0x0511, bInterfaceClass: 0xFF },
-    { idVendor: 0x0813, idProduct: 0xA511, bInterfaceClass: 0xFF },
-
-    { }                                                /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, ov511_table);
-
-
 #define OV511_I2C_RETRIES 3
 
 /* Video Size 640 x 480 x 3 bytes for RGB */
@@ -75,8 +58,6 @@ MODULE_DEVICE_TABLE (usb, ov511_table);
 #define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
 
 #define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384)
-#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : \
-                    ((p) == VIDEO_PALETTE_YUV422 ? 16 : 24))
 
 /* PARAMETER VARIABLES: */
 static int autoadjust = 1;    /* CCD dynamically changes exposure, etc... */
@@ -89,7 +70,7 @@ static int autoadjust = 1;    /* CCD dynamically changes exposure, etc... */
  * 5=highly repetitive mesgs
  * NOTE: This should be changed to 0, 1, or 2 for production kernels
  */
-static int debug = 3;
+static int debug = 0;
 
 /* Fix vertical misalignment of red and blue at 640x480 */
 static int fix_rgb_offset = 0;
@@ -127,6 +108,13 @@ static int compress = 0;
 /* Display test pattern - doesn't work yet either */
 static int testpat = 0;
 
+/* Setting this to 1 will make the sensor output GBR422 instead on YUV420. Only
+ * affects RGB24 mode. */
+static int sensor_gbr = 0;
+
+/* Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details. */
+static int dumppix = 0;
+
 MODULE_PARM(autoadjust, "i");
 MODULE_PARM_DESC(autoadjust, "CCD dynamically changes exposure");
 MODULE_PARM(debug, "i");
@@ -153,6 +141,10 @@ MODULE_PARM(compress, "i");
 MODULE_PARM_DESC(compress, "Turn on compression (not functional yet)");
 MODULE_PARM(testpat, "i");
 MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)");
+MODULE_PARM(sensor_gbr, "i");
+MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420");
+MODULE_PARM(dumppix, "i");
+MODULE_PARM_DESC(dumppix, "Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details");
 
 MODULE_AUTHOR("Mark McClelland <mwm@i.am> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>");
 MODULE_DESCRIPTION("OV511 USB Camera Driver");
@@ -182,6 +174,15 @@ static struct cam_list clist[] = {
        {  -1, NULL }
 };
 
+static __devinitdata struct usb_device_id device_table [] = {
+       { idVendor: 0x05a9, idProduct: 0x0511 },  /* OV511 */
+       { idVendor: 0x05a9, idProduct: 0xA511 },  /* OV511+ */
+       { idVendor: 0x0813, idProduct: 0x0002 },  /* Intel Play Me2Cam OV511+ */
+       { }  /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, device_table);
+
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 static struct palette_list plist[] = {
        { VIDEO_PALETTE_GREY,   "GREY" },
@@ -372,6 +373,7 @@ static int ov511_read_proc(char *page, char **start, off_t off,
                ov511->bridge == BRG_OV511PLUS ? "OV511+" :
                "unknown");
        out += sprintf (out, "sensor          : %s\n",
+               ov511->sensor == SEN_OV6620 ? "OV6620" :
                ov511->sensor == SEN_OV7610 ? "OV7610" :
                ov511->sensor == SEN_OV7620 ? "OV7620" :
                ov511->sensor == SEN_OV7620AE ? "OV7620AE" :
@@ -463,7 +465,6 @@ static void proc_ov511_destroy(void)
 }
 #endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
 
-
 /**********************************************************************
  *
  * Camera interface
@@ -715,7 +716,7 @@ static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
 {
        int rc;
        
-       PDEBUG(3, "Reset: type=0x%X", reset_type);
+       PDEBUG(4, "Reset: type=0x%X", reset_type);
        rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
        rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
 
@@ -844,14 +845,21 @@ ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
        } else if ((ov511->sensor == SEN_OV7620) 
                 || (ov511->sensor == SEN_OV7620AE)) {
 #if 0
-               cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
-               cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
-               // DEBUG_CODE
-               PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
-                ov511_i2c_read(dev, OV7610_REG_BRT)); 
+               int cur_sat, new_sat, tmp;
 
-               if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+               cur_sat = ov511_i2c_read(dev, OV7610_REG_BLUE);
+
+               tmp = (p->hue >> 8) - cur_sat;
+               new_sat = (tmp < 0) ? (-tmp) | 0x80 : tmp;
+
+               PDEBUG(1, "cur=%d target=%d diff=%d", cur_sat, p->hue >> 8, tmp); 
+
+               if (ov511_i2c_write(dev, OV7610_REG_BLUE, new_sat) < 0)
                        return -EIO;
+
+               // DEBUG_CODE
+               PDEBUG(1, "hue=%d", ov511_i2c_read(dev, OV7610_REG_BLUE)); 
+
 #endif
        }
 
@@ -897,6 +905,23 @@ ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
        return 0;
 }
 
+/* Returns number of bits per pixel (regardless of where they are located; planar or
+ * not), or zero for unsupported format.
+ */
+static int ov511_get_depth(int palette)
+{
+       switch (palette) {
+       case VIDEO_PALETTE_GREY:    return 8;
+       case VIDEO_PALETTE_RGB565:  return 16;
+       case VIDEO_PALETTE_RGB24:   return 24;  
+       case VIDEO_PALETTE_YUV422:  return 16;
+       case VIDEO_PALETTE_YUYV:    return 16;
+       case VIDEO_PALETTE_YUV420:  return 24;
+       case VIDEO_PALETTE_YUV422P: return 24; /* Planar */
+       default:                    return 0;  /* Invalid format */
+       }
+}
+
 /* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */
 static struct mode_list mlist[] = {
        /* W    H   C  PXCNT LNCNT PXDIV LNDIV M420  COMA  COML */
@@ -932,6 +957,12 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
        if (ov511_stop(ov511->dev) < 0)
                return -EIO;
 
+       /* Dumppix only works with RGB24 */
+       if (dumppix && (mode != VIDEO_PALETTE_RGB24)) {
+               err("dumppix only supported with RGB 24");
+               return -EINVAL;
+       }
+
        if (mode == VIDEO_PALETTE_GREY) {
                ov511_reg_write(dev, 0x16, 0x00);
                if (ov511->sensor == SEN_OV7610
@@ -968,9 +999,9 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
                break;
        case SEN_OV6620:
                hwsbase = 0x38;
-               hwebase = 0x39;
-               vwsbase = 0x03;
-               vwebase = 0x04;
+               hwebase = 0x3a;
+               vwsbase = 0x05;
+               vwebase = 0x06;
                break;
        case SEN_OV7620:
                hwsbase = 0x2c;
@@ -1054,13 +1085,16 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
                /* Calculate and set the clock divisor */
                clock = ((sub_flag ? ov511->subw * ov511->subh : width * height)
                        * (mlist[i].color ? 3 : 2) / 2) / 66000;
+#if 0
+               clock *= cams;
+#endif
                ov511_i2c_write(dev, 0x11, clock);
 
-#ifdef OV511_GBR422
-               ov511_i2c_write(dev, 0x12, mlist[i].common_A | 0x08);
-#else
-               ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00));
-#endif
+               /* We only have code to convert GBR -> RGB24 */
+               if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr)
+                       ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x0a:0x08));
+               else
+                       ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00));
 
                /* 7620/6620 don't have register 0x35, so play it safe */
                if (ov511->sensor == SEN_OV7610 ||
@@ -1128,7 +1162,7 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
 
 static inline void
 ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
-       int rowPixels, unsigned char * rgb)
+       int rowPixels, unsigned char * rgb, int bits)
 {
        const int rvScale = 91881;
        const int guScale = -22553;
@@ -1149,14 +1183,32 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
        yTL *= yScale; yTR *= yScale;
        yBL *= yScale; yBR *= yScale;
 
-       /* Write out top two pixels */
-       rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
-       rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
+       if (bits == 24) {
+               /* Write out top two pixels */
+               rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
+               rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
 
-       /* Skip down to next line to write out bottom two pixels */
-       rgb += 3 * rowPixels;
-       rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
-       rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
+               /* Skip down to next line to write out bottom two pixels */
+               rgb += 3 * rowPixels;
+               rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
+               rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
+       } else if (bits == 16) {
+               /* Write out top two pixels */
+               rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) | ((LIMIT(g+yTL) << 3) & 0xE0);
+               rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) | (LIMIT(r+yTL) & 0xF8);
+
+               rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) | ((LIMIT(g+yTR) << 3) & 0xE0);
+               rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) | (LIMIT(r+yTR) & 0xF8);
+
+               /* Skip down to next line to write out bottom two pixels */
+               rgb += 2 * rowPixels;
+
+               rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) | ((LIMIT(g+yBL) << 3) & 0xE0);
+               rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) | (LIMIT(r+yBL) & 0xF8);
+
+               rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) | ((LIMIT(g+yBR) << 3) & 0xE0);
+               rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) | (LIMIT(r+yBR) & 0xF8);
+       }
 }
 
 /*
@@ -1182,7 +1234,7 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
  * Note that the U and V data in one segment represents a 16 x 16 pixel
  * area, but the Y data represents a 32 x 8 pixel area.
  *
- * If OV511_DUMPPIX is defined, _parse_data just dumps the incoming segments,
+ * If dumppix module param is set, _parse_data just dumps the incoming segments,
  * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
  * this puts the data on the standard output and can be analyzed with the
  * parseppm.c utility I wrote.  That's a much faster way for figuring out how
@@ -1192,14 +1244,8 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
 #define HDIV 8
 #define WDIV (256/HDIV)
 
-#undef OV511_DUMPPIX
-
-/* #define this and OV511_DUMPPIX to disable parsing of UV data */
-#undef OV511_FORCE_MONO
-
-#ifdef OV511_GBR422
 static void
-ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
+ov511_parse_gbr422_to_rgb24(unsigned char *pIn0, unsigned char *pOut0,
                       int iOutY, int iOutUV, int iHalf, int iWidth)
 {
        int k, l, m;
@@ -1246,14 +1292,12 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
        }
 }
 
-#else
-
 static void
-ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
-                      int iOutY, int iOutUV, int iHalf, int iWidth)
+ov511_parse_yuv420_to_rgb(unsigned char *pIn0, unsigned char *pOut0,
+                      int iOutY, int iOutUV, int iHalf, int iWidth, int bits)
 {
-#ifndef OV511_DUMPPIX
        int k, l, m;
+       int bytes = bits >> 3;
        unsigned char *pIn;
        unsigned char *pOut, *pOut1;
 
@@ -1266,11 +1310,11 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
                        for (l = 0; l < 8; l++) {
                                for (m = 0; m < 8; m++) {
                                        *pOut1 = *pIn++;
-                                       pOut1 += 3;
+                                       pOut1 += bytes;
                                }
-                               pOut1 += (iWidth - 8) * 3;
+                               pOut1 += (iWidth - 8) * bytes;
                        }
-                       pOut += 8 * 3;
+                       pOut += 8 * bytes;
                }
        }
 
@@ -1280,16 +1324,16 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
        for (l = 0; l < 4; l++) {
                for (m=0; m<8; m++) {
                        int y00 = *(pOut);
-                       int y01 = *(pOut+3);
-                       int y10 = *(pOut+iWidth*3);
-                       int y11 = *(pOut+iWidth*3+3);
+                       int y01 = *(pOut+bytes);
+                       int y10 = *(pOut+iWidth*bytes);
+                       int y11 = *(pOut+iWidth*bytes+bytes);
                        int v   = *(pIn+64) - 128;
                        int u   = *pIn++ - 128;
                        ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth,
-                               pOut);
-                       pOut += 6;
+                               pOut, bits);
+                       pOut += 2 * bytes;
                }
-               pOut += (iWidth*2 - 16) * 3;
+               pOut += (iWidth*2 - 16) * bytes;
        }
 
        /* Just copy the other UV rows */
@@ -1297,9 +1341,9 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
                for (m = 0; m < 8; m++) {
                        *pOut++ = *(pIn + 64);
                        *pOut = *pIn++;
-                       pOut += 5;
+                       pOut += 2 * bytes - 1;
                }
-               pOut += (iWidth*2 - 16) * 3;
+               pOut += (iWidth*2 - 16) * bytes;
        }
 
        /* Calculate values if it's the second half */
@@ -1317,72 +1361,65 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
                                        int v   = *pOut1 - 128;
                                        int u   = *(pOut1+1) - 128;
                                        ov511_move_420_block(y00, y01, y10,
-                                               y11, u, v, iWidth, pOut1);
-                                       pOut1 += 6;
+                                               y11, u, v, iWidth, pOut1, bits);
+                                       pOut1 += 2 * bytes;
                                }
-                               pOut1 += (iWidth*2 - 8) * 3;
+                               pOut1 += (iWidth*2 - 8) * bytes;
                                pIn += 8;
                        }
-                       pOut += 8 * 3;
-               }
-       }
-#else
-
-#ifndef OV511_FORCE_MONO
-       /* Just dump pix data straight out for debug */
-       int i, j;
-
-       pOut0 += iOutY;
-       for (i = 0; i < HDIV; i++) {
-               for (j = 0; j < WDIV; j++) {
-                       *pOut0++ = *pIn0++;
-                       *pOut0++ = *pIn0++;
-                       *pOut0++ = *pIn0++;
+                       pOut += 8 * bytes;
                }
-               pOut0 += (iWidth - WDIV) * 3;
        }
-#else
+}
 
-#if 1
-       /* This converts the Y data to "black-and-white" RGB data */
-       /* Useful for experimenting with compression */
-       int k, l, m;
+static void
+ov511_dumppix(unsigned char *pIn0, unsigned char *pOut0,
+             int iOutY, int iOutUV, int iHalf, int iWidth)
+{
+       int i, j, k;
        unsigned char *pIn, *pOut, *pOut1;
 
-       pIn = pIn0 + 128;
-       pOut = pOut0 + iOutY;
-       for (k = 0; k < 4; k++) {
-               pOut1 = pOut;
-               for (l = 0; l < 8; l++) {
-                       for (m = 0; m < 8; m++) {
-                               *pOut1++ = *pIn;
-                               *pOut1++ = *pIn;
-                               *pOut1++ = *pIn++;
+       switch (dumppix) {
+       case 1: /* Just dump YUV data straight out for debug */
+               pOut0 += iOutY;
+               for (i = 0; i < HDIV; i++) {
+                       for (j = 0; j < WDIV; j++) {
+                               *pOut0++ = *pIn0++;
+                               *pOut0++ = *pIn0++;
+                               *pOut0++ = *pIn0++;
                        }
-                       pOut1 += (iWidth - 8) * 3;
+                       pOut0 += (iWidth - WDIV) * 3;
                }
-               pOut += 8 * 3;
-       }
-#else
-       /* This will dump the Y channel data stream as-is */ 
-       int count;
-       unsigned char *pIn, *pOut;
-
-       pIn = pIn0 + 128;
-       pOut = pOut0 + output_offset;
-       for (count = 0; count < 256; count++) {
-               *pOut++ = *pIn;
-               *pOut++ = *pIn;
-               *pOut++ = *pIn++;
-               output_offset += 3;
-       }       
-#endif
-
-#endif
-
-#endif
+               break;
+       case 2: /* This converts the Y data to "black-and-white" RGB data */
+               /* Useful for experimenting with compression */
+               pIn = pIn0 + 128;
+               pOut = pOut0 + iOutY;
+               for (i = 0; i < 4; i++) {
+                       pOut1 = pOut;
+                       for (j = 0; j < 8; j++) {
+                               for (k = 0; k < 8; k++) {
+                                       *pOut1++ = *pIn;
+                                       *pOut1++ = *pIn;
+                                       *pOut1++ = *pIn++;
+                               }
+                               pOut1 += (iWidth - 8) * 3;
+                       }
+                       pOut += 8 * 3;
+               }
+               break;
+       case 3: /* This will dump only the Y channel data stream as-is */
+               pIn = pIn0 + 128;
+               pOut = pOut0 + output_offset;
+               for (i = 0; i < 256; i++) {
+                       *pOut++ = *pIn;
+                       *pOut++ = *pIn;
+                       *pOut++ = *pIn++;
+                       output_offset += 3;
+               }
+               break;
+       } /* End switch (dumppix) */
 }
-#endif
 
 /* This converts YUV420 segments to YUYV */
 static void
@@ -1677,6 +1714,11 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
                        /* Frame start */
                        PDEBUG(4, "Frame start, framenum = %d", ov511->curframe);
 
+#if 0
+                       /* Make sure no previous data carries over; necessary
+                        * for compression experimentation */
+                       memset(frame->data, 0, MAX_DATA_SIZE);
+#endif
                        output_offset = 0;
 
                        /* Check to see if it's a snapshot frame */
@@ -1755,8 +1797,19 @@ check_middle:
                                ov511_parse_data_grey (pData, pOut, iOutY, frame->width);
                                break;
                        case VIDEO_PALETTE_RGB24:
-                               ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV,
-                                       iY & 1, frame->width);
+                               if (dumppix)
+                                       ov511_dumppix(pData, pOut, iOutY, iOutUV,
+                                               iY & 1, frame->width);
+                               else if (sensor_gbr)
+                                       ov511_parse_gbr422_to_rgb24(pData, pOut, iOutY, iOutUV,
+                                               iY & 1, frame->width);
+                               else
+                                       ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV,
+                                               iY & 1, frame->width, 24);
+                               break;
+                       case VIDEO_PALETTE_RGB565:
+                               ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV,
+                                       iY & 1, frame->width, 16);
                                break;
                        case VIDEO_PALETTE_YUV422:
                        case VIDEO_PALETTE_YUYV:
@@ -1797,11 +1850,20 @@ check_middle:
 static void ov511_isoc_irq(struct urb *urb)
 {
        int len;
-       struct usb_ov511 *ov511 = urb->context;
+       struct usb_ov511 *ov511;
        struct ov511_sbuf *sbuf;
 
-       if (!ov511->dev)
+       if (!urb->context) {
+               PDEBUG(4, "no context");
                return;
+       }
+
+       ov511 = (struct usb_ov511 *) urb->context;
+
+       if (!ov511->dev || !ov511->user) {
+               PDEBUG(4, "no device, or not open");
+               return;
+       }
 
        if (!ov511->streaming) {
                PDEBUG(4, "hmmm... not streaming, but got interrupt");
@@ -1820,6 +1882,8 @@ static void ov511_isoc_irq(struct urb *urb)
        /* Move to the next sbuf */
        ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF;
 
+       urb->dev = ov511->dev;
+
        return;
 }
 
@@ -1887,6 +1951,7 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
                ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb;
 
        for (n = 0; n < OV511_NUMSBUF; n++) {
+               ov511->sbuf[n].urb->dev = ov511->dev;
                err = usb_submit_urb(ov511->sbuf[n].urb);
                if (err)
                        err("init isoc: usb_submit_urb(%d) ret %d", n, err);
@@ -2094,7 +2159,7 @@ static void ov511_dealloc(struct usb_ov511 *ov511, int now)
 static int ov511_open(struct video_device *dev, int flags)
 {
        struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
-       int err = 0;
+       int err;
 
        MOD_INC_USE_COUNT;
        PDEBUG(4, "opening");
@@ -2189,8 +2254,8 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                b.audios = 0;
                b.maxwidth = ov511->maxwidth;
                b.maxheight = ov511->maxheight;
-               b.minwidth = 32;
-               b.minheight = 16;
+               b.minwidth = 160;
+               b.minheight = 120;
 
                if (copy_to_user(arg, &b, sizeof(b)))
                        return -EFAULT;
@@ -2252,12 +2317,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                if (copy_from_user(&p, arg, sizeof(p)))
                        return -EFAULT;
 
-               if (p.palette != VIDEO_PALETTE_GREY &&
-                   p.palette != VIDEO_PALETTE_RGB24 &&
-                   p.palette != VIDEO_PALETTE_YUV422 &&
-                   p.palette != VIDEO_PALETTE_YUYV &&
-                   p.palette != VIDEO_PALETTE_YUV420 &&
-                   p.palette != VIDEO_PALETTE_YUV422P)
+               if (!ov511_get_depth(p.palette))
                        return -EINVAL;
                        
                if (ov7610_set_picture(ov511, &p))
@@ -2388,7 +2448,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
        case VIDIOCMCAPTURE:
        {
                struct video_mmap vm;
-               int ret;
+               int ret, depth;
 
                if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
                        return -EFAULT;
@@ -2397,19 +2457,21 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
                        vm.frame, vm.width, vm.height, vm.format);
 
-               if (vm.format != VIDEO_PALETTE_RGB24 &&
-                   vm.format != VIDEO_PALETTE_YUV422 &&
-                   vm.format != VIDEO_PALETTE_YUYV &&
-                   vm.format != VIDEO_PALETTE_YUV420 &&
-                   vm.format != VIDEO_PALETTE_YUV422P &&
-                   vm.format != VIDEO_PALETTE_GREY)
+               depth = ov511_get_depth(vm.format);
+               if (!depth) {
+                       err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
                        return -EINVAL;
+               }
 
-               if ((vm.frame != 0) && (vm.frame != 1))
+               if ((vm.frame != 0) && (vm.frame != 1)) {
+                       err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
                        return -EINVAL;
-                               
-               if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight)
+               }
+
+               if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight) {
+                       err("VIDIOCMCAPTURE: requested dimensions too big");
                        return -EINVAL;
+               }
 
                if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
                        return -EBUSY;
@@ -2437,7 +2499,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                ov511->frame[vm.frame].format = vm.format;
                ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
                ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format);
-               ov511->frame[vm.frame].depth = GET_DEPTH(vm.format);
+               ov511->frame[vm.frame].depth = depth;
 
                /* Mark it as ready */
                ov511->frame[vm.frame].grabstate = FRAME_READY;
@@ -2496,6 +2558,13 @@ redo:
                                goto redo;
                        }                       
                case FRAME_DONE:
+                       if (ov511->snap_enabled && !ov511->frame[frame].snapshot) {
+                               int ret;
+                               if ((ret = ov511_new_frame(ov511, frame)) < 0)
+                                       return ret;
+                               goto redo;
+                       }
+
                        ov511->frame[frame].grabstate = FRAME_UNUSED;
 
                        /* Reset the hardware snapshot button */
@@ -2672,7 +2741,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr,
 
        PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
 
-       if (size > (((2 * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+       if (size > (((OV511_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
                return -EINVAL;
 
        pos = (unsigned long)ov511->fbuf;
@@ -3072,7 +3141,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
 
        init_waitqueue_head(&ov511->wq);
 
-       if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) {
+       if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) < 0) {
                err("video_register_device failed");
                return -EBUSY;
        }
@@ -3159,8 +3228,9 @@ error:
  *
  ***************************************************************************/
 
-static void* ov511_probe(struct usb_device *dev, unsigned int ifnum,
-                        const struct usb_device_id *id)
+static void * __devinit
+ov511_probe(struct usb_device *dev, unsigned int ifnum,
+       const struct usb_device_id *id)
 {
        struct usb_interface_descriptor *interface;
        struct usb_ov511 *ov511;
@@ -3174,9 +3244,9 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum,
 
        interface = &dev->actconfig->interface[ifnum].altsetting[0];
 
-       /* Checking vendor/product should be enough, but what the hell.
-          USB ID matching cannot check for a bInterfaceSubclass value
-          of 0, so we check it here. */
+       /* Checking vendor/product should be enough, but what the hell */
+       if (interface->bInterfaceClass != 0xFF)
+               return NULL;
        if (interface->bInterfaceSubClass != 0x00)
                return NULL;
 
@@ -3203,9 +3273,14 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum,
                ov511->bridge = BRG_OV511PLUS;
                break;
        case 0x0002:
+               if (dev->descriptor.idVendor != 0x0813)
+                       goto error;
                info("Intel Play Me2Cam (OV511+) found");
                ov511->bridge = BRG_OV511PLUS;
                break;
+       default:
+               err("Unknown product ID");
+               goto error;
        }
 
        ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
@@ -3265,7 +3340,8 @@ error:
 }
 
 
-static void ov511_disconnect(struct usb_device *dev, void *ptr)
+static void __devexit 
+ov511_disconnect(struct usb_device *dev, void *ptr)
 {
        struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr;
        int n;
@@ -3324,9 +3400,9 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
 
 static struct usb_driver ov511_driver = {
        name:           "ov511",
+       id_table:       device_table,
        probe:          ov511_probe,
-       disconnect:     ov511_disconnect,
-       id_table:       ov511_table,
+       disconnect:     ov511_disconnect
 };
 
 
index e78d5ede95883330ba0ab73a76206e207b8efae4..3e6ddee49af738037e318c9c7b9e036411a0b77b 100644 (file)
 #include <linux/etherdevice.h>
 #include <linux/usb.h>
 #include <linux/module.h>
-
-
-static const char *version = __FILE__ ": v0.4.13 2000/10/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
+#include "pegasus.h"
 
 
 #define        PEGASUS_USE_INTR
+#define        PEGASUS_WRITE_EEPROM
 
-
-#define        PEGASUS_II              0x80000000
-#define        HAS_HOME_PNA            0x40000000
-
-#define        PEGASUS_MTU             1500
-#define        PEGASUS_MAX_MTU         1536
-
-#define        EPROM_WRITE             0x01
-#define        EPROM_READ              0x02
-#define        EPROM_DONE              0x04
-#define        EPROM_WR_ENABLE         0x10
-#define        EPROM_LOAD              0x20
-
-#define        MII_BMCR                0x00
-#define        MII_BMSR                0x01
-#define        BMSR_MEDIA              0x7808
-#define        MII_ANLPA               0x05
-#define        ANLPA_100TX_FD          0x0100
-#define        ANLPA_100TX_HD          0x0080
-#define        ANLPA_10T_FD            0x0040
-#define        ANLPA_10T_HD            0x0020
-#define        PHY_DONE                0x80
-#define        PHY_READ                0x40
-#define        PHY_WRITE               0x20
-#define        DEFAULT_GPIO_RESET      0x24
-#define        LINKSYS_GPIO_RESET      0x24
-#define        DEFAULT_GPIO_SET        0x26
-
-#define        PEGASUS_PRESENT         0x00000001
-#define        PEGASUS_RUNNING         0x00000002
-#define        PEGASUS_TX_BUSY         0x00000004
-#define        PEGASUS_RX_BUSY         0x00000008
-#define        CTRL_URB_RUNNING        0x00000010
-#define        CTRL_URB_SLEEP          0x00000020
-#define        PEGASUS_UNPLUG          0x00000040
-#define        ETH_REGS_CHANGE         0x40000000
-#define        ETH_REGS_CHANGED        0x80000000
-
-#define        RX_MULTICAST            2
-#define        RX_PROMISCUOUS          4
-
-#define        REG_TIMEOUT             (HZ)
-#define        PEGASUS_TX_TIMEOUT      (HZ*10)
-
-#define        TX_UNDERRUN             0x80
-#define        EXCESSIVE_COL           0x40
-#define        LATE_COL                0x20
-#define        NO_CARRIER              0x10
-#define        LOSS_CARRIER            0x08
-#define        JABBER_TIMEOUT          0x04
-
-#define        PEGASUS_REQT_READ       0xc0
-#define        PEGASUS_REQT_WRITE      0x40
-#define        PEGASUS_REQ_GET_REGS    0xf0
-#define        PEGASUS_REQ_SET_REGS    0xf1
-#define        PEGASUS_REQ_SET_REG     PEGASUS_REQ_SET_REGS
-#define        ALIGN(x)                x __attribute__((aligned(L1_CACHE_BYTES)))
-
-enum pegasus_registers {
-       EthCtrl0 = 0,
-       EthCtrl1 = 1,
-       EthCtrl2 = 2,
-       EthID = 0x10,
-       Reg1d = 0x1d,
-       EpromOffset = 0x20,
-       EpromData = 0x21,       /* 0x21 low, 0x22 high byte */
-       EpromCtrl = 0x23,
-       PhyAddr = 0x25,
-       PhyData = 0x26,         /* 0x26 low, 0x27 high byte */
-       PhyCtrl = 0x28,
-       UsbStst = 0x2a,
-       EthTxStat0 = 0x2b,
-       EthTxStat1 = 0x2c,
-       EthRxStat = 0x2d,
-       Reg7b = 0x7b,
-       Gpio0 = 0x7e,
-       Gpio1 = 0x7f,
-       Reg81 = 0x81,
-};
-
-
-typedef struct pegasus {
-       struct usb_device       *usb;
-       struct net_device       *net;
-       struct net_device_stats stats;
-       unsigned                flags;
-       unsigned                features;
-       int                     intr_interval;
-       struct urb              ctrl_urb, rx_urb, tx_urb, intr_urb;
-       devrequest              dr;
-       wait_queue_head_t       ctrl_wait;
-       struct semaphore        ctrl_sem;
-       unsigned char           ALIGN(rx_buff[PEGASUS_MAX_MTU]);
-       unsigned char           ALIGN(tx_buff[PEGASUS_MAX_MTU]);
-       unsigned char           ALIGN(intr_buff[8]);
-       __u8                    eth_regs[4];
-       __u8                    phy;
-       __u8                    gpio_res;
-} pegasus_t;
-
-struct usb_eth_dev {
-       char    *name;
-       __u32   private; /* LSB is gpio reset value */
-};
+static const char *version = __FILE__ ": v0.4.17 2000/11/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
 
 
 static int loopback = 0;
 static int mii_mode = 0;
 static int multicast_filter_limit = 32;
 
+static struct usb_eth_dev usb_dev_id[] = {
+#define        PEGASUS_DEV(pn, vid, pid, flags)        \
+       {name:pn, vendor:vid, device:pid, private:flags},
+#include "pegasus.h"
+#undef PEGASUS_DEV
+       {NULL, 0, 0, 0}
+};
+
+static struct usb_device_id pegasus_ids[] = {
+#define        PEGASUS_DEV(pn, vid, pid, flags) {idVendor:vid, idProduct:pid},
+#include "pegasus.h"
+#undef PEGASUS_DEV
+       { }
+};
+
 
 MODULE_AUTHOR("Petko Manolov <petkan@dce.bg>");
 MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
 MODULE_PARM(loopback, "i");
 MODULE_PARM(mii_mode, "i");
 MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
-MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0) - default = MII mode = 0");
-
-
-#define PEGASUS_DEV(product_name, vendor_id, product_id, flags) \
-       {name: product_name, private: flags},
-
-static struct usb_eth_dev usb_dev_id[] = {
-
-#      define PEGASUS_DEV(product_name, vendor_id, product_id, flags) \
-               {name: product_name, private: flags},
-#      include "pegasus_devs.h"
-#      undef PEGASUS_DEV
-
-       {NULL, 0 }
-};
-
-
-/* The entries in this table MUST CORRESPOND LINE-BY-LINE to the
-   entries of usb_dev_id[]. */
-static struct usb_device_id pegasus_ids [] = {
-#      define PEGASUS_DEV(product_name, vendor_id, product_id, flags) \
-               {idVendor: vendor_id, idProduct: product_id },
-#      include "pegasus_devs.h"
-#      undef PEGASUS_DEV
-
-    { }                                                /* Terminating entry */
-};
+MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
 
 MODULE_DEVICE_TABLE (usb, pegasus_ids);
 
+
 static int update_eth_regs_async( pegasus_t * );
 /* Aargh!!! I _really_ hate such tweaks */
 static void ctrl_callback( urb_t *urb )
@@ -238,7 +124,7 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
        int     ret;
 
-       if ( pegasus->flags & ETH_REGS_CHANGED ) {
+       while ( pegasus->flags & ETH_REGS_CHANGED ) {
                pegasus->flags |= CTRL_URB_SLEEP;
                interruptible_sleep_on( &pegasus->ctrl_wait );
        }
@@ -269,7 +155,7 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
        int     ret;
 
-       if ( pegasus->flags & ETH_REGS_CHANGED ) {
+       while ( pegasus->flags & ETH_REGS_CHANGED ) {
                pegasus->flags |= CTRL_URB_SLEEP ;
                interruptible_sleep_on( &pegasus->ctrl_wait );
        }
@@ -300,7 +186,7 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
 {
        int     ret;
 
-       if ( pegasus->flags & ETH_REGS_CHANGED ) {
+       while ( pegasus->flags & ETH_REGS_CHANGED ) {
                pegasus->flags |= CTRL_URB_SLEEP;
                interruptible_sleep_on( &pegasus->ctrl_wait );
        }
@@ -349,7 +235,7 @@ static int update_eth_regs_async( pegasus_t *pegasus )
 }
 
 
-static int read_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
+static int read_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
 {
        int     i;
        __u8    data[4] = { phy, 0, 0, indx };
@@ -372,7 +258,7 @@ static int read_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
 }
 
 
-static int write_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
+static int write_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
 {
        int     i;
        __u8    data[4] = { phy, 0, 0, indx };
@@ -500,6 +386,15 @@ static inline int reset_mac( pegasus_t *pegasus )
        }
        if ( i == REG_TIMEOUT )
                return 1;
+
+       if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
+            usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK1 ) {
+               __u16   auxmode;
+
+               read_mii_word( pegasus, 0, 0x1b, &auxmode );
+               write_mii_word( pegasus, 0, 0x1b, auxmode | 4 );
+       }
+
        return  0;
 }
 
@@ -511,13 +406,13 @@ static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
        pegasus_t *pegasus = dev->priv;
 
 
-       if ( read_phy_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) 
-               return 2;
+       if ( read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) 
+               return 1;
        if ( !(bmsr & 0x20) && !loopback ) 
                warn( "%s: link NOT established (0x%x) - check the cable.",
                        dev->name, bmsr );
-       if ( read_phy_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
-               return 4;
+       if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
+               return 2;
        if ( !(linkpart & 1) )
                warn( "link partner stat %x", linkpart );
 
@@ -557,23 +452,29 @@ static void read_bulk_callback( struct urb *urb )
 
        if ( pegasus->flags & PEGASUS_RX_BUSY ) {
                pegasus->stats.rx_errors++;
+               dbg("pegasus Rx busy");
                return;
        }
        pegasus->flags |= PEGASUS_RX_BUSY;
 
-       rx_status = *(int *)(pegasus->rx_buff + count - 4);
-
-       if (urb->status) {
-               dbg("%s: RX status %d", net->name, urb->status);
-               goto goon;
+       switch ( urb->status ) {
+               case USB_ST_NOERROR:
+                       break;
+               case USB_ST_NORESPONSE:
+                       dbg( "reset MAC" );
+                       pegasus->flags &= ~PEGASUS_RX_BUSY;
+                       break;
+               default:
+                       dbg( "%s: RX status %d", net->name, urb->status );
+                       goto goon;
        }
 
        if ( !count )
                goto goon;
 
+       rx_status = *(int *)(pegasus->rx_buff + count - 4);
        if ( rx_status & 0x000e0000 ) {
-
-               dbg("%s: error receiving packet %x", net->name, rx_status & 0xe0000);
+               dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
                pegasus->stats.rx_errors++;
                if ( rx_status & 0x060000 )
                        pegasus->stats.rx_length_errors++;
@@ -581,7 +482,6 @@ static void read_bulk_callback( struct urb *urb )
                        pegasus->stats.rx_crc_errors++;
                if ( rx_status & 0x100000 )
                        pegasus->stats.rx_frame_errors++;
-
                goto goon;
        }
 
@@ -637,6 +537,16 @@ static void intr_callback( struct urb *urb )
 
        if ( !pegasus )
                return;
+               
+       switch ( urb->status ) {
+               case USB_ST_NOERROR:
+                       break;
+               case USB_ST_URB_KILLED:
+                       return;
+               default:
+                       info("intr status %d", urb->status);
+       }
+
        d = urb->transfer_buffer;
        net = pegasus->net;
        if ( d[0] & 0xfc ) {
@@ -650,17 +560,10 @@ static void intr_callback( struct urb *urb )
                if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
                        pegasus->stats.tx_carrier_errors++;
        }
-       switch ( urb->status ) {
-               case USB_ST_NOERROR:
-                       break;
-               case USB_ST_URB_KILLED:
-                       break;
-               default:
-                       info("intr status %d", urb->status);
-       }
 }
 #endif
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)
 static void pegasus_tx_timeout( struct net_device *net )
 {
        pegasus_t *pegasus = net->priv;
@@ -673,6 +576,7 @@ static void pegasus_tx_timeout( struct net_device *net )
        usb_unlink_urb( &pegasus->tx_urb );
        pegasus->stats.tx_errors++;
 }
+#endif
 
 
 static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
@@ -725,6 +629,14 @@ static inline void get_interrupt_interval( pegasus_t *pegasus )
        __u8    data[2];
 
        read_eprom_word( pegasus, 4, (__u16 *)data );
+       if ( data[1] < 0x80 ) {
+               info( "intr interval will be changed from %ums to %ums",
+                    data[1], 0x80 );
+               data[1] = 0x80;
+#ifdef PEGASUS_WRITE_EEPROM
+               write_eprom_word( pegasus, 4, *(__u16 *)data );
+#endif
+       }
        pegasus->intr_interval = data[1];
 }
 
@@ -747,7 +659,6 @@ static int pegasus_open(struct net_device *net)
        if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
                warn( __FUNCTION__ " failed rx_urb %d", res );
 #ifdef PEGASUS_USE_INTR
-       get_interrupt_interval( pegasus );
        FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
                        usb_rcvintpipe(pegasus->usb, 3),
                        pegasus->intr_buff, sizeof(pegasus->intr_buff),
@@ -792,12 +703,12 @@ static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
                case SIOCDEVPRIVATE:
                        data[0] = pegasus->phy;
                case SIOCDEVPRIVATE+1:
-                       read_phy_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+                       read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
                        return 0;
                case SIOCDEVPRIVATE+2:
                        if ( !capable(CAP_NET_ADMIN) )
                                return -EPERM;
-                       write_phy_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+                       write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
                        return 0;
                default:
                        return -EOPNOTSUPP;
@@ -838,14 +749,14 @@ static __u8 mii_phy_probe( pegasus_t *pegasus )
        __u16   tmp;
 
        for ( i=0; i < 32; i++ ) {
-               read_phy_word( pegasus, i, MII_BMSR, &tmp );
+               read_mii_word( pegasus, i, MII_BMSR, &tmp );
                if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 )
                        continue;
                else
                        return  i;
        }
 
-       return  0;
+       return  0xff;
 }
 
 
@@ -863,9 +774,9 @@ static inline void setup_pegasus_II( pegasus_t *pegasus )
 static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
                             const struct usb_device_id *id)
 {
-       struct net_device *net;
-       pegasus_t *pegasus;
-       const int dev_indx = id - pegasus_ids;
+       struct net_device       *net;
+       pegasus_t               *pegasus;
+       int                     dev_index = id - pegasus_ids;
 
        if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
                err("usb_set_configuration() failed");
@@ -879,7 +790,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
 
        usb_inc_dev_use( dev );
        memset(pegasus, 0, sizeof(struct pegasus));
-       init_MUTEX( &pegasus-> ctrl_sem );
+       pegasus->dev_index = dev_index;
        init_waitqueue_head( &pegasus->ctrl_wait );
 
        net = init_etherdev( NULL, 0 );
@@ -903,7 +814,10 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
        net->get_stats = pegasus_netdev_stats;
        net->mtu = PEGASUS_MTU;
 
-       pegasus->features = usb_dev_id[dev_indx].private;
+       pegasus->features = usb_dev_id[dev_index].private;
+#ifdef PEGASUS_USE_INTR
+       get_interrupt_interval( pegasus );
+#endif
        if ( reset_mac(pegasus) ) {
                err("can't reset MAC");
                unregister_netdev( pegasus->net );
@@ -912,7 +826,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
                return NULL;
        }
 
-       info( "%s: %s", net->name, usb_dev_id[dev_indx].name );
+       info( "%s: %s", net->name, usb_dev_id[dev_index].name );
 
        set_ethernet_addr( pegasus );
 
@@ -922,7 +836,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
        }
        
        pegasus->phy = mii_phy_probe( pegasus );
-       if ( !pegasus->phy ) {
+       if ( pegasus->phy == 0xff ) {
                warn( "can't locate MII phy, using default" );
                pegasus->phy = 1;
        }
diff --git a/drivers/usb/pegasus.h b/drivers/usb/pegasus.h
new file mode 100644 (file)
index 0000000..740aaf3
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ *  Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef        PEGASUS_DEV
+
+#define        PEGASUS_II              0x80000000
+#define        HAS_HOME_PNA            0x40000000
+
+#define        PEGASUS_MTU             1500
+#define        PEGASUS_MAX_MTU         1536
+
+#define        EPROM_WRITE             0x01
+#define        EPROM_READ              0x02
+#define        EPROM_DONE              0x04
+#define        EPROM_WR_ENABLE         0x10
+#define        EPROM_LOAD              0x20
+
+#define        MII_BMCR                0x00
+#define        MII_BMSR                0x01
+#define        BMSR_MEDIA              0x7808
+#define        MII_ANLPA               0x05
+#define        ANLPA_100TX_FD          0x0100
+#define        ANLPA_100TX_HD          0x0080
+#define        ANLPA_10T_FD            0x0040
+#define        ANLPA_10T_HD            0x0020
+#define        PHY_DONE                0x80
+#define        PHY_READ                0x40
+#define        PHY_WRITE               0x20
+#define        DEFAULT_GPIO_RESET      0x24
+#define        LINKSYS_GPIO_RESET      0x24
+#define        DEFAULT_GPIO_SET        0x26
+
+#define        PEGASUS_PRESENT         0x00000001
+#define        PEGASUS_RUNNING         0x00000002
+#define        PEGASUS_TX_BUSY         0x00000004
+#define        PEGASUS_RX_BUSY         0x00000008
+#define        CTRL_URB_RUNNING        0x00000010
+#define        CTRL_URB_SLEEP          0x00000020
+#define        PEGASUS_UNPLUG          0x00000040
+#define        ETH_REGS_CHANGE         0x40000000
+#define        ETH_REGS_CHANGED        0x80000000
+
+#define        RX_MULTICAST            2
+#define        RX_PROMISCUOUS          4
+
+#define        REG_TIMEOUT             (HZ)
+#define        PEGASUS_TX_TIMEOUT      (HZ*10)
+
+#define        TX_UNDERRUN             0x80
+#define        EXCESSIVE_COL           0x40
+#define        LATE_COL                0x20
+#define        NO_CARRIER              0x10
+#define        LOSS_CARRIER            0x08
+#define        JABBER_TIMEOUT          0x04
+
+#define        PEGASUS_REQT_READ       0xc0
+#define        PEGASUS_REQT_WRITE      0x40
+#define        PEGASUS_REQ_GET_REGS    0xf0
+#define        PEGASUS_REQ_SET_REGS    0xf1
+#define        PEGASUS_REQ_SET_REG     PEGASUS_REQ_SET_REGS
+#define        ALIGN(x)                x __attribute__((aligned(L1_CACHE_BYTES)))
+
+enum pegasus_registers {
+       EthCtrl0 = 0,
+       EthCtrl1 = 1,
+       EthCtrl2 = 2,
+       EthID = 0x10,
+       Reg1d = 0x1d,
+       EpromOffset = 0x20,
+       EpromData = 0x21,       /* 0x21 low, 0x22 high byte */
+       EpromCtrl = 0x23,
+       PhyAddr = 0x25,
+       PhyData = 0x26,         /* 0x26 low, 0x27 high byte */
+       PhyCtrl = 0x28,
+       UsbStst = 0x2a,
+       EthTxStat0 = 0x2b,
+       EthTxStat1 = 0x2c,
+       EthRxStat = 0x2d,
+       Reg7b = 0x7b,
+       Gpio0 = 0x7e,
+       Gpio1 = 0x7f,
+       Reg81 = 0x81,
+};
+
+
+typedef struct pegasus {
+       struct usb_device       *usb;
+       struct net_device       *net;
+       struct net_device_stats stats;
+       unsigned                flags;
+       unsigned                features;
+       int                     dev_index;
+       int                     intr_interval;
+       struct urb              ctrl_urb, rx_urb, tx_urb, intr_urb;
+       devrequest              dr;
+       wait_queue_head_t       ctrl_wait;
+       struct semaphore        ctrl_sem;
+       unsigned char           ALIGN(rx_buff[PEGASUS_MAX_MTU]);
+       unsigned char           ALIGN(tx_buff[PEGASUS_MAX_MTU]);
+       unsigned char           ALIGN(intr_buff[8]);
+       __u8                    eth_regs[4];
+       __u8                    phy;
+       __u8                    gpio_res;
+} pegasus_t;
+
+
+struct usb_eth_dev {
+       char    *name;
+       __u16   vendor;
+       __u16   device;
+       __u32   private; /* LSB is gpio reset value */
+};
+
+
+#define VENDOR_ACCTON           0x083a
+#define VENDOR_ADMTEK           0x07a6
+#define VENDOR_BILLIONTON       0x08dd
+#define VENDOR_COREGA           0x07aa
+#define VENDOR_DLINK1           0x2001
+#define VENDOR_DLINK2           0x07b8
+#define VENDOR_IODATA           0x04bb
+#define VENDOR_LANEED           0x056e
+#define VENDOR_LINKSYS          0x066b
+#define VENDOR_MELCO            0x0411
+#define VENDOR_SMC              0x0707
+#define VENDOR_SOHOWARE         0x15e8
+
+
+#else  /* PEGASUS_DEV */
+
+
+PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
+               VENDOR_ADMTEK, 0x8511,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)",
+               VENDOR_ADMTEK, 0x0986,
+               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
+               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4001,
+               LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4002,
+               LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK1, 0x4003,
+               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK1, 0xabc1,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "D-Link DU-E10", VENDOR_DLINK2, 0xabc1,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "D-Link DU-E100", VENDOR_DLINK2, 0x4002,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
+               LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
+               LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
+               LINKSYS_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "Linksys USB Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
+               LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
+               DEFAULT_GPIO_RESET )
+
+
+#endif /* PEGASUS_DEV */
diff --git a/drivers/usb/pegasus_devs.h b/drivers/usb/pegasus_devs.h
deleted file mode 100644 (file)
index 8b6e77d..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* This file is derived from pegasus.c.
- *  Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* This file should be included after defining the macro PEGASUS_DEV. */
-
-PEGASUS_DEV( "Billionton USB-100", 0x08dd, 0x0986,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "Billionton USBLP-100", 0x08dd, 0x0987,
-               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-
-PEGASUS_DEV( "Billionton USBEL-100", 0x08dd, 0x0988,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "Billionton USBE-100", 0x08dd, 0x8511,
-               DEFAULT_GPIO_RESET | PEGASUS_II )
-
-PEGASUS_DEV( "Corega FEter USB-TX", 0x7aa, 0x0004,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", 0x0411, 0x0001,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "D-Link DSB-650TX", 0x2001, 0x4001,
-               LINKSYS_GPIO_RESET )
-
-PEGASUS_DEV( "D-Link DSB-650TX", 0x2001, 0x4002,
-               LINKSYS_GPIO_RESET )
-
-PEGASUS_DEV( "D-Link DSB-650TX(PNA)", 0x2001, 0x4003,
-               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-
-PEGASUS_DEV( "D-Link DSB-650", 0x2001, 0xabc1,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "D-Link DU-E10", 0x07b8, 0xabc1,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "D-Link DU-E100", 0x07b8, 0x4002,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "Linksys USB10TX", 0x066b, 0x2202,
-               LINKSYS_GPIO_RESET )
-
-PEGASUS_DEV( "Linksys USB100TX", 0x066b, 0x2203,
-               LINKSYS_GPIO_RESET )
-
-PEGASUS_DEV( "Linksys USB100TX", 0x066b, 0x2204,
-               LINKSYS_GPIO_RESET | HAS_HOME_PNA )
-
-PEGASUS_DEV( "Linksys USB Ethernet Adapter", 0x066b, 0x2206,
-               LINKSYS_GPIO_RESET )
-
-PEGASUS_DEV( "SMC 202 USB Ethernet", 0x0707, 0x0200,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986,
-               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-
-PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "IO DATA USB ET/TX", 0x04bb, 0x0904,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "SOHOware NUB100 Ethernet", 0x15e8, 0x9100,
-               DEFAULT_GPIO_RESET )
-
-PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", 0x07a6, 0x8511,
-               DEFAULT_GPIO_RESET | PEGASUS_II )
index b7dfc3503c7a507129b3a6aacd10942247b6eddb..c77ba35e275cbc453233adcaf019fad6daa30f71 100644 (file)
@@ -498,7 +498,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
        }
 
 #ifdef DEBUG
-       usblp_check_status(usblp);
+       usblp_check_status(usblp, 0);
 #endif
 
        info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
index 1bab9d524d5763fd7fc73627f7db871ed8bf806a..8d38a7a9d817da7cfe2a2c569129d43db1990b24 100644 (file)
@@ -85,13 +85,35 @@ static void belkin_sa_set_termios   (struct usb_serial_port *port, struct termios
 static int  belkin_sa_ioctl            (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 static void belkin_sa_break_ctl                (struct usb_serial_port *port, int break_state );
 
+
+static __devinitdata struct usb_device_id id_table_combined [] = {
+       { idVendor: BELKIN_SA_VID,      idProduct: BELKIN_SA_PID },
+       { idVendor: BELKIN_OLD_VID,     idProduct: BELKIN_OLD_PID },
+       { idVendor: PERACOM_VID,        idProduct: PERACOM_PID },
+       { }                                                     /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id belkin_sa_table [] = {
+       { idVendor: BELKIN_SA_VID,      idProduct: BELKIN_SA_PID },
+       { }                                                     /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id belkin_old_table [] = {
+       { idVendor: BELKIN_OLD_VID,     idProduct: BELKIN_OLD_PID },
+       { }                                                     /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id peracom_table [] = {
+       { idVendor: PERACOM_VID,        idProduct: PERACOM_PID },
+       { }                                                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
 /* All of the device info needed for the Belkin serial converter */
-static __u16   belkin_sa_vendor_id     = BELKIN_SA_VID;
-static __u16   belkin_sa_product_id    = BELKIN_SA_PID;
 struct usb_serial_device_type belkin_sa_device = {
        name:                   "Belkin F5U103 USB Serial Adapter",
-       idVendor:               &belkin_sa_vendor_id,           /* the Belkin vendor ID */
-       idProduct:              &belkin_sa_product_id,          /* the Belkin F5U103 product id */
+       id_table:               belkin_sa_table,                /* the Belkin F5U103 device */
        needs_interrupt_in:     MUST_HAVE,                      /* this device must have an interrupt in endpoint */
        needs_bulk_in:          MUST_HAVE,                      /* this device must have a bulk in endpoint */
        needs_bulk_out:         MUST_HAVE,                      /* this device must have a bulk out endpoint */
@@ -111,12 +133,9 @@ struct usb_serial_device_type belkin_sa_device = {
 
 
 /* This driver also supports the "old" school Belkin single port adaptor */
-static __u16   belkin_old_vendor_id    = BELKIN_OLD_VID;
-static __u16   belkin_old_product_id   = BELKIN_OLD_PID;
 struct usb_serial_device_type belkin_old_device = {
        name:                   "Belkin USB Serial Adapter",
-       idVendor:               &belkin_old_vendor_id,          /* the Belkin vendor ID */
-       idProduct:              &belkin_old_product_id,         /* the Belkin product id */
+       id_table:               belkin_old_table,               /* the old Belkin device */
        needs_interrupt_in:     MUST_HAVE,                      /* this device must have an interrupt in endpoint */
        needs_bulk_in:          MUST_HAVE,                      /* this device must have a bulk in endpoint */
        needs_bulk_out:         MUST_HAVE,                      /* this device must have a bulk out endpoint */
@@ -135,12 +154,9 @@ struct usb_serial_device_type belkin_old_device = {
 };
 
 /* this driver also works for the Peracom single port adapter */
-static __u16   peracom_vendor_id       = PERACOM_VID;
-static __u16   peracom_product_id      = PERACOM_PID;
 struct usb_serial_device_type peracom_device = {
        name:                   "Peracom single port USB Serial Adapter",
-       idVendor:               &peracom_vendor_id,             /* the Peracom vendor ID */
-       idProduct:              &peracom_product_id,            /* the Peracom product id */
+       id_table:               peracom_table,                  /* the Peracom device */
        needs_interrupt_in:     MUST_HAVE,                      /* this device must have an interrupt in endpoint */
        needs_bulk_in:          MUST_HAVE,                      /* this device must have a bulk in endpoint */
        needs_bulk_out:         MUST_HAVE,                      /* this device must have a bulk out endpoint */
@@ -284,7 +300,6 @@ static void belkin_sa_read_int_callback (struct urb *urb)
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
        struct usb_serial *serial;
-       struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
 
        /* the urb might have been killed. */
@@ -360,7 +375,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios
        unsigned int cflag = port->tty->termios->c_cflag;
        unsigned int old_iflag = old_termios->c_iflag;
        unsigned int old_cflag = old_termios->c_cflag;
-       __u16 urb_value; /* Will hold the new flags */
+       __u16 urb_value = 0; /* Will hold the new flags */
        
        /* Set the baud rate */
        if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
index 8fdfd95bdf412043c54be0e34ac1a00560c419ee..57915b46a67110384b5a367e324e3f517348dc9e 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (11/13/2000) Bill Ryder
+ *     Added spinlock protected open code and close code.
+ *     Multiple opens work (sort of - see webpage).
+ *     Cleaned up comments. Removed multiple PID/VID definitions.
+ *     Factorised cts/dtr code
+ *     Made use of __FUNCTION__ in dbg's
+ *      
  * (11/01/2000) Adam J. Richter
  *     usb_device_id table support
  * 
 
 #include "ftdi_sio.h"
 
-#define FTDI_VENDOR_ID                 0x0403
-#define FTDI_SIO_SERIAL_CONVERTER_ID   0x8372
+#define FTDI_VENDOR_ID                 FTDI_VID
+#define FTDI_SIO_SERIAL_CONVERTER_ID   FTDI_SIO_PID
+#define FTDI_8U232AM_PID               0x6001
 
-static __devinitdata struct usb_device_id id_table [] = {
-    { idVendor: FTDI_VENDOR_ID, idProduct: FTDI_SIO_SERIAL_CONVERTER_ID },
+static __devinitdata struct usb_device_id id_table_sio [] = {
+    { idVendor: FTDI_VID, idProduct: FTDI_SIO_PID },
     { }                                                /* Terminating entry */
 };
 
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE (usb, id_table_sio);
 
 
 /* function prototypes for a FTDI serial converter */
@@ -95,7 +103,7 @@ static int  ftdi_sio_ioctl           (struct usb_serial_port *port, struct file * file, u
 /* All of the device info needed for the FTDI SIO serial converter */
 struct usb_serial_device_type ftdi_sio_device = {
        name:                   "FTDI SIO",
-       id_table:               id_table,
+       id_table:               id_table_sio,
        needs_interrupt_in:     MUST_HAVE_NOT,          /* this device must not have an interrupt in endpoint */
        needs_bulk_in:          MUST_HAVE,              /* this device must have a bulk in endpoint */
        needs_bulk_out:         MUST_HAVE,              /* this device must have a bulk out endpoint */
@@ -113,63 +121,55 @@ struct usb_serial_device_type ftdi_sio_device = {
        startup:                ftdi_sio_startup,
 };
 
-
 /*
  * ***************************************************************************
  * FTDI SIO Serial Converter specific driver functions
  * ***************************************************************************
  *
- * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code
- * Thanx to FTDI for so kindly providing details of the protocol required
- *   to talk to the device - http://www.ftdi.co.uk
- *
- * Tested as at this version - other stuff might work
- * 23 March 2000
- *     Works:
- *      Baudrates - 9600, 38400,19200, 57600, 115200  
- *      TIOCMBIC - TIOCM_DTR / TIOCM_RTS 
- *      TIOCMBIS - TIOCM_DTR / TIOCM_RTS 
- *      TIOCMSET - DTR on/RTSon  / DTR off, RTS off 
- *      no parity:CS8 even parity:CS7 odd parity:CS7 
- *      CRTSCTS flow control 
- *     
- *      Pilot-xfer zillions of times
- *  
- *      cu works with dir option 
- *
- *   Not Tested (ie might not work): 
- *      xon/xoff flow control 
- *      ppp (modem handling in general) 
- *
- *   KNOWN BUGS:
- *    Multiple Opens
- *    ==============
- *      Seems to have problem when opening an already open port, 
- *      Get I/O error on first attempt, then it lets you in. 
- *      Need to do proper usage counting - keep registered callbacks for first opener.
- *     
- *     Reproduce with: 
- *       cu -l /dev/ttyUSB0 dir 
- *       whilst cu is running do:
- *        stty -a < /dev/ttyUSB0  
- *
- *     from stty get: 'bash: /dev/ttyUSB0: Invalid argument ' 
- *     from cu get 
- *        write: Invalid argument 
- *    
- *    Initialisation Problem
- *    ======================
- *    Pilot transfer required me to run the serial_loopback program before it would work.
- *    Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio
+ *    See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date
+ *     testing information
+ * 
  *
  */
 
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
+/* utility functions to set and unset dtr and rts */
+#define HIGH 1
+#define LOW 0
+static int set_rts(struct usb_device *dev, 
+                  unsigned int pipe,
+                  int high_or_low)
+{
+       static char buf[1];
+       unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH : 
+                               FTDI_SIO_SET_RTS_LOW);
+       return(usb_control_msg(dev, pipe,
+                              FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+                              FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+                              ftdi_high_or_low, 0, 
+                              buf, 0, WDR_TIMEOUT));
+}
+static int set_dtr(struct usb_device *dev, 
+                  unsigned int pipe,
+                  int high_or_low)
+{
+       static char buf[1];
+       unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH : 
+                               FTDI_SIO_SET_DTR_LOW);
+       return(usb_control_msg(dev, pipe,
+                              FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+                              FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+                              ftdi_high_or_low, 0, 
+                              buf, 0, WDR_TIMEOUT));
+}
+
+
 /* do some startup allocations not currently performed by usb_serial_probe() */
 static int ftdi_sio_startup (struct usb_serial *serial)
 {
        init_waitqueue_head(&serial->port[0].write_wait);
+
        
        return (0);
 }
@@ -178,65 +178,55 @@ static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_sio_open */
        struct termios tmp_termios;
        struct usb_serial *serial = port->serial;
+       unsigned long flags;    /* Used for spinlock */
        int result;
        char buf[1]; /* Needed for the usb_control_msg I think */
 
-       dbg("ftdi_sio_open port %d", port->number);
+       dbg(__FUNCTION__ " port %d", port->number);
 
-        /* FIXME - multiple concurrent opens cause trouble */
-       if (port->active) {
-               err ("port already open");
-               return -EINVAL;
-       }
-       port->active = 1; /* FIXME - For multiple open this should increment */
+       spin_lock_irqsave (&port->port_lock, flags);
+       
+       MOD_INC_USE_COUNT;
+       ++port->open_count;
 
-       /* See ftdi_sio.h for description of what is reset */
-       usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                       FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-                       FTDI_SIO_RESET_SIO, 
-                       0, buf, 0, WDR_TIMEOUT);
+       if (!port->active){
+               port->active = 1;
+               spin_unlock_irqrestore (&port->port_lock, flags);
 
-       /* Setup termios */
-       port->tty->termios->c_cflag =
-               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+               /* See ftdi_sio.h for description of what is reset */
+               usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                               FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
+                               FTDI_SIO_RESET_SIO, 
+                               0, buf, 0, WDR_TIMEOUT);
 
-       
-       ftdi_sio_set_termios(port, &tmp_termios);       
+               /* Setup termios */
+               port->tty->termios->c_cflag =
+                       B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 
-       /* Disable flow control */
-       if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                           FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
-                           FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                           0, 0, 
-                           buf, 0, WDR_TIMEOUT) < 0) {
-               err("error from flowcontrol urb");
-               return(-EINVAL);
-       }           
-
-       /* Turn on RTS and DTR since we are not flow controlling*/
-       if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                           FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                           FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                           (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, 
-                           buf, 0, WDR_TIMEOUT) < 0) {
-               err("Error from DTR HIGH urb");
-       }
-       if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                           FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                           FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                           (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, 
-                           buf, 0, WDR_TIMEOUT) < 0) {
-               err("Error from RTS HIGH urb");
-       }
+               /* ftdi_sio_set_termios  will send usb control messages */
+               /* ftdi_sio_set_termios will set up port according to above list */
+               
+               ftdi_sio_set_termios(port, &tmp_termios);       
+
+               /* Turn on RTS and DTR since we are not flow controlling*/
+               if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+                       err("Error from DTR HIGH urb");
+               }
+               if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+                       err("Error from RTS HIGH urb");
+               }
        
-       /* Start reading from the device */
-       FILL_BULK_URB(port->read_urb, serial->dev, 
-                     usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-                     port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-                     ftdi_sio_read_bulk_callback, port);
-       result = usb_submit_urb(port->read_urb);
-       if (result)
-               err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+               /* Start reading from the device */
+               FILL_BULK_URB(port->read_urb, serial->dev, 
+                             usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+                             port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+                             ftdi_sio_read_bulk_callback, port);
+               result = usb_submit_urb(port->read_urb);
+               if (result)
+                       err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+       } else { /* the port was already active - so no initialisation was done */
+               spin_unlock_irqrestore (&port->port_lock, flags);
+       }
 
        return (0);
 } /* ftdi_sio_open */
@@ -247,41 +237,48 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
        struct usb_serial *serial = port->serial;
        unsigned int c_cflag = port->tty->termios->c_cflag;
        char buf[1];
+       unsigned long flags;
+
+       dbg( __FUNCTION__ " port %d", port->number);
+
+       spin_lock_irqsave (&port->port_lock, flags);
+       --port->open_count;
+
+       if (port->open_count <= 0) {
+               spin_unlock_irqrestore (&port->port_lock, flags);
+               if (c_cflag & HUPCL){
+                       /* Disable flow control */
+                       if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+                                           0, 0, 
+                                           buf, 0, WDR_TIMEOUT) < 0) {
+                               err("error from flowcontrol urb");
+                       }           
+
+                       /* drop DTR */
+                       if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+                               err("Error from DTR LOW urb");
+                       }
+                       /* drop RTS */
+                       if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+                               err("Error from RTS LOW urb");
+                       }       
+               } /* Note change no line is hupcl is off */
+
+               /* shutdown our bulk reads and writes */
+               usb_unlink_urb (port->write_urb);
+               usb_unlink_urb (port->read_urb);
+               port->active = 0;
+               port->open_count = 0;
+       } else { 
+               spin_unlock_irqrestore (&port->port_lock, flags);
+       }
+
+       MOD_DEC_USE_COUNT;
 
-       dbg("ftdi_sio_close port %d", port->number);
-       
-       if (c_cflag & HUPCL){
-               /* Disable flow control */
-               if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                   0, 0, 
-                                   buf, 0, WDR_TIMEOUT) < 0) {
-                       err("error from flowcontrol urb");
-               }           
 
-               /* drop DTR */
-               if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                   (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
-                                   buf, 0, WDR_TIMEOUT) < 0) {
-                       err("Error from DTR LOW urb");
-               }
-               /* drop RTS */
-               if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                   (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
-                                   buf, 0, WDR_TIMEOUT) < 0) {
-                       err("Error from RTS LOW urb");
-               }       
-       }
 
-       /* shutdown our bulk reads and writes */
-       usb_unlink_urb (port->write_urb);
-       usb_unlink_urb (port->read_urb);
-       port->active = 0;
 } /* ftdi_sio_close */
 
 
@@ -300,7 +297,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
        int result;
        DECLARE_WAITQUEUE(wait, current);
        
-       dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
+       dbg(__FUNCTION__ " port %d, %d bytes", port->number, count);
 
        if (count == 0) {
                err("write request of 0 bytes");
@@ -317,7 +314,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
                add_wait_queue(&port->write_wait, &wait);
                set_current_state (TASK_INTERRUPTIBLE);
                while (port->write_urb->status == -EINPROGRESS) {
-                       dbg("ftdi_sio - write in progress - retrying");
+                       dbg(__FUNCTION__ " write in progress - retrying");
                        if (0 /* file->f_flags & O_NONBLOCK */) {
                                rc = -EAGAIN;
                                goto err;
@@ -353,7 +350,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
                first_byte = port->write_urb->transfer_buffer;
                *first_byte = 1 | ((count-data_offset) << 2) ; 
 
-               dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+               dbg(__FUNCTION__ "Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
                usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
                
                /* send the data out the bulk port */
@@ -368,7 +365,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
                        return 0;
                }
 
-               dbg("write returning: %d", count - data_offset);
+               dbg(__FUNCTION__ " write returning: %d", count - data_offset);
                return (count - data_offset);
        }
        
@@ -420,7 +417,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
        int i;
        int result;
 
-       dbg("ftdi_sio read callback");
+       dbg(__FUNCTION__);
 
        if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
                return;
@@ -430,10 +427,6 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
        if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
                return;
        }
-       
-       /* TO DO -- check for hung up line and handle appropriately: */
-       /*   send hangup (need to find out how to do this) */
 
        if (urb->status) {
                /* This will happen at close every time so it is a dbg not an err */
@@ -447,6 +440,12 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
                 dbg("Just status");
         }
 
+       /* TO DO -- check for hung up line and handle appropriately: */
+       /*   send hangup (need to find out how to do this) */
+       /* See acm.c - you do a tty_hangup  - eg tty_hangup(tty) */
+       /* if CD is dropped and the line is not CLOCAL then we should hangup */
+
+
        if (urb->actual_length > data_offset) {
                for (i = data_offset ; i < urb->actual_length ; ++i) {
                        tty_insert_flip_char(tty, data[i], 0);
@@ -476,10 +475,10 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
 { /* ftdi_sio_set_termios */
        struct usb_serial *serial = port->serial;
        unsigned int cflag = port->tty->termios->c_cflag;
-       __u16 urb_value; /* Will hold the new flags */
+       __u16 urb_value; /* will hold the new flags */
        char buf[1]; /* Perhaps I should dynamically alloc this? */
        
-       dbg("ftdi_sio_set_termios port %d", port->number);
+       dbg(__FUNCTION__ " port %d", port->number);
 
 
        /* FIXME -For this cut I don't care if the line is really changing or 
@@ -530,7 +529,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
        case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
        case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
        case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
-       default: dbg("FTDI_SIO does not support the baudrate requested"); 
+       default: dbg(__FUNCTION__ "FTDI_SIO does not support the baudrate requested"); 
                /* FIXME - how to return an error for this? */ break;
        }
        if ((cflag & CBAUD) == B0 ) {
@@ -543,18 +542,10 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
                        err("error from disable flowcontrol urb");
                }           
                /* Drop RTS and DTR */
-               if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                   (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
-                                   buf, 0, WDR_TIMEOUT) < 0) {
+               if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
                        err("Error from DTR LOW urb");
                }
-               if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                   FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                   (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
-                                   buf, 0, WDR_TIMEOUT) < 0) {
+               if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
                        err("Error from RTS LOW urb");
                }       
                
@@ -571,7 +562,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
        /* Set flow control */
        /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
        if (cflag & CRTSCTS) {
-               dbg("Setting to CRTSCTS flow control");
+               dbg(__FUNCTION__ "Setting to CRTSCTS flow control");
                if (usb_control_msg(serial->dev, 
                                    usb_sndctrlpipe(serial->dev, 0),
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -584,7 +575,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
        } else { 
                /* CHECK Assuming XON/XOFF handled by stack - not by device */
                /* Disable flow control */
-               dbg("Turning off hardware flow control");
+               dbg(__FUNCTION__ "Turning off hardware flow control");
                if (usb_control_msg(serial->dev, 
                                    usb_sndctrlpipe(serial->dev, 0),
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -605,13 +596,13 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
        char buf[1];
        int  ret, mask;
        
-       dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd);
+       dbg(__FUNCTION__ " cmd 0x%04x", cmd);
 
        /* Based on code from acm.c and others */
        switch (cmd) {
 
        case TIOCMGET:
-               dbg("TIOCMGET");
+               dbg(__FUNCTION__ "TIOCMGET");
                /* Request the status from the device */
                if ((ret = usb_control_msg(serial->dev, 
                                           usb_rcvctrlpipe(serial->dev, 0),
@@ -619,7 +610,7 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
                                           FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
                                           0, 0, 
                                           buf, 1, HZ * 5)) < 0 ) {
-                       dbg("Get not get modem status of device");
+                       dbg(__FUNCTION__ "Get not get modem status of device");
                        return(ret);
                }
 
@@ -631,7 +622,7 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
                break;
 
        case TIOCMSET: /* Turns on and off the lines as specified by the mask */
-               dbg("TIOCMSET");
+               dbg(__FUNCTION__ "TIOCMSET");
                if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
                urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW);
                if ((ret = usb_control_msg(serial->dev, 
@@ -656,26 +647,20 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
                break;
                                        
        case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
-               dbg("TIOCMBIS");
+               dbg(__FUNCTION__ "TIOCMBIS");
                if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
                if (mask & TIOCM_DTR){
-                       if ((ret = usb_control_msg(serial->dev, 
-                                           usb_sndctrlpipe(serial->dev, 0),
-                                           FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                           FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                           FTDI_SIO_SET_DTR_HIGH , 0,
-                                           buf, 0, WDR_TIMEOUT)) < 0){
+                       if ((ret = set_dtr(serial->dev, 
+                                          usb_sndctrlpipe(serial->dev, 0),
+                                          HIGH)) < 0) {
                                err("Urb to set DTR failed");
                                return(ret);
-                               }
                        }
-                       if (mask & TIOCM_RTS) {
-                       if ((ret = usb_control_msg(serial->dev, 
-                                           usb_sndctrlpipe(serial->dev, 0),
-                                           FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                           FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                           FTDI_SIO_SET_RTS_HIGH , 0,
-                                           buf, 0, WDR_TIMEOUT)) < 0){
+               }
+               if (mask & TIOCM_RTS) {
+                       if ((ret = set_rts(serial->dev, 
+                                          usb_sndctrlpipe(serial->dev, 0),
+                                          HIGH)) < 0){
                                err("Urb to set RTS failed");
                                return(ret);
                        }
@@ -683,26 +668,20 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
                                        break;
 
        case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
-               dbg("TIOCMBIC");
+               dbg(__FUNCTION__ "TIOCMBIC");
                if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
                if (mask & TIOCM_DTR){
-                       if ((ret = usb_control_msg(serial->dev, 
-                                           usb_sndctrlpipe(serial->dev, 0),
-                                           FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                           FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                           FTDI_SIO_SET_DTR_LOW , 0,
-                                           buf, 0, WDR_TIMEOUT)) < 0){
+                       if ((ret = set_dtr(serial->dev, 
+                                          usb_sndctrlpipe(serial->dev, 0),
+                                          LOW)) < 0){
                                err("Urb to unset DTR failed");
                                return(ret);
                        }
                }       
                if (mask & TIOCM_RTS) {
-                       if ((ret = usb_control_msg(serial->dev, 
-                                              usb_sndctrlpipe(serial->dev, 0),
-                                              FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-                                              FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                                           FTDI_SIO_SET_RTS_LOW , 0,
-                                           buf, 0, WDR_TIMEOUT)) < 0){
+                       if ((ret = set_rts(serial->dev, 
+                                          usb_sndctrlpipe(serial->dev, 0),
+                                          LOW)) < 0){
                                err("Urb to unset RTS failed");
                                return(ret);
                        }
@@ -722,11 +701,11 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
          /* This is not an error - turns out the higher layers will do 
           *  some ioctls itself (see comment above)
           */
-               dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd);
+               dbg(__FUNCTION__ "arg not supported - it was 0x%04x",cmd);
                return(-ENOIOCTLCMD);
                break;
        }
-       dbg("ftdi_sio_ioctl returning 0");
+       dbg(__FUNCTION__ " returning 0");
        return 0;
 } /* ftdi_sio_ioctl */
 
index 4535428b7c866a35067c34e30213c18c73c522df..f294a0ea587386963918454c914739b9d742e4d2 100644 (file)
@@ -635,6 +635,9 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
                                                break;
                                }
                        }
+                       /* if driver not bound, leave defaults unchanged */
+                       if (private == NULL)
+                               interface->act_altsetting = 0;
                }
                else /* "old style" driver */
                        private = driver->probe(dev, ifnum, NULL);
@@ -650,58 +653,15 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
 }
 
 
-#if    defined(CONFIG_KMOD)
+#ifdef CONFIG_HOTPLUG
 
 /*
  * USB hotplugging invokes what /proc/sys/kernel/hotplug says
  * (normally /sbin/hotplug) when USB devices get added or removed.
- */
-
-static int to_bcd (char *buf, __u16 *bcdValue)
-{
-       int     retval = 0;
-       char    *value = (char *) bcdValue;
-       int     temp;
-
-       /* digits are 0-9 then ":;<=>?" for devices using
-        * non-bcd (non-standard!) values here ... */
-
-       /* No leading (or later, trailing) zeroes since scripts do
-        * literal matches, and that's how they're doing them. */
-       if ((temp = value [1] & 0xf0) != 0) {
-               temp >>= 4;
-               temp += '0';
-               *buf++ = (char) temp;
-               retval++;
-       }
-
-       temp = value [1] & 0x0f;
-       temp += '0';
-       *buf++ = (char) temp;
-       retval++;
-
-       *buf++ = '.';
-       retval++;
-
-       temp = value [0] & 0xf0;
-       temp >>= 4;
-       temp += '0';
-       *buf++ = (char) temp;
-       retval++;
-
-       if ((temp = value [0] & 0x0f) != 0) {
-               temp += '0';
-               *buf++ = (char) temp;
-               retval++;
-       }
-       *buf++ = 0;
-
-       return retval;
-}
-
-/*
+ *
  * This invokes a user mode policy agent, typically helping to load driver
- * or other modules, configure the device, or both.
+ * or other modules, configure the device, and more.  Drivers can provide
+ * a MODULE_DEVICE_TABLE to help with module loading subtasks.
  *
  * Some synchronization is important: removes can't start processing
  * before the add-device processing completes, and vice versa.  That keeps
@@ -772,9 +732,7 @@ static void call_policy (char *verb, struct usb_device *dev)
         * all the device descriptors we don't tell them about.  Or
         * even act as usermode drivers.
         *
-        * XXX how little intelligence can we hardwire?
-        * (a) mount point: /devfs, /dev, /proc/bus/usb etc.
-        * (b) naming convention: bus1/device3, 001/003 etc.
+        * FIXME reduce hardwired intelligence here
         */
        envp [i++] = "DEVFS=/proc/bus/usb";
        envp [i++] = scratch;
@@ -782,14 +740,14 @@ static void call_policy (char *verb, struct usb_device *dev)
                dev->bus->busnum, dev->devnum) + 1;
 #endif
 
-       /* per-device configuration hacks are often necessary */
+       /* per-device configuration hacks are common */
        envp [i++] = scratch;
-       scratch += sprintf (scratch, "PRODUCT=%x/%x/",
+       scratch += sprintf (scratch, "PRODUCT=%x/%x/%x",
                dev->descriptor.idVendor,
-               dev->descriptor.idProduct);
-       scratch += to_bcd (scratch, &dev->descriptor.bcdDevice) + 1;
+               dev->descriptor.idProduct,
+               dev->descriptor.bcdDevice) + 1;
 
-       /* otherwise, use a simple (so far) generic driver binding model */
+       /* class-based driver binding models */
        envp [i++] = scratch;
        scratch += sprintf (scratch, "TYPE=%d/%d/%d",
                            dev->descriptor.bDeviceClass,
@@ -798,17 +756,18 @@ static void call_policy (char *verb, struct usb_device *dev)
        if (dev->descriptor.bDeviceClass == 0) {
                int alt = dev->actconfig->interface [0].act_altsetting;
 
-               /* simple/common case: one config, one interface, one driver
-                * unsimple cases:  everything else
+               /* a simple/common case: one config, one interface, one driver
+                * with current altsetting being a reasonable setting.
+                * everything needs a smart agent and usbdevfs; or can rely on
+                * device-specific binding policies.
                 */
+               envp [i++] = scratch;
                scratch += sprintf (scratch, "INTERFACE=%d/%d/%d",
                        dev->actconfig->interface [0].altsetting [alt].bInterfaceClass,
                        dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass,
                        dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol)
                        + 1;
                /* INTERFACE-0, INTERFACE-1, ... ? */
-       } else {
-               /* simple/common case: generic device, handled generically */
        }
        envp [i++] = 0;
        /* assert: (scratch - buf) < sizeof buf */
index caad14264070aaf0971272df8e565ebb6696bbd8..fcb662e8e27aabaa8815e0a611ad3ce6b491c926 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/video/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
+ * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
  *
  * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
  *
index 3a3a2232bfbb43a6b1dc29eeb61157f46967fb0d..5fbbee13b0bbddddb6a04f4ca097234ca7cf0438 100644 (file)
@@ -1,4 +1,5 @@
 /* Recently Update by v1.09.50 */
+#include <linux/config.h>
 #include "sis_300.h"
 
 #if defined(ALLOC_PRAGMA)
@@ -1520,4 +1521,4 @@ USHORT CalcDelay2(ULONG ROMAddr,USHORT key)
        return(data);
 }
 
-#endif /* CONFIG_FB_SIS_LINUXBIOS */
\ No newline at end of file
+#endif /* CONFIG_FB_SIS_LINUXBIOS */
index 7200365f2083064e8220076cbc9e64aff5d871dc..c7f89e4547def0464cf538f62b437258db6ab2af 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include "initdef.h"
 
 USHORT DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48},
@@ -159,4 +160,4 @@ extern void SetReg4(u16 port, unsigned long data);
 extern u8 GetReg1(u16 port, u16 index);
 extern u8 GetReg2(u16 port);
 extern u32 GetReg3(u16 port);
-extern void ClearDAC(u16 port);
\ No newline at end of file
+extern void ClearDAC(u16 port);
index b24998342cee0bcae7e8d534b44ffc683bedeb8e..195fd28f1e4a8ba05d759aa2a4a2f7ff91a6a5f5 100644 (file)
@@ -1,5 +1,6 @@
 /* Recently Update by v1.09.50 */
 
+#include <linux/config.h>
 #include "sis_301.h"
 
 #ifndef CONFIG_FB_SIS_LINUXBIOS
@@ -2864,4 +2865,4 @@ BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo)
        return 1;
 }
 
-#endif
\ No newline at end of file
+#endif
index 0f38590b4cd08463e54313150f4f684156e2d98f..89e280c0aa0a9f09e348c211104d364a03d844ef 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include "initdef.h"
 
 USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE;
index 0f24d4fb99195645c212d93b26da05cc55157f9b..592180c18810f07a13ade3988bbc553b657d8659 100644 (file)
@@ -11,6 +11,7 @@
 #define EXPORT_SYMTAB
 #undef  SISFBDEBUG
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 5cf82f46886eb2441b08bf0d1428d5bf4e04fa49..d3706c05e8e888f119ab565c4a1f109c161b270a 100644 (file)
@@ -10,7 +10,8 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: intrep.c,v 1.69 2000/08/24 09:35:47 dwmw2 Exp $
+ * - Based on Id: intrep.c,v 1.71 2000/10/27 16:51:29 dwmw2 Exp
+ * - With the ctype() changes from v1.77.
  *
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
 #include <linux/version.h>
 #include <linux/smp_lock.h>
 #include <linux/sched.h>
-
+#include <linux/ctype.h>
 
 #include "intrep.h"
 #include "jffs_fm.h"
 
-#if LINUX_VERSION_CODE < 0x20300
-#define set_current_state(x) do{current->state = x;} while (0)
-#endif
-
 #if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG
 long no_jffs_file = 0;
 long no_jffs_node = 0;
@@ -94,48 +91,7 @@ static int jffs_update_file(struct jffs_file *f, struct jffs_node *node);
 static __u8 flash_read_u8(struct mtd_info *mtd, loff_t from);
 
 #if 1
-#define _U      01
-#define _L      02
-#define _N      04
-#define _S      010
-#define _P      020
-#define _C      040
-#define _X      0100
-#define _B      0200
-
-const unsigned char jffs_ctype_[1 + 256] = {
-       0,
-       _C,     _C,     _C,     _C,     _C,     _C,     _C,     _C,
-       _C,     _C|_S,  _C|_S,  _C|_S,  _C|_S,  _C|_S,  _C,     _C,
-       _C,     _C,     _C,     _C,     _C,     _C,     _C,     _C,
-       _C,     _C,     _C,     _C,     _C,     _C,     _C,     _C,
-       _S|_B,  _P,     _P,     _P,     _P,     _P,     _P,     _P,
-       _P,     _P,     _P,     _P,     _P,     _P,     _P,     _P,
-       _N,     _N,     _N,     _N,     _N,     _N,     _N,     _N,
-       _N,     _N,     _P,     _P,     _P,     _P,     _P,     _P,
-       _P,     _U|_X,  _U|_X,  _U|_X,  _U|_X,  _U|_X,  _U|_X,  _U,
-       _U,     _U,     _U,     _U,     _U,     _U,     _U,     _U,
-       _U,     _U,     _U,     _U,     _U,     _U,     _U,     _U,
-       _U,     _U,     _U,     _P,     _P,     _P,     _P,     _P,
-       _P,     _L|_X,  _L|_X,  _L|_X,  _L|_X,  _L|_X,  _L|_X,  _L,
-       _L,     _L,     _L,     _L,     _L,     _L,     _L,     _L,
-       _L,     _L,     _L,     _L,     _L,     _L,     _L,     _L,
-       _L,     _L,     _L,     _P,     _P,     _P,     _P,     _C
-};
-
-#define jffs_isalpha(c)      ((jffs_ctype_+1)[(int)c]&(_U|_L))
-#define jffs_isupper(c)      ((jffs_ctype_+1)[(int)c]&_U)
-#define jffs_islower(c)      ((jffs_ctype_+1)[(int)c]&_L)
-#define jffs_isdigit(c)      ((jffs_ctype_+1)[(int)c]&_N)
-#define jffs_isxdigit(c)     ((jffs_ctype_+1)[(int)c]&(_X|_N))
-#define jffs_isspace(c)      ((jffs_ctype_+1)[(int)c]&_S)
-#define jffs_ispunct(c)      ((jffs_ctype_+1)[(int)c]&_P)
-#define jffs_isalnum(c)      ((jffs_ctype_+1)[(int)c]&(_U|_L|_N))
-#define jffs_isprint(c)      ((jffs_ctype_+1)[(int)c]&(_P|_U|_L|_N|_B))
-#define jffs_isgraph(c)      ((jffs_ctype_+1)[(int)c]&(_P|_U|_L|_N))
-#define jffs_iscntrl(c)      ((jffs_ctype_+1)[(int)c]&_C)
-
-void
+static void
 jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size)
 {
        char line[16];
@@ -169,7 +125,7 @@ jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size)
                printk("  ");
 
                for (i = 0; i < j; i++) {
-                       if (jffs_isgraph(line[i])) {
+                       if (isgraph(line[i])) {
                                printk("%c", line[i]);
                        }
                        else {
@@ -193,9 +149,12 @@ flash_safe_read(struct mtd_info *mtd, loff_t from,
        size_t retlen;
        int res;
 
+       D3(printk(KERN_NOTICE "flash_safe_read(%p, %08x, %p, %08x)\n",
+                 mtd, from, buf, count));
+
        res = MTD_READ(mtd, from, count, &retlen, buf);
        if (retlen != count) {
-               printk("Didn't read all bytes in flash_safe_read(). Returned %d\n", res);
+               panic("Didn't read all bytes in flash_safe_read(). Returned %d\n", res);
        }
        return res?res:retlen;
 }
@@ -367,9 +326,37 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size)
 {
        __u32 sum = 0;
        loff_t ptr = start;
-       while (size-- > 0) {
-               sum += flash_read_u8(mtd, ptr++);
+       __u8 *read_buf;
+       int i, length;
+
+       /* Allocate read buffer */
+       read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL);
+
+       /* Loop until checksum done */
+       while (size) {
+               /* Get amount of data to read */
+               if (size < 4096)
+                       length = size;
+               else
+                       length = 4096;
+
+               /* Perform flash read */
+               D3(printk(KERN_NOTICE "jffs_checksum_flash\n"));
+               flash_safe_read(mtd, ptr, &read_buf[0], length);
+
+               /* Compute checksum */
+               for (i=0; i < length ; i++)
+                       sum += read_buf[i];
+
+               /* Update pointer and size */
+               size -= length;
+               ptr += length;
        }
+
+       /* Free read buffer */
+       kfree (read_buf);
+
+       /* Return result */
        D3(printk("checksum result: 0x%08x\n", sum));
        return sum;
 }
@@ -609,12 +596,17 @@ jffs_scan_flash(struct jffs_control *c)
        loff_t pos = fmc->flash_start;
        loff_t start;
        loff_t end = fmc->flash_start + fmc->flash_size;
+       __u8 *read_buf;
+       int i, len, retlen;
 
        D1(printk("jffs_scan_flash(): start pos = 0x%lx, end = 0x%lx\n",
                  (long)pos, (long)end));
 
        flash_safe_acquire(fmc->mtd);
 
+       /* Allocate read buffer */
+       read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL);
+
        /* Start the scan.  */
        while (pos < end) {
                deleted_file = 0;
@@ -629,9 +621,22 @@ jffs_scan_flash(struct jffs_control *c)
                           something else than 0xff is found.  */
                        D1(printk("jffs_scan_flash(): 0xff at pos 0x%lx.\n",
                                  (long)pos));
-                       for (; pos < end
-                              && JFFS_EMPTY_BITMASK == flash_read_u32(fmc->mtd, pos);
-                            pos += 4);
+
+                       len = end - pos < 4096 ? end - pos : 4096;
+
+                       retlen = flash_safe_read(fmc->mtd, pos,
+                                                &read_buf[0], len);
+
+                       retlen &= ~3;
+
+                       for (i=0 ; i < retlen ; i+=4, pos += 4) {
+                               if(*((__u32 *) &read_buf[i]) !=
+                                               JFFS_EMPTY_BITMASK)
+                                       break;
+                       }
+                       if (i == retlen)
+                               continue;
+
                        D1(printk("jffs_scan_flash(): 0xff ended at "
                                  "pos 0x%lx.\n", (long)pos));
 
@@ -748,7 +753,12 @@ jffs_scan_flash(struct jffs_control *c)
                        if (!(node = (struct jffs_node *)
                                     kmalloc(sizeof(struct jffs_node),
                                             GFP_KERNEL))) {
+                               /* Free read buffer */
+                               kfree (read_buf);
+
+                               /* Release the flash device */
                                flash_safe_release(fmc->mtd);
+       
                                return -ENOMEM;
                        }
                        DJM(no_jffs_node++);
@@ -893,7 +903,13 @@ jffs_scan_flash(struct jffs_control *c)
                                D(printk("jffs_scan_flash(): !node->fm\n"));
                                kfree(node);
                                DJM(no_jffs_node--);
+
+                               /* Free read buffer */
+                               kfree (read_buf);
+
+                               /* Release the flash device */
                                flash_safe_release(fmc->mtd);
+
                                return -ENOMEM;
                        }
                        if ((err = jffs_insert_node(c, 0, &raw_inode,
@@ -911,7 +927,13 @@ jffs_scan_flash(struct jffs_control *c)
                                        D(printk("jffs_scan_flash: !dl\n"));
                                        kfree(node);
                                        DJM(no_jffs_node--);
+
+                                       /* Release the flash device */
                                        flash_safe_release(fmc->flash_part);
+
+                                       /* Free read buffer */
+                                       kfree (read_buf);
+
                                        return -ENOMEM;
                                }
                                dl->ino = deleted_file;
@@ -936,6 +958,11 @@ jffs_scan_flash(struct jffs_control *c)
                DJM(no_jffs_node--);
        }
        jffs_build_end(fmc);
+
+       /* Free read buffer */
+       kfree (read_buf);
+
+       /* Return happy */
        D3(printk("jffs_scan_flash(): Leaving...\n"));
        flash_safe_release(fmc->mtd);
        return 0;
@@ -1598,6 +1625,7 @@ jffs_get_node_data(struct jffs_file *f, struct jffs_node *node,
                  f->name, node->ino, node->version, node_offset));
 
        r = jffs_min(avail, max_size);
+       D3(printk(KERN_NOTICE "jffs_get_node_data\n"));
        flash_safe_read(fmc->mtd, pos, buf, r);
 
        D3(printk("  jffs_get_node_data(): Read %u byte%s.\n",
index 4df91abe3a3523149a025d4df933e92a5e92d800..4b6afe2e9c61400ffbad68e8c8c14aed03058cd1 100644 (file)
@@ -86,10 +86,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
 
        case NCP_IOC_CONN_LOGGED_IN:
 
-               if ((permission(inode, MAY_WRITE) != 0)
-                   && (current->uid != server->m.mounted_uid)) {
+               if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
-               }
                if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
                        return -EINVAL;
                if (server->root_setuped)
@@ -207,8 +205,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                        struct nw_info_struct i;
                        struct dentry* dentry;
 
-                       if (   (permission(inode, MAY_WRITE) != 0)
-                           && (current->uid != server->m.mounted_uid))
+                       if (!capable(CAP_SYS_ADMIN))
                        {
                                return -EACCES;
                        }
@@ -513,8 +510,7 @@ outrel:
  * Thanks Petr Vandrovec for idea and many hints.
  */
        case NCP_IOC_SETCHARSETS:
-               if ((permission(inode, MAY_WRITE) != 0) &&
-                                (current->uid != server->m.mounted_uid))
+               if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
                if (server->root_setuped)
                        return -EBUSY;
index 9272822a4f5eea5c681a0a01896da4c6a98b1df6..6e09c8bf2613d3578f1a114f10e8cffcb1e69a49 100644 (file)
@@ -1005,6 +1005,8 @@ ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen,
 
                /* this is wrong! */
                vname_cc = kmalloc(vlen, GFP_KERNEL);
+               if (!vname_cc)
+                       return -ENOMEM;
                for (i = 0; i < vlen; i++)
                        vname_cc[i] = ncp_tolower(in, vname[i]);
                vname = vname_cc;
index cda20c9f605bbf9ba4f9f5d0011ffc72ca811242..8c527656000c36a1887329f92dec8aec39e818de 100644 (file)
@@ -372,7 +372,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
                task->start_time,
                vsize,
                mm ? mm->rss : 0, /* you might want to shift this left 3 */
-               task->rlim ? task->rlim[RLIMIT_RSS].rlim_cur : 0,
+               task->rlim[RLIMIT_RSS].rlim_cur,
                mm ? mm->start_code : 0,
                mm ? mm->end_code : 0,
                mm ? mm->start_stack : 0,
index 1aedb342448972979a84661b533f3ec3e4cadef9..0e4a1e3a678f7681375250f7dd40eddebb8e5145 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/current.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/compiler.h>      /* __builtin_expect */
 
 #define DEBUG_SEMAPHORE 0
 #define DEBUG_RW_SEMAPHORE 0
index 4b95d09cd68d4864f4788346d24f5f33a2af815f..4e77e5d8a02f80ffb4a296f10142020980cdb2ae 100644 (file)
@@ -146,200 +146,6 @@ static void __init check_popad(void)
 #endif
 }
 
-/*
- *     B step AMD K6 before B 9730xxxx have hardware bugs that can cause
- *     misexecution of code under Linux. Owners of such processors should
- *     contact AMD for precise details and a CPU swap.
- *
- *     See     http://www.mygale.com/~poulot/k6bug.html
- *             http://www.amd.com/K6/k6docs/revgd.html
- *
- *     The following test is erm.. interesting. AMD neglected to up
- *     the chip setting when fixing the bug but they also tweaked some
- *     performance at the same time..
- */
-extern void vide(void);
-__asm__(".align 4\nvide: ret");
-
-static void __init check_amd_k6(void)
-{
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-           boot_cpu_data.x86 == 5 &&
-           boot_cpu_data.x86_model == 6 &&
-           boot_cpu_data.x86_mask == 1)
-       {
-               int n;
-               void (*f_vide)(void);
-               unsigned long d, d2;
-
-               printk(KERN_INFO "AMD K6 stepping B detected - ");
-
-#define K6_BUG_LOOP 1000000
-
-               /*
-                * It looks like AMD fixed the 2.6.2 bug and improved indirect 
-                * calls at the same time.
-                */
-
-               n = K6_BUG_LOOP;
-               f_vide = vide;
-               rdtscl(d);
-               while (n--) 
-                       f_vide();
-               rdtscl(d2);
-               d = d2-d;
-
-               /* Knock these two lines out if it debugs out ok */
-               printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
-               printk(KERN_INFO "AMD K6 stepping B detected - ");
-               /* -- cut here -- */
-               if (d > 20*K6_BUG_LOOP) 
-                       printk("system stability may be impaired when more than 32 MB are used.\n");
-               else 
-                       printk("probably OK (after B9730xxxx).\n");
-               printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
-       }
-}
-
-/*
- * All current models of Pentium and Pentium with MMX technology CPUs
- * have the F0 0F bug, which lets nonpriviledged users lock up the system:
- */
-
-#ifndef CONFIG_M686
-extern void trap_init_f00f_bug(void);
-
-static void __init check_pentium_f00f(void)
-{
-       /*
-        * Pentium and Pentium MMX
-        */
-       boot_cpu_data.f00f_bug = 0;
-       if (boot_cpu_data.x86 == 5 && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
-               printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
-               boot_cpu_data.f00f_bug = 1;
-               trap_init_f00f_bug();
-       }
-}
-#endif
-
-/*
- * Perform the Cyrix 5/2 test. A Cyrix won't change
- * the flags, while other 486 chips will.
- */
-
-static inline int test_cyrix_52div(void)
-{
-       unsigned int test;
-
-       __asm__ __volatile__(
-            "sahf\n\t"         /* clear flags (%eax = 0x0005) */
-            "div %b2\n\t"      /* divide 5 by 2 */
-            "lahf"             /* store flags into %ah */
-            : "=a" (test)
-            : "0" (5), "q" (2)
-            : "cc");
-
-       /* AH is 0x02 on Cyrix after the divide.. */
-       return (unsigned char) (test >> 8) == 0x02;
-}
-
-/*
- * Fix cpuid problems with Cyrix CPU's:
- *   -- on the Cx686(L) the cpuid is disabled on power up.
- *   -- braindamaged BIOS disable cpuid on the Cx686MX.
- */
-
-extern unsigned char Cx86_dir0_msb;  /* exported HACK from cyrix_model() */
-
-static void __init check_cx686_cpuid(void)
-{
-       if (boot_cpu_data.cpuid_level == -1 &&
-           ((Cx86_dir0_msb == 5) || (Cx86_dir0_msb == 3))) {
-               int eax, dummy;
-               unsigned char ccr3, ccr4;
-               __u32 old_cap;
-
-               cli();
-               ccr3 = getCx86(CX86_CCR3);
-               setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
-               ccr4 = getCx86(CX86_CCR4);
-               setCx86(CX86_CCR4, ccr4 | 0x80);          /* enable cpuid  */
-               setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-               sti();
-
-               /* we have up to level 1 available on the Cx6x86(L|MX) */
-               boot_cpu_data.cpuid_level = 1;
-               /*  Need to preserve some externally computed capabilities  */
-               old_cap = boot_cpu_data.x86_capability & X86_FEATURE_MTRR;
-               cpuid(1, &eax, &dummy, &dummy,
-                     &boot_cpu_data.x86_capability);
-               boot_cpu_data.x86_capability |= old_cap;
-
-               boot_cpu_data.x86 = (eax >> 8) & 15;
-               /*
-                * we already have a cooked step/rev number from DIR1
-                * so we don't use the cpuid-provided ones.
-                */
-       }
-}
-
-/*
- * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
- * BIOSes for compatability with DOS games.  This makes the udelay loop
- * work correctly, and improves performance.
- */
-
-extern void calibrate_delay(void) __init;
-
-static void __init check_cx686_slop(void)
-{
-       if (Cx86_dir0_msb == 3) {
-               unsigned char ccr3, ccr5;
-
-               cli();
-               ccr3 = getCx86(CX86_CCR3);
-               setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
-               ccr5 = getCx86(CX86_CCR5);
-               if (ccr5 & 2)
-                       setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
-               setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-               sti();
-
-               if (ccr5 & 2) { /* possible wrong calibration done */
-                       printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
-                       calibrate_delay();
-                       boot_cpu_data.loops_per_sec = loops_per_sec;
-               }
-       }
-}
-
-/*
- * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
- * by the fact that they preserve the flags across the division of 5/2.
- * PII and PPro exhibit this behavior too, but they have cpuid available.
- */
-
-static void __init check_cyrix_cpu(void)
-{
-       if ((boot_cpu_data.cpuid_level == -1) && (boot_cpu_data.x86 == 4)
-           && test_cyrix_52div()) {
-
-               strcpy(boot_cpu_data.x86_vendor_id, "CyrixInstead");
-       }
-}
-/*
- * In setup.c's cyrix_model() we have set the boot_cpu_data.coma_bug
- * on certain processors that we know contain this bug and now we
- * enable the workaround for it.
- */
-
-static void __init check_cyrix_coma(void)
-{
-}
 /*
  * Check whether we are able to run this kernel safely on SMP.
  *
@@ -391,7 +197,7 @@ static void __init check_config(void)
  */
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
        if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
-           && boot_cpu_data.x86_capability & X86_FEATURE_APIC
+           && test_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability)
            && boot_cpu_data.x86 == 5
            && boot_cpu_data.x86_model == 2
            && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
@@ -409,10 +215,7 @@ static void __init check_config(void)
 
 static void __init check_bugs(void)
 {
-       check_cyrix_cpu();
        identify_cpu(&boot_cpu_data);
-       check_cx686_cpuid();
-       check_cx686_slop();
 #ifndef CONFIG_SMP
        printk("CPU: ");
        print_cpu_info(&boot_cpu_data);
@@ -421,10 +224,5 @@ static void __init check_bugs(void)
        check_fpu();
        check_hlt();
        check_popad();
-       check_amd_k6();
-#ifndef CONFIG_M686
-       check_pentium_f00f();
-#endif
-       check_cyrix_coma();
        system_utsname.machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
 }
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
new file mode 100644 (file)
index 0000000..598edbd
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * cpufeature.h
+ *
+ * Defines x86 CPU feature bits
+ */
+
+#ifndef __ASM_I386_CPUFEATURE_H
+#define __ASM_I386_CPUFEATURE_H
+
+/* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */
+#define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT)
+
+#define NCAPINTS       4       /* Currently we have 4 32-bit words worth of info */
+
+/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
+#define X86_FEATURE_FPU                (0*32+ 0) /* Onboard FPU */
+#define X86_FEATURE_VME                (0*32+ 1) /* Virtual Mode Extensions */
+#define X86_FEATURE_DE         (0*32+ 2) /* Debugging Extensions */
+#define X86_FEATURE_PSE        (0*32+ 3) /* Page Size Extensions */
+#define X86_FEATURE_TSC                (0*32+ 4) /* Time Stamp Counter */
+#define X86_FEATURE_MSR                (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_PAE                (0*32+ 6) /* Physical Address Extensions */
+#define X86_FEATURE_MCE                (0*32+ 7) /* Machine Check Architecture */
+#define X86_FEATURE_CX8                (0*32+ 8) /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC       (0*32+ 9) /* Onboard APIC */
+#define X86_FEATURE_SEP                (0*32+11) /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR       (0*32+12) /* Memory Type Range Registers */
+#define X86_FEATURE_PGE                (0*32+13) /* Page Global Enable */
+#define X86_FEATURE_MCA                (0*32+14) /* Machine Check Architecture */
+#define X86_FEATURE_CMOV       (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_PAT                (0*32+16) /* Page Attribute Table */
+#define X86_FEATURE_PSE36      (0*32+17) /* 36-bit PSEs */
+#define X86_FEATURE_PN         (0*32+18) /* Processor serial number */
+#define X86_FEATURE_CLFLSH     (0*32+19) /* Supports the CLFLUSH instruction */
+#define X86_FEATURE_DTES       (0*32+21) /* Debug Trace Store */
+#define X86_FEATURE_ACPI       (0*32+22) /* ACPI via MSR */
+#define X86_FEATURE_MMX                (0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR       (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
+                                         /* of FPU context), and CR4.OSFXSR available */
+#define X86_FEATURE_XMM                (0*32+25) /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2       (0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_SELFSNOOP  (0*32+27) /* CPU self snoop */
+#define X86_FEATURE_ACC                (0*32+29) /* Automatic clock control */
+#define X86_FEATURE_IA64       (0*32+30) /* IA-64 processor */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL    (1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MMXEXT     (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_LM         (1*32+29) /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT   (1*32+30) /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW      (1*32+31) /* 3DNow! */
+
+/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
+#define X86_FEATURE_RECOVERY   (2*32+ 0) /* CPU in recovery mode */
+#define X86_FEATURE_LONGRUN    (2*32+ 1) /* Longrun power control */
+#define X86_FEATURE_LRTI       (2*32+ 3) /* LongRun table interface */
+
+/* Other features, Linux-defined mapping, word 3 */
+/* This range is used for feature bits which conflict or are synthesized */
+#define X86_FEATURE_CXMMX      (3*32+ 0) /* Cyrix MMX extensions */
+#define X86_FEATURE_K6_MTRR    (3*32+ 1) /* AMD K6 nonstandard MTRRs */
+#define X86_FEATURE_CYRIX_ARR  (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_MCR        (3*32+ 3) /* Centaur MCRs (= MTRRs) */
+
+#endif /* __ASM_I386_CPUFEATURE_H */
+
+/* 
+ * Local Variables:
+ * mode:c
+ * comment-column:42
+ * End:
+ */
index 55ffacff16a26602c6405aa764ef0072345ace6d..c8d826232e19c0605180842d19bf3df374f0ce87 100644 (file)
@@ -8,6 +8,8 @@
 #include <asm/ptrace.h>
 #include <asm/user.h>
 
+#include <linux/utsname.h>
+
 typedef unsigned long elf_greg_t;
 
 #define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
@@ -84,7 +86,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
    instruction set this CPU supports.  This could be done in user space,
    but it's not easy, and we've already done it here.  */
 
-#define ELF_HWCAP      (boot_cpu_data.x86_capability)
+#define ELF_HWCAP      (boot_cpu_data.x86_capability[0])
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
@@ -93,7 +95,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
    For the moment, we have only optimizations for the Intel generations,
    but that could change... */
 
-#define ELF_PLATFORM  ("i386\0i486\0i586\0i686"+(((boot_cpu_data.x86>6?6:boot_cpu_data.x86)-3)*5))
+#define ELF_PLATFORM  (system_utsname.machine)
 
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
index dfb9c0591bfdeb92be68b643f91ae601672d337a..5b52abdfe07c2553f461e4648b89dc213141214b 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/page.h>
 #include <asm/types.h>
 #include <asm/sigcontext.h>
+#include <asm/cpufeature.h>
 #include <linux/config.h>
 #include <linux/threads.h>
 
@@ -37,8 +38,8 @@ struct cpuinfo_x86 {
        char    hlt_works_ok;   /* Problems on some 486Dx4's and old 386's */
        char    hard_math;
        char    rfu;
-       int     cpuid_level;    /* Maximum supported CPUID level, -1=no CPUID */
-       __u32   x86_capability;
+               int     cpuid_level;    /* Maximum supported CPUID level, -1=no CPUID */
+       __u32   x86_capability[NCAPINTS];
        char    x86_vendor_id[16];
        char    x86_model_id[64];
        int     x86_cache_size;  /* in KB - valid for CPUS which support this
@@ -67,39 +68,6 @@ struct cpuinfo_x86 {
  * capabilities of CPUs
  */
 
-#define X86_FEATURE_FPU                0x00000001      /* onboard FPU */
-#define X86_FEATURE_VME                0x00000002      /* Virtual Mode Extensions */
-#define X86_FEATURE_DE         0x00000004      /* Debugging Extensions */
-#define X86_FEATURE_PSE                0x00000008      /* Page Size Extensions */
-#define X86_FEATURE_TSC                0x00000010      /* Time Stamp Counter */
-#define X86_FEATURE_MSR                0x00000020      /* Model-Specific Registers, RDMSR, WRMSR */
-#define X86_FEATURE_PAE                0x00000040      /* Physical Address Extensions */
-#define X86_FEATURE_MCE                0x00000080      /* Machine Check Exceptions */
-#define X86_FEATURE_CX8                0x00000100      /* CMPXCHG8 instruction */
-#define X86_FEATURE_APIC       0x00000200      /* onboard APIC */
-#define X86_FEATURE_10         0x00000400
-#define X86_FEATURE_SEP                0x00000800      /* Fast System Call */ 
-#define X86_FEATURE_MTRR       0x00001000      /* Memory Type Range Registers */
-#define X86_FEATURE_PGE                0x00002000      /* Page Global Enable */
-#define X86_FEATURE_MCA                0x00004000      /* Machine Check Architecture */
-#define X86_FEATURE_CMOV       0x00008000      /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
-#define X86_FEATURE_PAT                0x00010000      /* Page Attribute Table */
-#define X86_FEATURE_PSE36      0x00020000      /* 36-bit PSEs */
-#define X86_FEATURE_PN         0x00040000
-#define X86_FEATURE_19         0x00080000
-#define X86_FEATURE_20         0x00100000
-#define X86_FEATURE_21         0x00200000
-#define X86_FEATURE_22         0x00400000
-#define X86_FEATURE_MMX                0x00800000      /* Multimedia Extensions */
-#define X86_FEATURE_FXSR       0x01000000      /* FXSAVE and FXRSTOR instructions (fast save and restore of FPU context), and CR4.OSFXSR (OS uses these instructions) available */
-#define X86_FEATURE_XMM                0x02000000      /* Streaming SIMD Extensions */
-#define X86_FEATURE_26         0x04000000
-#define X86_FEATURE_27         0x08000000
-#define X86_FEATURE_28         0x10000000
-#define X86_FEATURE_29         0x20000000
-#define X86_FEATURE_30         0x40000000
-#define X86_FEATURE_AMD3D      0x80000000
-
 extern struct cpuinfo_x86 boot_cpu_data;
 extern struct tss_struct init_tss[NR_CPUS];
 
@@ -112,21 +80,21 @@ extern struct cpuinfo_x86 cpu_data[];
 #endif
 
 #define cpu_has_pge \
-               (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+               (test_bit(X86_FEATURE_PGE,  &boot_cpu_data.x86_capability))
 #define cpu_has_pse \
-               (boot_cpu_data.x86_capability & X86_FEATURE_PSE)
+               (test_bit(X86_FEATURE_PSE,  &boot_cpu_data.x86_capability))
 #define cpu_has_pae \
-               (boot_cpu_data.x86_capability & X86_FEATURE_PAE)
+               (test_bit(X86_FEATURE_PAE,  &boot_cpu_data.x86_capability))
 #define cpu_has_tsc \
-               (boot_cpu_data.x86_capability & X86_FEATURE_TSC)
+               (test_bit(X86_FEATURE_TSC,  &boot_cpu_data.x86_capability))
 #define cpu_has_de \
-               (boot_cpu_data.x86_capability & X86_FEATURE_DE)
+               (test_bit(X86_FEATURE_DE,   &boot_cpu_data.x86_capability))
 #define cpu_has_vme \
-               (boot_cpu_data.x86_capability & X86_FEATURE_VME)
+               (test_bit(X86_FEATURE_VME,  &boot_cpu_data.x86_capability))
 #define cpu_has_fxsr \
-               (boot_cpu_data.x86_capability & X86_FEATURE_FXSR)
+               (test_bit(X86_FEATURE_FXSR, &boot_cpu_data.x86_capability))
 #define cpu_has_xmm \
-               (boot_cpu_data.x86_capability & X86_FEATURE_XMM)
+               (test_bit(X86_FEATURE_XMM,  &boot_cpu_data.x86_capability))
 
 extern char ignore_irq13;
 
@@ -135,7 +103,28 @@ extern void print_cpu_info(struct cpuinfo_x86 *);
 extern void dodgy_tsc(void);
 
 /*
- *     Generic CPUID function
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF  0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF  0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF  0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF  0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF  0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF  0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF  0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF  0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF  0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL        0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT  0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF  0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM  0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC  0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID  0x00200000 /* CPUID detection flag */
+
+/*
+ * Generic CPUID function
  */
 extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
 {
@@ -147,6 +136,45 @@ extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
                : "a" (op));
 }
 
+/*
+ * CPUID functions returning a single datum
+ */
+extern inline unsigned int cpuid_eax(unsigned int op)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       __asm__("cpuid"
+               : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+               : "a" (op));
+       return eax;
+}
+extern inline unsigned int cpuid_ebx(unsigned int op)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       __asm__("cpuid"
+               : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+               : "a" (op));
+       return ebx;
+}
+extern inline unsigned int cpuid_ecx(unsigned int op)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       __asm__("cpuid"
+               : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+               : "a" (op));
+       return ecx;
+}
+extern inline unsigned int cpuid_edx(unsigned int op)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       __asm__("cpuid"
+               : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+               : "a" (op));
+       return edx;
+}
 
 /*
  * Intel CPU features in CR4
index 624bc55ed95e09c9d330d326b70d49f7cf0434af..66e56ec15b66a6439b9ac5715937b65180d104bd 100644 (file)
@@ -112,6 +112,6 @@ void free_divert_blk(struct net_device *);
 int divert_ioctl(unsigned int cmd, struct divert_cf *arg);
 void divert_frame(struct sk_buff *skb);
 
-#endif __KERNEL__
+#endif 
 
 #endif /* _LINUX_DIVERT_H */
index 266dc0f2525c2c4ab4c8f44cdfb4daf096969849..c7448158b152bfbfb07be3a8cd1c03e659b64d32 100644 (file)
@@ -139,23 +139,4 @@ struct dn_addr {
 #define OSIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, int)
 #define OSIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, int)
 
-/*
- * An unofficial structure used to set/get routes.
- * Be warned, this will probably change as the routing
- * evolves. Also this is only for use with the ioctl()
- * and the routing will use rtnetlink eventually.
- */
-struct dn_fib_rtinfo {
-       unsigned long flags; /* Flags */
-#define DN_FIB_RTINFO_F_REPLACE 0x0001  /* Replace any existing route */
-#define DN_FIB_RTINFO_F_DEVCOST 0x0002  /* Add cost of device         */
-       unsigned long timeout; /* Time in seconds route should last */
-       unsigned short src;  /* Source Address, 0 = any */
-       unsigned short dst;  /* Destination Address     */
-       unsigned short nhp;  /* Next Hop Address        */
-       unsigned short hops; /* Hops on path            */
-       unsigned short cost; /* Cost of path            */
-       char device[16];
-};
-
 #endif /* _LINUX_DN_H */
index 6a398694fa556b649b24e753d9f92acda6383690..384171b3f6eb3aa2483fda14c108aec4ebd0f7eb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ethtool.h,v 1.1 2000/11/10 05:44:33 davem Exp $
+/* $Id: ethtool.h,v 1.2 2000/11/12 10:05:57 davem Exp $
  * ethtool.h: Defines for Linux ethtool.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
@@ -79,6 +79,7 @@ struct ethtool_cmd {
 #define PORT_AUI               0x01
 #define PORT_MII               0x02
 #define PORT_FIBRE             0x03
+#define PORT_BNC               0x04
 
 /* Which tranceiver to use. */
 #define XCVR_INTERNAL          0x00
index f367280113ce3aad5e2034efa2a8a4825acda33b..6ef5b4c780f9b38099e5c2c3f59b4d0e459e10c4 100644 (file)
@@ -73,7 +73,7 @@ extern struct kernel_param __setup_start, __setup_end;
  * Mark functions and data as being only used at initialization
  * or exit time.
  */
-#define __init         /* __attribute__ ((__section__ (".text.init"))) */
+#define __init         __attribute__ ((__section__ (".text.init")))
 #define __exit         __attribute__ ((unused, __section__(".text.exit")))
 #define __initdata     __attribute__ ((__section__ (".data.init")))
 #define __exitdata     __attribute__ ((unused, __section__ (".data.exit")))
index 2f8704f025b4bb1b754d765c61d09ff5d3e81a55..3064eec9cb8e2691d3849bd3592c87c452c3bf7d 100644 (file)
 #define NF_DN_ROUTE            6
 #define NF_DN_NUMHOOKS         7
 
+enum nf_dn_hook_priorities {
+       NF_DN_PRI_FIRST = INT_MIN,
+       NF_DN_PRI_CONNTRACK = -200,
+       NF_DN_PRI_MANGLE = -150,
+       NF_DN_PRI_NAT_DST = -100,
+       NF_DN_PRI_FILTER = 0,
+       NF_DN_PRI_NAT_SRC = 100,
+       NF_DN_PRI_DNRTMSG = 200,
+       NF_DN_PRI_LAST = INT_MAX,
+};
+
+struct nf_dn_rtmsg {
+       int nfdn_ifindex;
+};
+
+#define NFDN_RTMSG(r) ((unsigned char *)(r) + NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg)))
+
+#define DNRMG_L1_GROUP 0x01
+#define DNRMG_L2_GROUP 0x02
+
 #endif /*__LINUX_DECNET_NETFILTER_H*/
index 41e7d92cce55ecc9c1c27589a97fd56c4f7e49cf..2afb52e98531b9ea42f72175069e8d4b7d4d7e83 100644 (file)
@@ -8,6 +8,7 @@
 #define NETLINK_ARPD           8
 #define NETLINK_ROUTE6         11      /* af_inet6 route comm channel */
 #define NETLINK_IP6_FW         13
+#define NETLINK_DNRTMSG                14      /* DECnet routing messages */
 #define NETLINK_TAPBASE                16      /* 16 to 31 are ethertap */
 
 #define MAX_LINKS 32           
index 668ed1c2b24fdfc208a6a32368fdc59f87fb9310..7b184ce94cb5534aca9333628bcd998ad812dd50 100644 (file)
@@ -87,5 +87,5 @@ extern void md_print_devices (void);
 
 #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
 
-#endif _MD_H
+#endif 
 
index 1dd42218584f9c5ca13774a6f15b44fd2cf77abe..35e60bd1ab4681e4121998b1ea0fe3f343245410 100644 (file)
@@ -31,7 +31,7 @@
 /* 001 */
 extern __inline__ int md_cpu_has_mmx(void)
 {
-       return boot_cpu_data.x86_capability & X86_FEATURE_MMX;
+       return test_bit(X86_FEATURE_MMX,  &boot_cpu_data.x86_capability);
 }
 #endif
 
@@ -152,5 +152,5 @@ typedef wait_queue_head_t md_wait_queue_head_t;
 
 /* END */
 
-#endif _MD_COMPATIBLE_H
+#endif 
 
index ce998195ced2fdd8deed6fc14ed1d93768bb7dbf..41d729e165a33c9a7279e4ac369c47acf8ac6fe8 100644 (file)
@@ -365,5 +365,5 @@ do {                                                                        \
        __wait_event_lock_irq(wq, condition, lock);                     \
 } while (0)
 
-#endif _MD_K_H
+#endif 
 
index 0c6e1a368e11b672e8e1642bd776624495e91edb..d6bb37a810b3f41f4e1d48acc6dae837e1be76ed 100644 (file)
@@ -168,5 +168,5 @@ static inline __u64 md_event(mdp_super_t *sb) {
        return (ev<<32)| sb->events_lo;
 }
 
-#endif _MD_P_H
+#endif 
 
index 9478513f903c71ff5cdc06a9e7e74bd3a2dc0371..c96b0e4043869c04e7b92af8993c592d7a08fdf6 100644 (file)
@@ -111,5 +111,5 @@ typedef struct mdu_param_s
        int                     max_fault;      /* unused for now */
 } mdu_param_t;
 
-#endif _MD_U_H
+#endif 
 
index 40738af958a94ff3cd107358acc1f63f8c4eff3c..0c7cab0de05cde4111ffad31b1ae0a7f01594a16 100644 (file)
@@ -139,6 +139,7 @@ enum
 #define RTPROT_MRT     10      /* Merit MRT */
 #define RTPROT_ZEBRA   11      /* Zebra */
 #define RTPROT_BIRD    12      /* BIRD */
+#define RTPROT_DNROUTED        13      /* DECnet routing daemon */
 
 /* rtm_scope
 
index eb55e776c832c45cecabc4513968ab2285406cf9..5d1f842c851271c30518397e7e59c0e8d53b8173 100644 (file)
@@ -54,7 +54,7 @@ extern unsigned int           nlm_debug;
 #undef ifdebug
 #ifdef RPC_DEBUG                       
 # define ifdebug(fac)          if (rpc_debug & RPCDBG_##fac)
-# define dfprintk(fac, args...)        do { ifdebug(fac) printk(## args); } while(0)
+# define dfprintk(fac, args...)        do { ifdebug(fac) printk(args); } while(0)
 # define RPC_IFDEBUG(x)                x
 #else
 # define dfprintk(fac, args...)        do ; while (0)
index b5155a2b6ff139011e14749151ec277dd67ae462..07f2c83e99f030f53e9b2dd4042730547719c1fd 100644 (file)
 #ifndef _LINUX_SYSCTL_H
 #define _LINUX_SYSCTL_H
 
+#include <linux/kernel.h>
+#include <linux/types.h>
 #include <linux/list.h>
 
+struct file;
+
 #define CTL_MAXNAME 10
 
 struct __sysctl_args {
index 498ea16fddc4919d3febf6c6196bca577e9b9e77..8b628d2e534197b0345a18894f26c650b2b83532 100644 (file)
@@ -39,9 +39,27 @@ extern int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri);
 extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, int *size, int noblock, int *err);
 
-#define NSP_REASON_NR 1
-#define NSP_REASON_DC 42
-#define NSP_REASON_NL 41
+#define NSP_REASON_OK 0                /* No error */
+#define NSP_REASON_NR 1                /* No resources */
+#define NSP_REASON_UN 2                /* Unrecognised node name */
+#define NSP_REASON_SD 3                /* Node shutting down */
+#define NSP_REASON_ID 4                /* Invalid destination end user */
+#define NSP_REASON_ER 5                /* End user lacks resources */
+#define NSP_REASON_OB 6                /* Object too busy */
+#define NSP_REASON_US 7                /* Unspecified error */
+#define NSP_REASON_TP 8                /* Third-Party abort */
+#define NSP_REASON_EA 9                /* End user has aborted the link */
+#define NSP_REASON_IF 10       /* Invalid node name format */
+#define NSP_REASON_LS 11       /* Local node shutdown */
+#define NSP_REASON_LL 32       /* Node lacks logical-link resources */
+#define NSP_REASON_LE 33       /* End user lacks logical-link resources */
+#define NSP_REASON_UR 34       /* Unacceptable RQSTRID or PASSWORD field */
+#define NSP_REASON_UA 36       /* Unacceptable ACCOUNT field */
+#define NSP_REASON_TM 38       /* End user timed out logical link */
+#define NSP_REASON_NU 39       /* Node unreachable */
+#define NSP_REASON_NL 41       /* No-link message */
+#define NSP_REASON_DC 42       /* Disconnect confirm */
+#define NSP_REASON_IO 43       /* Image data field overflow */
 
 #define NSP_DISCINIT 0x38
 #define NSP_DISCCONF 0x48
index fc3d83ee4e656075e13e99dfc31a11150c4fedee..22cd0863cafb910da773cd713060242adf802ac5 100644 (file)
@@ -220,5 +220,8 @@ extern unsigned long x25_display_timer(struct sock *);
 /* sysctl_net_x25.c */
 extern void x25_register_sysctl(void);
 extern void x25_unregister_sysctl(void);
-
+struct x25_skb_cb {
+       unsigned flags;
+};
+#define X25_SKB_CB(s) ((struct x25_skb_cb *) ((s)->cb))
 #endif
index 8e7455d3f82281c6a4c298a6189a34ab7ea6a7ef..25d5162b140b051354a4ae03b42045745c3be979 100644 (file)
@@ -77,16 +77,14 @@ struct task_struct * init_tasks[NR_CPUS] = {&init_task, };
 /*
  * The tasklist_lock protects the linked list of processes.
  *
- * The scheduler lock is protecting against multiple entry
- * into the scheduling code, and doesn't need to worry
- * about interrupts (because interrupts cannot call the
- * scheduler).
- *
- * The run-queue lock locks the parts that actually access
+ * The runqueue_lock locks the parts that actually access
  * and change the run-queues, and have to be interrupt-safe.
+ *
+ * If both locks are to be concurrently held, the runqueue_lock
+ * nests inside the tasklist_lock.
  */
-spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;  /* second */
-rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* third */
+spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;  /* inner */
+rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */
 
 static LIST_HEAD(runqueue_head);
 
@@ -199,12 +197,8 @@ static inline int preemption_goodness(struct task_struct * prev, struct task_str
 
 /*
  * This is ugly, but reschedule_idle() is very timing-critical.
- * We enter with the runqueue spinlock held, but we might end
- * up unlocking it early, so the caller must not unlock the
- * runqueue, it's always done by reschedule_idle().
- *
- * This function must be inline as anything that saves and restores
- * flags has to do so within the same register window on sparc (Anton)
+ * We `are called with the runqueue spinlock held and we must
+ * not claim the tasklist_lock.
  */
 static FASTCALL(void reschedule_idle(struct task_struct * p));
 
@@ -918,8 +912,8 @@ static int setscheduler(pid_t pid, int policy,
        /*
         * We play safe to avoid deadlocks.
         */
-       spin_lock_irq(&runqueue_lock);
-       read_lock(&tasklist_lock);
+       read_lock_irq(&tasklist_lock);
+       spin_lock(&runqueue_lock);
 
        p = find_process_by_pid(pid);
 
@@ -963,8 +957,8 @@ static int setscheduler(pid_t pid, int policy,
        current->need_resched = 1;
 
 out_unlock:
-       read_unlock(&tasklist_lock);
-       spin_unlock_irq(&runqueue_lock);
+       spin_unlock(&runqueue_lock);
+       read_unlock_irq(&tasklist_lock);
 
 out_nounlock:
        return retval;
index d49fab93a4a0371506d1244dcc0e8751c26b273b..45e865d255f8147f7041dd6182a0466430adc256 100644 (file)
@@ -117,18 +117,18 @@ static int badness(struct task_struct *p)
  */
 static struct task_struct * select_bad_process(void)
 {
-       int points = 0, maxpoints = 0;
+       int maxpoints = 0;
        struct task_struct *p = NULL;
        struct task_struct *chosen = NULL;
 
        read_lock(&tasklist_lock);
-       for_each_task(p)
-       {
-               if (p->pid)
-                       points = badness(p);
-               if (points > maxpoints) {
-                       chosen = p;
-                       maxpoints = points;
+       for_each_task(p) {
+               if (p->pid) {
+                       int points = badness(p);
+                       if (points > maxpoints) {
+                               chosen = p;
+                               maxpoints = points;
+                       }
                }
        }
        read_unlock(&tasklist_lock);
index 576744ceae45b2d71f397a3f70ea63899c6b6db2..c01ae329c564ffd5b76c646bae8465820cbcb4c8 100644 (file)
@@ -114,7 +114,7 @@ void ax25_register_sysctl(void)
        memset(ax25_table, 0x00, ax25_table_size);
 
        for (n = 0, ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) {
-               ctl_table *child = kmalloc(sizeof(ax25_param_table, GFP_ATOMIC);
+               ctl_table *child = kmalloc(sizeof(ax25_param_table), GFP_ATOMIC);
                if (!child) {
                        while (n--)
                                kfree(ax25_table[n].child);
index 491deb0d01657bd96f4caef41585c32c6a140bc8..9c3066003d11fde6d15980d4524b41c30b52fd63 100644 (file)
@@ -2192,6 +2192,7 @@ int dev_ioctl(unsigned int cmd, void *arg)
                case SIOCSIFHWBROADCAST:
                case SIOCSIFTXQLEN:
                case SIOCSIFNAME:
+               case SIOCETHTOOL:
                        if (!capable(CAP_NET_ADMIN))
                                return -EPERM;
                        dev_load(ifr.ifr_name);
@@ -2213,9 +2214,8 @@ int dev_ioctl(unsigned int cmd, void *arg)
                 */     
                 
                default:
-                       if ((cmd >= SIOCDEVPRIVATE &&
-                           cmd <= SIOCDEVPRIVATE + 15) ||
-                           cmd == SIOCETHTOOL) {
+                       if (cmd >= SIOCDEVPRIVATE &&
+                           cmd <= SIOCDEVPRIVATE + 15) {
                                dev_load(ifr.ifr_name);
                                rtnl_lock();
                                ret = dev_ifsioc(&ifr, cmd);
index c019d3f597f6e2602481167d9466f227f9a86e94..94422e1248ca03130f4377374a9396749eeb9b73 100644 (file)
@@ -5,6 +5,8 @@ bool '  DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    bool '  DECnet: router support (EXPERIMENTAL)' CONFIG_DECNET_ROUTER
    if [ "$CONFIG_DECNET_ROUTER"  = "y" ]; then
-      bool '    DECnet: use FWMARK value as routing key (EXPERIMENTAL)' CONFIG_DECNET_ROUTE_FWMARK
+      if [ "$CONFIG_NETFILTER" = "y" ]; then
+         bool '    DECnet: use FWMARK value as routing key (EXPERIMENTAL)' CONFIG_DECNET_ROUTE_FWMARK
+      fi
    fi
 fi
index 72ab936a2f4f1aa7be104f7264e3f09fd12f8a2b..1607d6d1b04dd02c137bd5b7577d12c579a30fd7 100644 (file)
@@ -21,19 +21,11 @@ Steve's quick list of things that need finishing off:
     send/recvmsg() calls should simply be a vector of set/getsockopt()
     calls]
 
- o check MSG_TRUNC, MSG_CTRUNC are set where they should be.
+ o check MSG_CTRUNC is set where it should be.
 
  o Start to hack together user level software and add more DECnet support
    in ifconfig for example. 
 
- o Fix conninit_rx to check out each CI before queuing it. Support code is
-   now in place, so this should be easy.
-
- o Work out which errors we can return from conninit_rx. Support code is
-   now in place, so this should be easy.
-
- o Check out receiving of errors in the light of what conninit_rx can return
-
  o Test adding/deleting of routes
 
  o Test route lookup
@@ -55,7 +47,11 @@ Steve's quick list of things that need finishing off:
    allow DECnet support in netstat.
 
  o Make sure that returned connect messages are generated when they should
-   be, and that the correct error messages are sent too. Ensure that the
-   conninit receiving routine does not accept conninits with parameters
-   that we cannot handle.
+   be, and that the correct error messages are sent too. 
+
+ o Add the routing message grabbing netfilter module [written, tested,
+   awaiting merge]
+
+ o Add perfect socket hashing - an idea suggested by Paul Koning [part written,
+   awaiting debugging and merge]
 
index 8de4439798a574d27e987bf5d9871fadc7a0f6d3..ca0850b4ac2812027334ee18a2513457e7c88701 100644 (file)
@@ -33,6 +33,8 @@
  *         David S. Miller: New socket locking
  *        Steve Whitehouse: Socket list hashing/locking
  *         Arnaldo C. Melo: use capable, not suser
+ *        Steve Whitehouse: Removed unused code. Fix to use sk->allocation
+ *                          when required.
  */
 
 
@@ -538,7 +540,7 @@ static void dn_destroy_sock(struct sock *sk)
 
        switch(scp->state) {
                case DN_DN:
-                       dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_KERNEL);
+                       dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, sk->allocation);
                        scp->persist_fxn = dn_destroy_timer;
                        scp->persist = dn_nsp_persist(sk);
                        break;
@@ -550,7 +552,7 @@ static void dn_destroy_sock(struct sock *sk)
                case DN_DI:
                case DN_DR:
 disc_reject:
-                       dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_KERNEL);
+                       dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->allocation);
                case DN_NC:
                case DN_NR:
                case DN_RJ:
@@ -967,7 +969,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
 
        cb = (struct dn_skb_cb *)skb->cb;
 
-       if ((newsk = dn_alloc_sock(newsock, GFP_KERNEL)) == NULL) {
+       if ((newsk = dn_alloc_sock(newsock, sk->allocation)) == NULL) {
                release_sock(sk);
                kfree_skb(skb);
                return -ENOBUFS;
@@ -1031,7 +1033,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
 
        if (newsk->protinfo.dn.accept_mode == ACC_IMMED) {
                newsk->protinfo.dn.state = DN_CC;
-               dn_send_conn_conf(newsk, GFP_KERNEL);
+               dn_send_conn_conf(newsk, newsk->allocation);
                err = dn_wait_accept(newsock, flags);
        }
 
@@ -1388,7 +1390,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
                                return -EINVAL;
 
                        scp->state = DN_CC;
-                       dn_send_conn_conf(sk, GFP_KERNEL);
+                       dn_send_conn_conf(sk, sk->allocation);
                        err = dn_wait_accept(sock, sock->file->f_flags);
                        return err;
 
@@ -1399,7 +1401,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
 
                        scp->state = DN_DR;
                        sk->shutdown = SHUTDOWN_MASK;
-                       dn_nsp_send_disc(sk, 0x38, 0, GFP_KERNEL);
+                       dn_nsp_send_disc(sk, 0x38, 0, sk->allocation);
                        break;
 
                default:
@@ -1527,7 +1529,7 @@ static int dn_wait_run(struct sock *sk, int flags)
 
                case DN_CR:
                        scp->state = DN_CC;
-                       dn_send_conn_conf(sk, GFP_KERNEL);
+                       dn_send_conn_conf(sk, sk->allocation);
                        return dn_wait_accept(sk->socket, (flags & MSG_DONTWAIT) ? O_NONBLOCK : 0);
                case DN_CI:
                case DN_CC:
@@ -2083,7 +2085,7 @@ static int __init decnet_init(void)
        dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 #endif
 
-        printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.49s (C) 1995-2000 Linux DECnet Project Team\n");
+        printk(KERN_INFO "NET4: DECnet for Linux: V.2.4.0-test10s (C) 1995-2000 Linux DECnet Project Team\n");
 
        sock_register(&dn_family_ops);
        dev_add_pack(&dn_dix_packet_type);
@@ -2102,6 +2104,14 @@ static int __init decnet_init(void)
 #ifdef CONFIG_SYSCTL
        dn_register_sysctl();
 #endif /* CONFIG_SYSCTL */
+
+       /*
+        * Prevent DECnet module unloading until its fixed properly.
+        * Requires an audit of the code to check for memory leaks and
+        * initialisation problems etc.
+        */
+       MOD_INC_USE_COUNT;
+
        return 0;
 
 }
@@ -2111,7 +2121,6 @@ static int __init decnet_setup(char *str)
 {
        unsigned short area = simple_strtoul(str, &str, 0);
        unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
-       /* unsigned short type = simple_strtoul(*str > 0 ? ++str : str, &str, 0); */
 
        decnet_address = dn_htons(area << 10 | node);
        dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
index f05568ee5c9426ee641abad388ce7ddc4ed79e81..d8f91ac38988b34a21e529f15e465a22d4636f61 100644 (file)
@@ -19,6 +19,7 @@
  *          Steve Whitehouse : SIOCGIFCONF is now a compile time option
  *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
  *          Steve Whitehouse : Removed timer1 - its a user space issue now
+ *         Patrick Caulfield : Fixed router hello message format
  */
 
 #include <linux/config.h>
@@ -795,13 +796,14 @@ static void dn_send_router_hello(struct net_device *dev)
                        DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
        *((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize);
        ptr += 2;
-       *ptr++ = 0; /* Priority */
+       *ptr++ = dn_db->parms.priority; /* Priority */ 
        *ptr++ = 0; /* Area: Reserved */
        *((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
        ptr += 2;
        *ptr++ = 0; /* MPD: Reserved */
        i1 = ptr++;
        memset(ptr, 0, 7); /* Name: Reserved */
+       ptr += 7;
        i2 = ptr++;
 
        n = dn_neigh_elist(dev, ptr, n);
@@ -809,7 +811,7 @@ static void dn_send_router_hello(struct net_device *dev)
        *i2 = 7 * n;
        *i1 = 8 + *i2;
 
-       skb_trim(skb, (26 + *i2));
+       skb_trim(skb, (27 + *i2));
 
        pktlen = (unsigned short *)skb_push(skb, 2);
        *pktlen = dn_htons(skb->len - 2);
index 6155ebccfd912cb3aab22ba5d9b8af29571c0b49..4754cd85012292793d8dd9f77278af21792a4592 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * DECnet       An implementation of the DECnet protocol suite for the LINUX
  *              operating system.  DECnet is implemented using the  BSD Socket
@@ -23,6 +22,9 @@
  *    Steve Whitehouse:  Fixed lockup when socket filtering was enabled.
  *         Paul Koning:  Fix to push CC sockets into RUN when acks are
  *                       received.
+ *    Steve Whitehouse:
+ *   Patrick Caulfield:  Checking conninits for correctness & sending of error
+ *                       responses.
  */
 
 /******************************************************************************
 #include <net/dn_dev.h>
 #include <net/dn_route.h>
 
+extern int decnet_log_martians;
+
+static void dn_log_martian(struct sk_buff *skb, const char *msg)
+{
+       if (decnet_log_martians && net_ratelimit()) {
+               char *devname = skb->rx_dev ? skb->rx_dev->name : "???";
+               struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+               printk(KERN_INFO "DECnet: Martian packet (%s) rx_dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, cb->src, cb->dst, cb->src_port, cb->dst_port);
+       }
+}
 
 /*
  * For this function we've flipped the cross-subchannel bit
@@ -83,8 +95,6 @@ static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack)
        unsigned short type = ((ack >> 12) & 0x0003);
        int wakeup = 0;
 
-       /* printk(KERN_DEBUG "dn_ack: %hd 0x%04hx\n", type, ack); */
-
        switch(type) {
                case 0: /* ACK - Data */
                        if (after(ack, scp->ackrcv_dat)) {
@@ -148,50 +158,172 @@ static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth)
 }
 
 
+/**
+ * dn_check_idf - Check an image data field format is correct.
+ * @pptr: Pointer to pointer to image data
+ * @len: Pointer to length of image data
+ * @max: The maximum allowed length of the data in the image data field
+ * @follow_on: Check that this many bytes exist beyond the end of the image data
+ *
+ * Returns: 0 if ok, -1 on error
+ */
+static inline int dn_check_idf(unsigned char **pptr, int *len, unsigned char max, unsigned char follow_on)
+{
+       unsigned char *ptr = *pptr;
+       unsigned char flen = *ptr++;
+
+       (*len)--;
+       if (flen > max)
+               return -1;
+       if ((flen + follow_on) > *len)
+               return -1;
+
+       *len -= flen;
+       *pptr = ptr + flen;
+       return 0;
+}
+
+/*
+ * Table of reason codes to pass back to node which sent us a badly
+ * formed message, plus text messages for the log. A zero entry in
+ * the reason field means "don't reply" otherwise a disc init is sent with
+ * the specified reason code.
+ */
+static struct {
+       unsigned short reason;
+       const char *text;
+} ci_err_table[] = {
+ { 0,             "CI: Truncated message" },
+ { NSP_REASON_ID, "CI: Destination username error" },
+ { NSP_REASON_ID, "CI: Destination username type" },
+ { NSP_REASON_US, "CI: Source username error" },
+ { 0,             "CI: Truncated at menuver" },
+ { 0,             "CI: Truncated before access or user data" },
+ { NSP_REASON_IO, "CI: Access data format error" },
+ { NSP_REASON_IO, "CI: User data format error" }
+};
+
 /*
  * This function uses a slightly different lookup method
  * to find its sockets, since it searches on object name/number
- * rather than port numbers
+ * rather than port numbers. Various tests are done to ensure that
+ * the incoming data is in the correct format before it is queued to
+ * a socket.
  */
-static struct sock *dn_find_listener(struct sk_buff *skb)
+static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason)
 {
        struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
        struct nsp_conn_init_msg *msg = (struct nsp_conn_init_msg *)skb->data;
-       struct sockaddr_dn addr;
+       struct sockaddr_dn dstaddr;
+       struct sockaddr_dn srcaddr;
        unsigned char type = 0;
+       int dstlen;
+       int srclen;
+       unsigned char *ptr;
+       int len;
+       int err = 0;
+       unsigned char menuver;
 
-       memset(&addr, 0, sizeof(struct sockaddr_dn));
+       memset(&dstaddr, 0, sizeof(struct sockaddr_dn));
+       memset(&srcaddr, 0, sizeof(struct sockaddr_dn));
 
+       /*
+        * 1. Decode & remove message header
+        */
        cb->src_port = msg->srcaddr;
        cb->dst_port = msg->dstaddr;
        cb->services = msg->services;
        cb->info     = msg->info;
        cb->segsize  = dn_ntohs(msg->segsize);
 
+       if (skb->len < sizeof(*msg))
+               goto err_out;
+
        skb_pull(skb, sizeof(*msg));
 
-       /* printk(KERN_DEBUG "username2sockaddr 1\n"); */
-       if (dn_username2sockaddr(skb->data, skb->len, &addr, &type) < 0)
+       len = skb->len;
+       ptr = skb->data;
+
+       /*
+        * 2. Check destination end username format
+        */
+       dstlen = dn_username2sockaddr(ptr, len, &dstaddr, &type);
+       err++;
+       if (dstlen < 0)
                goto err_out;
 
+       err++;
        if (type > 1)
                goto err_out;
 
-       /* printk(KERN_DEBUG "looking for listener...\n"); */
-       return dn_sklist_find_listener(&addr);
+       len -= dstlen;
+       ptr += dstlen;
+
+       /*
+        * 3. Check source end username format
+        */
+       srclen = dn_username2sockaddr(ptr, len, &srcaddr, &type);
+       err++;
+       if (srclen < 0)
+               goto err_out;
+
+       len -= srclen;
+       ptr += srclen;
+       err++;
+       if (len < 1)
+               goto err_out;
+
+       menuver = *ptr;
+       ptr++;
+       len--;
+
+       /*
+        * 4. Check that optional data actually exists if menuver says it does
+        */
+       err++;
+       if ((menuver & (DN_MENUVER_ACC | DN_MENUVER_USR)) && (len < 1))
+               goto err_out;
+
+       /*
+        * 5. Check optional access data format
+        */
+       err++;
+       if (menuver & DN_MENUVER_ACC) {
+               if (dn_check_idf(&ptr, &len, 39, 1))
+                       goto err_out;
+               if (dn_check_idf(&ptr, &len, 39, 1))
+                       goto err_out;
+               if (dn_check_idf(&ptr, &len, 39, (menuver & DN_MENUVER_USR) ? 1 : 0))
+                       goto err_out;
+       }
+
+       /*
+        * 6. Check optional user data format
+        */
+       err++;
+       if (menuver & DN_MENUVER_USR) {
+               if (dn_check_idf(&ptr, &len, 16, 0))
+                       goto err_out;
+       }
+
+       /*
+        * 7. Look up socket based on destination end username
+        */
+       return dn_sklist_find_listener(&dstaddr);
 err_out:
+       dn_log_martian(skb, ci_err_table[err].text);
+       *reason = ci_err_table[err].reason;
        return NULL;
 }
 
+
 static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb)
 {
-       /* printk(KERN_DEBUG "checking backlog...\n"); */
        if (sk->ack_backlog >= sk->max_ack_backlog) {
                kfree_skb(skb);
                return;
        }
 
-       /* printk(KERN_DEBUG "waking up socket...\n"); */
        sk->ack_backlog++;
        skb_queue_tail(&sk->receive_queue, skb);
        sk->state_change(sk);
@@ -528,13 +660,20 @@ static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb)
        kfree_skb(skb);
 }
 
-static void dn_nsp_no_socket(struct sk_buff *skb)
+static void dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason)
 {
        struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
 
-       switch(cb->nsp_flags) {
-               case 0x28: /* Connect Confirm */
-                       dn_nsp_return_disc(skb, NSP_DISCCONF, NSP_REASON_NL);
+       if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {
+               switch(cb->nsp_flags & 0x70) {
+                       case 0x10:
+                       case 0x60: /* (Retransmitted) Connect Init */
+                               dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
+                               break;
+                       case 0x20: /* Connect Confirm */
+                               dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
+                               break;
+               }
        }
 
        kfree_skb(skb);
@@ -545,6 +684,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
        struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
        struct sock *sk = NULL;
        unsigned char *ptr = (unsigned char *)skb->data;
+       unsigned short reason = NSP_REASON_NL;
 
        skb->h.raw    = skb->data;
        cb->nsp_flags = *ptr++;
@@ -584,7 +724,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
                                goto free_out;
                        case 0x10:
                        case 0x60:
-                               sk = dn_find_listener(skb);
+                               sk = dn_find_listener(skb, &reason);
                                goto got_it;
                }
        }
@@ -632,7 +772,7 @@ got_it:
                return ret;
        }
 
-       dn_nsp_no_socket(skb);
+       dn_nsp_no_socket(skb, reason);
        return 1;
 
 free_out:
@@ -664,7 +804,6 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
         * Control packet.
         */
        if ((cb->nsp_flags & 0x0c) == 0x08) {
-               /* printk(KERN_DEBUG "control type\n"); */
                switch(cb->nsp_flags & 0x70) {
                        case 0x10:
                        case 0x60:
index 669aeccce9229f4c6c4abf87c17efa67dfad5ba7..6965cbf4296705e3f2b709e4259f5bae46baaaf7 100644 (file)
@@ -149,7 +149,7 @@ struct sk_buff *dn_alloc_send_skb(struct sock *sk, int *size, int noblock, int *
                        continue;
                }
 
-               if ((skb = dn_alloc_skb(sk, len, GFP_KERNEL)) == NULL)
+               if ((skb = dn_alloc_skb(sk, len, sk->allocation)) == NULL)
                        continue;
 
                *size = len - 11;
@@ -444,7 +444,7 @@ void dn_send_conn_ack (struct sock *sk)
        struct sk_buff *skb = NULL;
         struct nsp_conn_ack_msg *msg;
 
-       if ((skb = dn_alloc_skb(sk, 3, GFP_KERNEL)) == NULL)
+       if ((skb = dn_alloc_skb(sk, 3, sk->allocation)) == NULL)
                return;
 
         msg = (struct nsp_conn_ack_msg *)skb_put(skb, 3);
@@ -626,7 +626,7 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
        struct dn_skb_cb *cb;
        unsigned char type = 1;
 
-       if ((skb = dn_alloc_skb(sk, 200, (msgflg == NSP_CI) ? GFP_KERNEL : GFP_ATOMIC)) == NULL)
+       if ((skb = dn_alloc_skb(sk, 200, (msgflg == NSP_CI) ? sk->allocation : GFP_ATOMIC)) == NULL)
                return;
 
        cb  = (struct dn_skb_cb *)skb->cb;
index a2bc393987a7ede33fe0bdb881c9a1847c6495b0..20ec07acc922bd51117b77822525e8c12d3ce6fc 100644 (file)
@@ -812,8 +812,8 @@ non_local_input:
        key.oif = 0;
        key.scope = RT_SCOPE_UNIVERSE;
 
-#ifdef CONFIG_DECNET_ROUTE_FWMASK
-       key.fwmark = skb->fwmark;
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+       key.fwmark = skb->nfmark;
 #else
        key.fwmark = 0;
 #endif
@@ -890,7 +890,7 @@ int dn_route_input(struct sk_buff *skb)
                if ((rt->key.saddr == cb->src) &&
                                (rt->key.daddr == cb->dst) &&
                                (rt->key.oif == 0) &&
-#ifdef CONFIG_DECNET_ROUTE_FWMASK
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
                                (rt->key.fwmark == skb->nfmark) &&
 #endif
                                (rt->key.iif == cb->iif)) {
index c1931c867f7d597716b87a8dd795b3f97f59c475..0c9fb1f7ff8e945fe8d8df6443b58ef3f67aabad 100644 (file)
@@ -32,6 +32,7 @@ int decnet_time_wait = 30;
 int decnet_dn_count = 1;
 int decnet_di_count = 3;
 int decnet_dr_count = 3;
+int decnet_log_martians = 1;
 
 #ifdef CONFIG_SYSCTL
 extern int decnet_dst_gc_interval;
index f23b5bcf5216dbc491a1baa3ac4f67d61527bb58..67925c5b5542e6b2851d9dba820c202c1b20a207 100644 (file)
@@ -29,6 +29,7 @@
  *     
  ********************************************************************/
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/fs.h>
index e34a758b8f54a2f104e2c36777bbf928be4385f8..ead7ef6782b9341ce9679eeea2a611009f22c454 100644 (file)
@@ -8,6 +8,7 @@
  * and exchange frames with IrTTP.
  */
 
+#include <linux/config.h>
 #include "irnet_irda.h"                /* Private header */
 
 /************************* CONTROL CHANNEL *************************/
index a37d49be311626ebe6b2086ab1c3fe4ba028f8b7..0e5e9a36f519cc07eda106bc353c993f60136572 100644 (file)
@@ -14,6 +14,7 @@
 
 /***************************** INCLUDES *****************************/
 
+#include <linux/config.h>
 #include "irnet.h"             /* Module global include */
 
 /************************ CONSTANTS & MACROS ************************/
index cbfd650de739bcc29a7fe2e9d9d2b1277f914793..117f23eccb5419ebcfcb2ff2ccd1c962fa5134ec 100644 (file)
@@ -182,7 +182,7 @@ EXPORT_SYMBOL(irtty_unregister_dongle);
 EXPORT_SYMBOL(irtty_set_packet_mode);
 #endif
 
-static int __init irda_init(void)
+int __init irda_init(void)
 {
        IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
index 8cdc0a0dd499c6eed0ddcdef341dd9f61c448634..ac80c1a23ef0c68111fb396d4eeedc6eea71107c 100644 (file)
@@ -24,6 +24,7 @@
  ********************************************************************/
 
 #include <asm/system.h>
+#include <linux/config.h>
 #include <linux/delay.h>
 
 #include <net/irda/timer.h>
index 320722c40494cf3b7dccdd278f002d59c5c6bbb7..409e3bc461300c06ebb3e40ff704f1313dea0207 100644 (file)
  *     X.25 001        Jonathan Naylor Started coding.
  *     X.25 002        Jonathan Naylor Centralised disconnect handling.
  *                                     New timer architecture.
- *     2000-11-03      Henner Eisen    MSG_EOR handling more POSIX compliant.
- *     2000-22-03      Daniela Squassoni Allowed disabling/enabling of 
+ *     2000-03-11      Henner Eisen    MSG_EOR handling more POSIX compliant.
+ *     2000-03-22      Daniela Squassoni Allowed disabling/enabling of 
  *                                       facilities negotiation and increased 
  *                                       the throughput upper limit.
- *     2000-27-08      Arnaldo C. Melo s/suser/capable/ + micro cleanups
- *     2000-04-09      Henner Eisen    Set sock->state in x25_accept(). 
+ *     2000-08-27      Arnaldo C. Melo s/suser/capable/ + micro cleanups
+ *     2000-09-04      Henner Eisen    Set sock->state in x25_accept(). 
  *                                     Fixed x25_output() related skb leakage.
+ *     2000-10-02      Henner Eisen    Made x25_kick() single threaded per socket.
+ *     2000-10-27      Henner Eisen    MSG_DONTWAIT for fragment allocation.
  */
 
 #include <linux/config.h>
@@ -471,6 +473,7 @@ static int x25_create(struct socket *sock, int protocol)
 
        sock->ops    = &x25_proto_ops;
        sk->protocol = protocol;
+       sk->backlog_rcv = x25_process_rx_frame;
 
        x25->t21   = sysctl_x25_call_request_timeout;
        x25->t22   = sysctl_x25_reset_request_timeout;
@@ -905,6 +908,7 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
 
        if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
                return err;
+       X25_SKB_CB(skb)->flags = msg->msg_flags;
 
        skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);
 
@@ -974,14 +978,31 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
        if (msg->msg_flags & MSG_OOB) {
                skb_queue_tail(&sk->protinfo.x25->interrupt_out_queue, skb);
        } else {
-               err = x25_output(sk, skb);
-               if(err){
-                       len = err;
+               len = x25_output(sk, skb);
+               if(len<0){
                        kfree_skb(skb);
+               } else {
+                       if(sk->protinfo.x25->qbitincl) len++;
                }
        }
 
+       /*
+        * lock_sock() is currently only used to serialize this x25_kick()
+        * against input-driven x25_kick() calls. It currently only blocks
+        * incoming packets for this socket and does not protect against
+        * any other socket state changes and is not called from anywhere
+        * else. As x25_kick() cannot block and as long as all socket
+        * operations are BKL-wrapped, we don't need take to care about
+        * purging the backlog queue in x25_release().
+        *
+        * Using lock_sock() to protect all socket operations entirely
+        * (and making the whole x25 stack SMP aware) unfortunately would
+        * require major changes to {send,recv}msg and skb allocation methods.
+        * -> 2.5 ;)
+        */
+       lock_sock(sk);
        x25_kick(sk);
+       release_sock(sk);
 
        return len;
 }
index d986022fbd9ce57d05377dbf8664dcebcec03466..fbc781dcecaf2bce85a42afddda20e0fb2a56c30 100644 (file)
@@ -68,8 +68,17 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
         *      Find an existing socket.
         */
        if ((sk = x25_find_socket(lci, neigh)) != NULL) {
+               int queued = 1;
+
                skb->h.raw = skb->data;
-               return x25_process_rx_frame(sk, skb);
+               bh_lock_sock(sk);
+               if (!sk->lock.users) {
+                       queued = x25_process_rx_frame(sk, skb);
+               } else {
+                       sk_add_backlog(sk, skb);
+               }
+               bh_unlock_sock(sk);
+               return queued;
        }
 
        /*
index 5110d327ab83b517f3b607616b9b2683bd74cc51..c285af6c886fe3ef142f6d8fa260c41cef1d1d16 100644 (file)
  *     X.25 001        Jonathan Naylor   Started coding.
  *     X.25 002        Jonathan Naylor   Centralised disconnection code.
  *                                       New timer architecture.
- *     mar/20/00       Daniela Squassoni Disabling/enabling of facilities 
+ *     2000-03-20      Daniela Squassoni Disabling/enabling of facilities 
  *                                       negotiation.
+ *     2000-11-10      Henner Eisen      Check and reset for out-of-sequence
+ *                                       i-frames.
  */
 
 #include <linux/config.h>
@@ -216,7 +218,8 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
 
                case X25_DATA:  /* XXX */
                        sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
-                       if (!x25_validate_nr(sk, nr)) {
+                       if ((ns!=sk->protinfo.x25->vr) || 
+                           !x25_validate_nr(sk, nr)) {
                                x25_clear_queues(sk);
                                x25_write_internal(sk, X25_RESET_REQUEST);
                                x25_start_t22timer(sk);
index 077f2c0b4212f7b7f2c94f6554793cacd74c695d..b3ce3047709768abb0f95aa28eca4c8f80d6dda7 100644 (file)
  *     History
  *     X.25 001        Jonathan Naylor Started coding.
  *     X.25 002        Jonathan Naylor New timer architecture.
- *      2000-09-04     Henner Eisen    Prevented x25_output() skb leakage.
+ *     2000-09-04      Henner Eisen    Prevented x25_output() skb leakage.
+ *     2000-10-27      Henner Eisen    MSG_DONTWAIT for fragment allocation.
+ *     2000-11-10      Henner Eisen    x25_send_iframe(): re-queued frames
+ *                                     needed cleaned seq-number fields.
  */
 
 #include <linux/config.h>
@@ -55,13 +58,17 @@ static int x25_pacsize_to_bytes(unsigned int pacsize)
 }
 
 /*
- *     This is where all X.25 information frames pass;
+ *     This is where all X.25 information frames pass.
+ *
+ *      Returns the amount of user data bytes sent on success
+ *      or a negative error code on failure.
  */
 int x25_output(struct sock *sk, struct sk_buff *skb)
 {
        struct sk_buff *skbn;
        unsigned char header[X25_EXT_MIN_LEN];
        int err, frontlen, len, header_len, max_len;
+       int sent=0, noblock = X25_SKB_CB(skb)->flags & MSG_DONTWAIT;
 
        header_len = (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
        max_len    = x25_pacsize_to_bytes(sk->protinfo.x25->facilities.pacsize_out);
@@ -74,11 +81,14 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
                frontlen = skb_headroom(skb);
 
                while (skb->len > 0) {
-                       if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, 0, &err)) == NULL){
-                               int unsent = skb->len - header_len;
-                               SOCK_DEBUG(sk, "x25_output: framgent allocation failed, err=%d, %d bytes unsent\n", err, unsent); 
-                               return err;
+                       if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, noblock, &err)) == NULL){
+                               if(err == -EWOULDBLOCK && noblock){
+                                       kfree_skb(skb);
+                                       return sent;
                                }
+                               SOCK_DEBUG(sk, "x25_output: fragment allocation failed, err=%d, %d bytes sent\n", err, sent);
+                               return err;
+                       }
                                
                        skb_reserve(skbn, frontlen);
 
@@ -100,13 +110,15 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
                        }
 
                        skb_queue_tail(&sk->write_queue, skbn);
+                       sent += len;
                }
                
                kfree_skb(skb);
        } else {
                skb_queue_tail(&sk->write_queue, skb);
+               sent = skb->len - header_len;
        }
-       return 0;
+       return sent;
 }
 
 /* 
@@ -119,9 +131,11 @@ static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
                return;
 
        if (sk->protinfo.x25->neighbour->extended) {
-               skb->data[2] |= (sk->protinfo.x25->vs << 1) & 0xFE;
+               skb->data[2]  = (sk->protinfo.x25->vs << 1) & 0xFE;
+               skb->data[3] &= X25_EXT_M_BIT;
                skb->data[3] |= (sk->protinfo.x25->vr << 1) & 0xFE;
        } else {
+               skb->data[2] &= X25_STD_M_BIT;
                skb->data[2] |= (sk->protinfo.x25->vs << 1) & 0x0E;
                skb->data[2] |= (sk->protinfo.x25->vr << 5) & 0xE0;
        }