Merge with linus
authorTony Luck <tony.luck@intel.com>
Tue, 17 May 2005 16:10:20 +0000 (09:10 -0700)
committerTony Luck <tony.luck@intel.com>
Tue, 17 May 2005 16:10:20 +0000 (09:10 -0700)
205 files changed:
Documentation/dvb/README.flexcop [new file with mode: 0644]
Documentation/dvb/bt8xx.txt
Documentation/dvb/ci.txt [new file with mode: 0644]
Documentation/dvb/get_dvb_firmware
Documentation/feature-removal-schedule.txt
Makefile
arch/alpha/kernel/osf_sys.c
arch/arm/mach-s3c2410/clock.c
arch/arm/mach-s3c2410/s3c2440.c
arch/arm/mm/Kconfig
arch/arm/mm/copypage-v4mc.S [deleted file]
arch/arm/mm/copypage-v4mc.c [new file with mode: 0644]
arch/arm/mm/copypage-v6.c
arch/arm/mm/flush.c
arch/arm/mm/mm-armv.c
arch/i386/kernel/cpu/amd.c
arch/i386/kernel/cpu/common.c
arch/ia64/ia32/ia32_ioctl.c
arch/mips/vr41xx/common/pmu.c
arch/um/kernel/irq_user.c
arch/x86_64/Kconfig
arch/x86_64/defconfig
arch/x86_64/kernel/Makefile
arch/x86_64/kernel/apic.c
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/mpparse.c
arch/x86_64/kernel/nmi.c
arch/x86_64/kernel/pmtimer.c [new file with mode: 0644]
arch/x86_64/kernel/ptrace.c
arch/x86_64/kernel/setup.c
arch/x86_64/kernel/smpboot.c
arch/x86_64/kernel/time.c
arch/x86_64/kernel/vsyscall.c
arch/x86_64/mm/fault.c
arch/x86_64/mm/ioremap.c
crypto/crypto_null.c
drivers/block/ioctl.c
drivers/block/pktcdvd.c
drivers/char/raw.c
drivers/char/watchdog/i8xx_tco.c
drivers/ide/ide-proc.c
drivers/ieee1394/Kconfig
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/ieee1394_transactions.c
drivers/ieee1394/ieee1394_transactions.h
drivers/ieee1394/nodemgr.c
drivers/ieee1394/ohci1394.c
drivers/ieee1394/ohci1394.h
drivers/ieee1394/pcilynx.c
drivers/ieee1394/pcilynx.h
drivers/ieee1394/video1394.c
drivers/input/keyboard/atkbd.c
drivers/input/mouse/alps.c
drivers/input/serio/serio.c
drivers/input/serio/serport.c
drivers/md/linear.c
drivers/md/multipath.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid6main.c
drivers/media/common/saa7146_core.c
drivers/media/dvb/Kconfig
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/Makefile
drivers/media/dvb/b2c2/b2c2-common.c [deleted file]
drivers/media/dvb/b2c2/b2c2-usb-core.c [deleted file]
drivers/media/dvb/b2c2/flexcop-common.h [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-dma.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-eeprom.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-fe-tuner.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-hw-filter.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-i2c.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-misc.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-pci.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-reg.h [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-sram.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-usb.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop-usb.h [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop.c [new file with mode: 0644]
drivers/media/dvb/b2c2/flexcop.h [new file with mode: 0644]
drivers/media/dvb/b2c2/skystar2.c
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/bt8xx/Makefile
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/bt8xx/bt878.h
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dst.h [deleted file]
drivers/media/dvb/bt8xx/dst_ca.c [new file with mode: 0644]
drivers/media/dvb/bt8xx/dst_ca.h [new file with mode: 0644]
drivers/media/dvb/bt8xx/dst_common.h [new file with mode: 0644]
drivers/media/dvb/bt8xx/dst_priv.h
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/bt8xx/dvb-bt8xx.h
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
drivers/media/dvb/dibusb/dvb-dibusb.h
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/at76c651.c
drivers/media/dvb/frontends/cx22700.c
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/dib3000mb.c
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/dvb_dummy_fe.c
drivers/media/dvb/frontends/l64781.c
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/mt352.c
drivers/media/dvb/frontends/mt352.h
drivers/media/dvb/frontends/nxt2002.c
drivers/media/dvb/frontends/nxt6000.c
drivers/media/dvb/frontends/nxt6000_priv.h
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/sp8870.c
drivers/media/dvb/frontends/sp887x.c
drivers/media/dvb/frontends/stv0297.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/tda1004x.h
drivers/media/dvb/frontends/tda8083.c
drivers/media/dvb/frontends/tda80xx.c
drivers/media/dvb/frontends/ves1820.c
drivers/media/dvb/frontends/ves1x93.c
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_ca.c
drivers/media/dvb/ttpci/av7110_hw.c
drivers/media/dvb/ttpci/av7110_hw.h
drivers/media/dvb/ttpci/av7110_ir.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttpci/budget.h
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/video/Kconfig
drivers/media/video/bttv-cards.c
drivers/media/video/video-buf-dvb.c
drivers/mmc/Kconfig
drivers/mmc/wbsd.c
drivers/mmc/wbsd.h
drivers/net/Makefile
drivers/net/ibm_emac/ibm_emac_core.c
drivers/net/tulip/tulip_core.c
drivers/net/wireless/Kconfig
drivers/pcmcia/ds.c
drivers/s390/block/dasd.c
drivers/serial/21285.c
drivers/serial/8250.c
drivers/serial/amba-pl010.c
drivers/serial/amba-pl011.c
drivers/serial/clps711x.c
drivers/serial/pxa.c
drivers/serial/s3c2410.c
drivers/serial/sa1100.c
drivers/serial/serial_cs.c
drivers/serial/serial_lh7a40x.c
drivers/serial/serial_txx9.c
drivers/serial/vr41xx_siu.c
drivers/usb/core/sysfs.c
drivers/usb/host/ehci-hub.c
drivers/usb/net/Kconfig
drivers/usb/net/usbnet.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/cypress_m8.h
fs/binfmt_elf.c
fs/buffer.c
fs/proc/mmu.c
include/asm-arm/arch-imx/imx-regs.h
include/asm-arm/arch-s3c2410/regs-nand.h
include/asm-arm/page.h
include/asm-ia64/ioctl32.h
include/asm-um/elf.h [deleted file]
include/asm-x86_64/apicdef.h
include/asm-x86_64/io_apic.h
include/asm-x86_64/ioctl32.h
include/asm-x86_64/nmi.h
include/asm-x86_64/processor.h
include/asm-x86_64/proto.h
include/asm-x86_64/vsyscall.h
include/linux/serial_core.h
include/media/video-buf-dvb.h
kernel/irq/handle.c
kernel/printk.c
kernel/profile.c
mm/memory.c
mm/mremap.c
mm/nommu.c
mm/rmap.c
mm/swapfile.c
security/selinux/ss/services.c

diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop
new file mode 100644 (file)
index 0000000..a50c70f
--- /dev/null
@@ -0,0 +1,205 @@
+This README escorted the skystar2-driver rewriting procedure. It describes the
+state of the new flexcop-driver set and some internals are written down here
+too.
+
+This document hopefully describes things about the flexcop and its
+device-offsprings. Goal was to write an easy-to-write and easy-to-read set of
+drivers based on the skystar2.c and other information.
+
+Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been
+touched and rewritten.
+
+History & News
+==============
+  2005-04-01 - correct USB ISOC transfers (thanks to Vadim Catana)
+
+
+
+
+General coding processing
+=========================
+
+We should proceed as follows (as long as no one complains):
+
+0) Think before start writing code!
+
+1) rewriting the skystar2.c with the help of the flexcop register descriptions
+and splitting up the files to a pci-bus-part and a flexcop-part.
+The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the
+device-specific part and b2c2-flexcop.ko for the common flexcop-functions.
+
+2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c
+and other pci drivers)
+
+3) make some beautification (see 'Improvements when rewriting (refactoring) is
+done')
+
+4) Testing the new driver and maybe substitute the skystar2.c with it, to reach
+a wider tester audience.
+
+5) creating an usb-bus-part using the already written flexcop code for the pci
+card.
+
+Idea: create a kernel-object for the flexcop and export all important
+functions. This option saves kernel-memory, but maybe a lot of functions have
+to be exported to kernel namespace.
+
+
+Current situation
+=================
+
+0) Done :)
+1) Done (some minor issues left)
+2) Done
+3) Not ready yet, more information is necessary
+4) next to be done (see the table below)
+5) USB driver is working (yes, there are some minor issues)
+
+What seems to be ready?
+-----------------------
+
+1) Rewriting
+1a) i2c is cut off from the flexcop-pci.c and seems to work
+1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1e) eeprom (reading MAC address)
+1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me))
+1f) misc. register accesses for reading parameters (e.g. resetting, revision)
+1g) pid/mac filter (flexcop-hw-filter.c)
+1i) dvb-stuff initialization in flexcop.c (done)
+1h) dma stuff (now just using the size-irq, instead of all-together, to be done)
+1j) remove flexcop initialization from flexcop-pci.c completely (done)
+1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO')
+1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from
+non-static where possible, moved code to proper places)
+
+2) Search for errors in the leftover of flexcop-pci.c (partially done)
+5a) add MAC address reading
+5c) feeding of ISOC data to the software demux (format of the isochronous data
+and speed optimization, no real error) (thanks to Vadim Catana)
+
+What to do in the near future?
+--------------------------------------
+(no special order here)
+
+5) USB driver
+5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting)
+
+Testing changes
+---------------
+
+O             = item is working
+P             = item is partially working
+X             = item is not working
+N             = item does not apply here
+<empty field> = item need to be examined
+
+       | PCI                               | USB
+item   | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312
+-------+-------+---------+---------+-------+-------+---------+---------+-------
+1a)    | O     |         |         |       | N     | N       | N       | N
+1b)    | O     |         |         |       |       |         | O       |
+1c)    | N     | N       |         |       | N     | N       | O       |
+1d)    |                 O                 |                 O
+1e)    |                 O                 |                 O
+1f)    |                                   P
+1g)    |                                   O
+1h)    |                 P                 |
+1i)    |                 O                 |                 N
+1j)    |                 O                 |                 N
+1l)    |                 O                 |                 N
+2)     |                 O                 |                 N
+5a)    |                 N                 |                 O
+5b)*   |                 N                 |
+5c)    |                 N                 |                 O
+
+* - not done yet
+
+Known bugs and problems and TODO
+--------------------------------
+
+1g/h/l) when pid filtering is enabled on the pci card
+
+DMA usage currently:
+  The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first
+  address and triggers an IRQ when it's full and starts writing to the second
+  address. When the second address is full, the IRQ is triggered again, and
+  the flexcop writes to first address again, and so on.
+  The buffersize of each address is currently 640*188 bytes.
+
+  Problem is, when using hw-pid-filtering and doing some low-bandwidth
+  operation (like scanning) the buffers won't be filled enough to trigger
+  the IRQ. That's why:
+
+  When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ
+  is triggered.  Is the current write address of DMA1 different to the one
+  during the last IRQ, then the data is passed to the demuxer.
+
+  There is an additional DMA-IRQ-method: packet count IRQ. This isn't
+  implemented correctly yet.
+
+  The solution is to disable HW PID filtering, but I don't know how the DVB
+  API software demux behaves on slow systems with 45MBit/s TS.
+
+Solved bugs :)
+--------------
+1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't
+working)
+SOLUTION: also index 0 was affected, because net_translation is done for
+these indexes by default
+
+5b) isochronous transfer does only work in the first attempt (for the Sky2PC
+USB, Air2PC is working) SOLUTION: the flexcop was going asleep and never really
+woke up again (don't know if this need fixes, see
+flexcop-fe-tuner.c:flexcop_sleep)
+
+NEWS: when the driver is loaded and unloaded and loaded again (w/o doing
+anything in the while the driver is loaded the first time), no transfers take
+place anymore.
+
+Improvements when rewriting (refactoring) is done
+=================================================
+
+- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control
+  (enable sleeping for other demods than dvb-s)
+- add support for CableStar (stv0297 Microtune 203x/ALPS) (almost done, incompatibilities with the Nexus-CA)
+
+Debugging
+---------
+- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it
+  with this flexcop, this is important, because i2c is now using the
+  flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for
+  that, please tell us so).
+
+Everything which is identical in the following table, can be put into a common
+flexcop-module.
+
+                  PCI                  USB
+-------------------------------------------------------------------------------
+Different:
+Register access:  accessing IO memory  USB control message
+I2C bus:          I2C bus of the FC    USB control message
+Data transfer:    DMA                  isochronous transfer
+EEPROM transfer:  through i2c bus      not clear yet
+
+Identical:
+Streaming:                 accessing registers
+PID Filtering:             accessing registers
+Sram destinations:         accessing registers
+Tuner/Demod:                     I2C bus
+DVB-stuff:            can be written for common use
+
+Acknowledgements (just for the rewriting part)
+================
+
+Bjarne Steinsbo thought a lot in the first place of the pci part for this code
+sharing idea.
+
+Andreas Oberritter for providing a recent PCI initialization template
+(pluto2.c).
+
+Boleslaw Ciesielski for pointing out a problem with firmware loader.
+
+Vadim Catana for correcting the USB transfer.
+
+comments, critics and ideas to linux-dvb@linuxtv.org.
index e3cacf4f2345e48258317bc23925e66a757a4a53..d64430bf4bb6ec5d681c2f7c30cc71905a72bd67 100644 (file)
@@ -17,74 +17,53 @@ Because of this, you need to enable
 "Device drivers" => "Multimedia devices"
   => "Video For Linux" => "BT848 Video For Linux"
 
+Furthermore you need to enable
+"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+  => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
+
 2) Loading Modules
 ==================
 
 In general you need to load the bttv driver, which will handle the gpio and
-i2c communication for us. Next you need the common dvb-bt8xx device driver
-and one frontend driver.
-
-The bttv driver will HANG YOUR SYSTEM IF YOU DO NOT SPECIFY THE CORRECT 
-CARD ID!
-
-(If you don't get your card running and you suspect that the card id you're
-using is wrong, have a look at "bttv-cards.c" for a list of possible card
-ids.)
-
-Pay attention to failures when you load the frontend drivers
-(e.g. dmesg, /var/log/messages).
+i2c communication for us, plus the common dvb-bt8xx device driver.
+The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
+TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
 
 3a) Nebula / Pinnacle PCTV
 --------------------------
 
-   $ modprobe bttv i2c_hw=1 card=0x68
-   $ modprobe dvb-bt8xx
-   
-For Nebula cards use the "nxt6000" frontend driver:
-   $ modprobe nxt6000
+   $ modprobe bttv (normally bttv is being loaded automatically by kmod)
+   $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
 
-For Pinnacle PCTV cards use the "cx24110" frontend driver:
-   $ modprobe cx24110
 
-3b) TwinHan
------------
+3b) TwinHan and Clones
+--------------------------
 
    $ modprobe bttv i2c_hw=1 card=0x71
    $ modprobe dvb-bt8xx
    $ modprobe dst
 
-The value 0x71 will override the PCI type detection for dvb-bt8xx, which 
-is necessary for TwinHan cards.#
+The value 0x71 will override the PCI type detection for dvb-bt8xx,
+which  is necessary for TwinHan cards.
 
-If you're having an older card (blue color circuit) and card=0x71 locks your
-machine, try using 0x68, too. If that does not work, ask on the DVB mailing list.
+If you're having an older card (blue color circuit) and card=0x71 locks
+your machine, try using 0x68, too. If that does not work, ask on the
+mailing list.
 
-The DST module takes a couple of useful parameters, in case the
-dst drivers fails to detect your type of card correctly.
+The DST module takes a couple of useful parameters.
 
-dst_type takes values 0 (satellite), 1 (terrestial TV), 2 (cable).
+verbose takes values 0 to 5. These values control the verbosity level.
 
-dst_type_flags takes bit combined values:
-1 = new tuner type packets. You can use this if your card is detected
-    and you have debug and you continually see the tuner packets not
-    working (make sure not a basic problem like dish alignment etc.)
+debug takes values 0 and 1. You can either disable or enable debugging.
 
-2 = TS 204. If your card tunes OK, but the picture is terrible, seemingly
-    breaking up in one half continually, and crc fails a lot, then
-    this is worth a try (or trying to turn off)
+dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
+0x20 means it has a Conditional Access slot.
 
-4 = has symdiv. Some cards, mostly without new tuner packets, require
-    a symbol division algorithm. Doesn't apply to terrestial TV.
-
-You can also specify a value to have the autodetected values turned off
-(e.g. 0). The autodected values are determined bythe cards 'response
+The autodected values are determined bythe cards 'response
 string' which you can see in your logs e.g.
 
-dst_check_ci: recognize DST-MOT
-
-or 
+dst_get_device_id: Recognise [DSTMCI]
 
-dst_check_ci: unable to recognize DSTXCI or STXCI
 
 --
-Authors: Richard Walker, Jamie Honan, Michael Hunold
+Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
diff --git a/Documentation/dvb/ci.txt b/Documentation/dvb/ci.txt
new file mode 100644 (file)
index 0000000..62e0701
--- /dev/null
@@ -0,0 +1,219 @@
+* For the user
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+NOTE: This document describes the usage of the high level CI API as
+in accordance to the Linux DVB API. This is a not a documentation for the,
+existing low level CI API.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To utilize the High Level CI capabilities,
+
+(1*) This point is valid only for the Twinhan/clones
+  For the Twinhan/Twinhan clones, the dst_ca module handles the CI
+  hardware handling.This module is loaded automatically if a CI
+  (Common Interface, that holds the CAM (Conditional Access Module)
+  is detected.
+
+(2) one requires a userspace application, ca_zap. This small userland
+  application is in charge of sending the descrambling related information
+  to the CAM.
+
+This application requires the following to function properly as of now.
+
+       (a) Tune to a valid channel, with szap.
+         eg: $ szap -c channels.conf -r "TMC" -x
+
+       (b) a channels.conf containing a valid PMT PID
+
+         eg: TMC:11996:h:0:27500:278:512:650:321
+
+         here 278 is a valid PMT PID. the rest of the values are the
+         same ones that szap uses.
+
+       (c) after running a szap, you have to run ca_zap, for the
+         descrambler to function,
+
+         eg: $ ca_zap patched_channels.conf "TMC"
+
+         The patched means a patch to apply to scan, such that scan can
+         generate a channels.conf_with pmt, which has this PMT PID info
+         (NOTE: szap cannot use this channels.conf with the PMT_PID)
+
+
+       (d) Hopeflly Enjoy your favourite subscribed channel as you do with
+         a FTA card.
+
+(3) Currently ca_zap, and dst_test, both are meant for demonstration
+  purposes only, they can become full fledged applications if necessary.
+
+
+* Cards that fall in this category
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+At present the cards that fall in this category are the Twinhan and it's
+clones, these cards are available as VVMER, Tomato, Hercules, Orange and
+so on.
+
+* CI modules that are supported
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The CI module support is largely dependant upon the firmware on the cards
+Some cards do support almost all of the available CI modules. There is
+nothing much that can be done in order to make additional CI modules
+working with these cards.
+
+Modules that have been tested by this driver at present are
+
+(1) Irdeto 1 and 2 from SCM
+(2) Viaccess from SCM
+(3) Dragoncam
+
+* The High level CI API
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* For the programmer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+With the High Level CI approach any new card with almost any random
+architecture can be implemented with this style, the definitions
+insidethe switch statement can be easily adapted for any card, thereby
+eliminating the need for any additional ioctls.
+
+The disadvantage is that the driver/hardware has to manage the rest. For
+the application programmer it would be as simple as sending/receiving an
+array to/from the CI ioctls as defined in the Linux DVB API. No changes
+have been made in the API to accomodate this feature.
+
+
+* Why the need for another CI interface ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This is one of the most commonly asked question. Well a nice question.
+Strictly speaking this is not a new interface.
+
+The CI interface is defined in the DVB API in ca.h as
+
+typedef struct ca_slot_info {
+       int num;               /* slot number */
+
+       int type;              /* CA interface this slot supports */
+#define CA_CI            1     /* CI high level interface */
+#define CA_CI_LINK       2     /* CI link layer level interface */
+#define CA_CI_PHYS       4     /* CI physical layer level interface */
+#define CA_DESCR         8     /* built-in descrambler */
+#define CA_SC          128     /* simple smart card interface */
+
+       unsigned int flags;
+#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */
+#define CA_CI_MODULE_READY   2
+} ca_slot_info_t;
+
+
+
+This CI interface follows the CI high level interface, which is not
+implemented by most applications. Hence this area is revisited.
+
+This CI interface is quite different in the case that it tries to
+accomodate all other CI based devices, that fall into the other categories
+
+This means that this CI interface handles the EN50221 style tags in the
+Application layer only and no session management is taken care of by the
+application. The driver/hardware will take care of all that.
+
+This interface is purely an EN50221 interface exchanging APDU's. This
+means that no session management, link layer or a transport layer do
+exist in this case in the application to driver communication. It is
+as simple as that. The driver/hardware has to take care of that.
+
+
+With this High Level CI interface, the interface can be defined with the
+regular ioctls.
+
+All these ioctls are also valid for the High level CI interface
+
+#define CA_RESET          _IO('o', 128)
+#define CA_GET_CAP        _IOR('o', 129, ca_caps_t)
+#define CA_GET_SLOT_INFO  _IOR('o', 130, ca_slot_info_t)
+#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t)
+#define CA_GET_MSG        _IOR('o', 132, ca_msg_t)
+#define CA_SEND_MSG       _IOW('o', 133, ca_msg_t)
+#define CA_SET_DESCR      _IOW('o', 134, ca_descr_t)
+#define CA_SET_PID        _IOW('o', 135, ca_pid_t)
+
+
+On querying the device, the device yields information thus
+
+CA_GET_SLOT_INFO
+----------------------------
+Command = [info]
+APP: Number=[1]
+APP: Type=[1]
+APP: flags=[1]
+APP: CI High level interface
+APP: CA/CI Module Present
+
+CA_GET_CAP
+----------------------------
+Command = [caps]
+APP: Slots=[1]
+APP: Type=[1]
+APP: Descrambler keys=[16]
+APP: Type=[1]
+
+CA_SEND_MSG
+----------------------------
+Descriptors(Program Level)=[ 09 06 06 04 05 50 ff f1]
+Found CA descriptor @ program level
+
+(20) ES type=[2] ES pid=[201]  ES length =[0 (0x0)]
+(25) ES type=[4] ES pid=[301]  ES length =[0 (0x0)]
+ca_message length is 25 (0x19) bytes
+EN50221 CA MSG=[ 9f 80 32 19 03 01 2d d1 f0 08 01 09 06 06 04 05 50 ff f1 02 e0 c9 00 00 04 e1 2d 00 00]
+
+
+Not all ioctl's are implemented in the driver from the API, the other
+features of the hardware that cannot be implemented by the API are achieved
+using the CA_GET_MSG and CA_SEND_MSG ioctls. An EN50221 style wrapper is
+used to exchange the data to maintain compatibility with other hardware.
+
+
+/* a message to/from a CI-CAM */
+typedef struct ca_msg {
+       unsigned int index;
+       unsigned int type;
+       unsigned int length;
+       unsigned char msg[256];
+} ca_msg_t;
+
+
+The flow of data can be described thus,
+
+
+
+
+
+       App (User)
+       -----
+       parse
+         |
+         |
+         v
+       en50221 APDU (package)
+   --------------------------------------
+   |     |                             | High Level CI driver
+   |     |                             |
+   |     v                             |
+   |   en50221 APDU (unpackage)        |
+   |     |                             |
+   |     |                             |
+   |     v                             |
+   |   sanity checks                   |
+   |     |                             |
+   |     |                             |
+   |     v                             |
+   |   do (H/W dep)                    |
+   --------------------------------------
+         |    Hardware
+         |
+         v
+
+
+
+
+The High Level CI interface uses the EN50221 DVB standard, following a
+standard ensures futureproofness.
index 3ffdcb394299f43b65f50c7df3898281504fd32c..a750f0101d9de7d15f47a13e0cc7240b3299ba1f 100644 (file)
@@ -107,7 +107,7 @@ sub tda10045 {
 sub tda10046 {
     my $sourcefile = "tt_budget_217g.zip";
     my $url = "http://www.technotrend.de/new/217g/$sourcefile";
-    my $hash = "a25b579e37109af60f4a36c37893957c";
+    my $hash = "6a7e1e2f2644b162ff0502367553c72d";
     my $outfile = "dvb-fe-tda10046.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
 
@@ -115,7 +115,7 @@ sub tda10046 {
 
     wgetfile($sourcefile, $url);
     unzip($sourcefile, $tmpdir);
-    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24479, "$tmpdir/fwtmp");
+    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24478, "$tmpdir/fwtmp");
     verify("$tmpdir/fwtmp", $hash);
     copy("$tmpdir/fwtmp", $outfile);
 
index d3c52dd24a2ae6f5a39d35d788c8831aa52f4b9c..b9eb209318ab7d737ba7e6be2a0587ce9e8a9d25 100644 (file)
@@ -63,3 +63,23 @@ Why: Outside of Linux, the only implementations of anything even
        people, who might be using implementations that I am not aware
        of, to adjust to this upcoming change.
 Who:   Paul E. McKenney <paulmck@us.ibm.com>
+
+---------------------------
+
+What:  IEEE1394 Audio and Music Data Transmission Protocol driver,
+       Connection Management Procedures driver
+When:  November 2005
+Files: drivers/ieee1394/{amdtp,cmp}*
+Why:   These are incomplete, have never worked, and are better implemented
+       in userland via raw1394 (see http://freebob.sourceforge.net/ for
+       example.)
+Who:   Jody McIntyre <scjody@steamballoon.com>
+
+---------------------------
+
+What:  raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
+When:  November 2005
+Why:   Deprecated in favour of the new ioctl-based rawiso interface, which is
+       more efficient.  You should really be using libraw1394 for raw1394
+       access anyway.
+Who:   Jody McIntyre <scjody@steamballoon.com>
index bddcb861b49bbb90bc5646a7da5c55833f4689b5..1bb028317f2bdc9107da7eb86f7835689b968c7e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -530,7 +530,7 @@ endif
 include $(srctree)/arch/$(ARCH)/Makefile
 
 # arch Makefile may override CC so keep this after arch Makefile is included
-NOSTDINC_FLAGS := -nostdinc -isystem $(shell $(CC) -print-file-name=include)
+NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
 CHECKFLAGS     += $(NOSTDINC_FLAGS)
 
 # warn about C99 declaration after statement
index 64e450dddb49d55c3ddea43bb35371958f52369a..167fd89f8707aeb1b0ad59190e9fa352718d5900 100644 (file)
@@ -1150,16 +1150,13 @@ osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remai
        if (get_tv32(&tmp, sleep))
                goto fault;
 
-       ticks = tmp.tv_usec;
-       ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
-       ticks += tmp.tv_sec * HZ;
+       ticks = timeval_to_jiffies(&tmp);
 
        current->state = TASK_INTERRUPTIBLE;
        ticks = schedule_timeout(ticks);
 
        if (remain) {
-               tmp.tv_sec = ticks / HZ;
-               tmp.tv_usec = ticks % HZ;
+               jiffies_to_timeval(ticks, &tmp);
                if (put_tv32(remain, &tmp))
                        goto fault;
        }
index e23f534d4e1d1696ff7343ad29f1ecad893f9cc1..8d986b8401c2474f3948bb3a4301c26a9784b7f1 100644 (file)
@@ -478,7 +478,7 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
 {
        unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
 
-       s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2;
+       s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate);
 
        printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
               print_mhz(s3c2440_clk_upll.rate));
index 9a8cc5ae225566e5d6d17de94df3fe79dbfe9a2c..d4c8281b55f64a5c3a7a4f2d4fef2c6433215d25 100644 (file)
@@ -192,9 +192,11 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
 
        iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
        iotable_init(mach_desc, size);
+
        /* rename any peripherals used differing from the s3c2410 */
 
-       s3c_device_i2c.name = "s3c2440-i2c";
+       s3c_device_i2c.name  = "s3c2440-i2c";
+       s3c_device_nand.name = "s3c2440-nand";
 
        /* change irq for watchdog */
 
@@ -225,7 +227,7 @@ void __init s3c2440_init_clocks(int xtal)
                break;
 
        case S3C2440_CLKDIVN_HDIVN_2:
-               hdiv = 1;
+               hdiv = 2;
                break;
 
        case S3C2440_CLKDIVN_HDIVN_4_8:
index c4fc6be629deeee971c6635b5130d7e329970a63..48bac7da8c70589dba5f06be40b325457398c640 100644 (file)
@@ -412,21 +412,20 @@ config CPU_BPREDICT_DISABLE
 
 config TLS_REG_EMUL
        bool
-       default y if (SMP || CPU_32v6) && (CPU_32v5 || CPU_32v4 || CPU_32v3)
+       default y if SMP && (CPU_32v5 || CPU_32v4 || CPU_32v3)
        help
-         We might be running on an ARMv6+ processor which should have the TLS
-         register but for some reason we can't use it, or maybe an SMP system
-         using a pre-ARMv6 processor (there are apparently a few prototypes
-         like that in existence) and therefore access to that register must
-         be emulated.
+         An SMP system using a pre-ARMv6 processor (there are apparently
+         a few prototypes like that in existence) and therefore access to
+         that required register must be emulated.
 
 config HAS_TLS_REG
        bool
-       depends on CPU_32v6
-       default y if !TLS_REG_EMUL
+       depends on !TLS_REG_EMUL
+       default y if SMP || CPU_32v7
        help
          This selects support for the CP15 thread register.
-         It is defined to be available on ARMv6 or later.  If a particular
-         ARMv6 or later CPU doesn't support it then it must omc;ide "select
-         TLS_REG_EMUL" along with its other caracteristics.
+         It is defined to be available on some ARMv6 processors (including
+         all SMP capable ARMv6's) or later processors.  User space may
+         assume directly accessing that register and always obtain the
+         expected value only on ARMv7 and above.
 
diff --git a/arch/arm/mm/copypage-v4mc.S b/arch/arm/mm/copypage-v4mc.S
deleted file mode 100644 (file)
index 305af3d..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  linux/arch/arm/lib/copy_page-armv4mc.S
- *
- *  Copyright (C) 1995-2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/constants.h>
-
-       .text
-       .align  5
-/*
- * ARMv4 mini-dcache optimised copy_user_page
- *
- * We flush the destination cache lines just before we write the data into the
- * corresponding address.  Since the Dcache is read-allocate, this removes the
- * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
- * and merged as appropriate.
- *
- * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
- * instruction.  If your processor does not supply this, you have to write your
- * own copy_user_page that does the right thing.
- */
-ENTRY(v4_mc_copy_user_page)
-       stmfd   sp!, {r4, lr}                   @ 2
-       mov     r4, r0
-       mov     r0, r1
-       bl      map_page_minicache
-       mov     r1, #PAGE_SZ/64                 @ 1
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4
-1:     mcr     p15, 0, r4, c7, c6, 1           @ 1   invalidate D line
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4+1
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4
-       mcr     p15, 0, r4, c7, c6, 1           @ 1   invalidate D line
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4
-       subs    r1, r1, #1                      @ 1
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmneia r0!, {r2, r3, ip, lr}           @ 4
-       bne     1b                              @ 1
-       ldmfd   sp!, {r4, pc}                   @ 3
-
-       .align  5
-/*
- * ARMv4 optimised clear_user_page
- *
- * Same story as above.
- */
-ENTRY(v4_mc_clear_user_page)
-       str     lr, [sp, #-4]!
-       mov     r1, #PAGE_SZ/64                 @ 1
-       mov     r2, #0                          @ 1
-       mov     r3, #0                          @ 1
-       mov     ip, #0                          @ 1
-       mov     lr, #0                          @ 1
-1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       subs    r1, r1, #1                      @ 1
-       bne     1b                              @ 1
-       ldr     pc, [sp], #4
-
-       __INITDATA
-
-       .type   v4_mc_user_fns, #object
-ENTRY(v4_mc_user_fns)
-       .long   v4_mc_clear_user_page
-       .long   v4_mc_copy_user_page
-       .size   v4_mc_user_fns, . - v4_mc_user_fns
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
new file mode 100644 (file)
index 0000000..fc69dcc
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  linux/arch/arm/lib/copypage-armv4mc.S
+ *
+ *  Copyright (C) 1995-2005 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This handles the mini data cache, as found on SA11x0 and XScale
+ * processors.  When we copy a user page page, we map it in such a way
+ * that accesses to this page will not touch the main data cache, but
+ * will be cached in the mini data cache.  This prevents us thrashing
+ * the main data cache on page faults.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+/*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently.
+ */
+#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
+                                 L_PTE_CACHEABLE)
+
+#define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
+
+static DEFINE_SPINLOCK(minicache_lock);
+
+/*
+ * ARMv4 mini-dcache optimised copy_user_page
+ *
+ * We flush the destination cache lines just before we write the data into the
+ * corresponding address.  Since the Dcache is read-allocate, this removes the
+ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
+ * and merged as appropriate.
+ *
+ * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
+ * instruction.  If your processor does not supply this, you have to write your
+ * own copy_user_page that does the right thing.
+ */
+static void __attribute__((naked))
+mc_copy_user_page(void *from, void *to)
+{
+       asm volatile(
+       "stmfd  sp!, {r4, lr}                   @ 2\n\
+       mov     r4, %2                          @ 1\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+1:     mcr     p15, 0, %1, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4+1\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       mcr     p15, 0, %1, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       subs    r4, r4, #1                      @ 1\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmneia %0!, {r2, r3, ip, lr}           @ 4\n\
+       bne     1b                              @ 1\n\
+       ldmfd   sp!, {r4, pc}                   @ 3"
+       :
+       : "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
+}
+
+void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+{
+       spin_lock(&minicache_lock);
+
+       set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot));
+       flush_tlb_kernel_page(0xffff8000);
+
+       mc_copy_user_page((void *)0xffff8000, kto);
+
+       spin_unlock(&minicache_lock);
+}
+
+/*
+ * ARMv4 optimised clear_user_page
+ */
+void __attribute__((naked))
+v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
+{
+       asm volatile(
+       "str    lr, [sp, #-4]!\n\
+       mov     r1, %0                          @ 1\n\
+       mov     r2, #0                          @ 1\n\
+       mov     r3, #0                          @ 1\n\
+       mov     ip, #0                          @ 1\n\
+       mov     lr, #0                          @ 1\n\
+1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       subs    r1, r1, #1                      @ 1\n\
+       bne     1b                              @ 1\n\
+       ldr     pc, [sp], #4"
+       :
+       : "I" (PAGE_SIZE / 64));
+}
+
+struct cpu_user_fns v4_mc_user_fns __initdata = {
+       .cpu_clear_user_page    = v4_mc_clear_user_page, 
+       .cpu_copy_user_page     = v4_mc_copy_user_page,
+};
index 694ac8208858a9c54475f8f3173b71cca7787d4e..a8c00236bd3d54283da26f1fe36d3a0cc3d6c636 100644 (file)
@@ -26,8 +26,8 @@
 #define to_address     (0xffffc000)
 #define to_pgprot      PAGE_KERNEL
 
-static pte_t *from_pte;
-static pte_t *to_pte;
+#define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
+
 static DEFINE_SPINLOCK(v6_lock);
 
 #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
@@ -74,8 +74,8 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd
         */
        spin_lock(&v6_lock);
 
-       set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
-       set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
+       set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
+       set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
 
        from = from_address + (offset << PAGE_SHIFT);
        to   = to_address + (offset << PAGE_SHIFT);
@@ -114,7 +114,7 @@ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
         */
        spin_lock(&v6_lock);
 
-       set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
+       set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
        flush_tlb_kernel_page(to);
        clear_page((void *)to);
 
@@ -129,21 +129,6 @@ struct cpu_user_fns v6_user_fns __initdata = {
 static int __init v6_userpage_init(void)
 {
        if (cache_is_vipt_aliasing()) {
-               pgd_t *pgd;
-               pmd_t *pmd;
-
-               pgd = pgd_offset_k(from_address);
-               pmd = pmd_alloc(&init_mm, pgd, from_address);
-               if (!pmd)
-                       BUG();
-               from_pte = pte_alloc_kernel(&init_mm, pmd, from_address);
-               if (!from_pte)
-                       BUG();
-
-               to_pte = pte_alloc_kernel(&init_mm, pmd, to_address);
-               if (!to_pte)
-                       BUG();
-
                cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
                cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
        }
@@ -151,5 +136,4 @@ static int __init v6_userpage_init(void)
        return 0;
 }
 
-__initcall(v6_userpage_init);
-
+core_initcall(v6_userpage_init);
index c6de48d895032de8d615ee0f1ae8d8b31e13a716..4085ed983e46e07c3ac62ba31f8b0e605ee2594c 100644 (file)
 
 #include <asm/cacheflush.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
+
+#ifdef CONFIG_CPU_CACHE_VIPT
+#define ALIAS_FLUSH_START      0xffff4000
+
+#define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
+
+static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
+{
+       unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
+
+       set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL));
+       flush_tlb_kernel_page(to);
+
+       asm(    "mcrr   p15, 0, %1, %0, c14\n"
+       "       mcrr    p15, 0, %1, %0, c5\n"
+           :
+           : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES)
+           : "cc");
+}
+#else
+#define flush_pfn_alias(pfn,vaddr)     do { } while (0)
+#endif
 
 static void __flush_dcache_page(struct address_space *mapping, struct page *page)
 {
@@ -36,6 +59,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
        if (!mapping)
                return;
 
+       /*
+        * This is a page cache page.  If we have a VIPT cache, we
+        * only need to do one flush - which would be at the relevant
+        * userspace colour, which is congruent with page->index.
+        */
+       if (cache_is_vipt()) {
+               if (cache_is_vipt_aliasing())
+                       flush_pfn_alias(page_to_pfn(page),
+                                       page->index << PAGE_CACHE_SHIFT);
+               return;
+       }
+
        /*
         * There are possible user space mappings of this page:
         * - VIVT cache: we need to also write back and invalidate all user
@@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
                        continue;
                offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
                flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page));
-               if (cache_is_vipt())
-                       break;
        }
        flush_dcache_mmap_unlock(mapping);
 }
index 585dfb8e20b96a7526b519d85afe8dc67226c562..2c2b93d77d433248dba64b6a1dd525eae51277fc 100644 (file)
@@ -37,6 +37,8 @@ pgprot_t pgprot_kernel;
 
 EXPORT_SYMBOL(pgprot_kernel);
 
+pmd_t *top_pmd;
+
 struct cachepolicy {
        const char      policy[16];
        unsigned int    cr_mask;
@@ -142,6 +144,16 @@ __setup("noalign", noalign_setup);
 
 #define FIRST_KERNEL_PGD_NR    (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
 
+static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
+{
+       return pmd_offset(pgd, virt);
+}
+
+static inline pmd_t *pmd_off_k(unsigned long virt)
+{
+       return pmd_off(pgd_offset_k(virt), virt);
+}
+
 /*
  * need to get a 16k page for level 1
  */
@@ -220,7 +232,7 @@ void free_pgd_slow(pgd_t *pgd)
                return;
 
        /* pgd is always present and good */
-       pmd = (pmd_t *)pgd;
+       pmd = pmd_off(pgd, 0);
        if (pmd_none(*pmd))
                goto free;
        if (pmd_bad(*pmd)) {
@@ -246,9 +258,8 @@ free:
 static inline void
 alloc_init_section(unsigned long virt, unsigned long phys, int prot)
 {
-       pmd_t *pmdp;
+       pmd_t *pmdp = pmd_off_k(virt);
 
-       pmdp = pmd_offset(pgd_offset_k(virt), virt);
        if (virt & (1 << 20))
                pmdp++;
 
@@ -283,11 +294,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
 static inline void
 alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
 {
-       pmd_t *pmdp;
+       pmd_t *pmdp = pmd_off_k(virt);
        pte_t *ptep;
 
-       pmdp = pmd_offset(pgd_offset_k(virt), virt);
-
        if (pmd_none(*pmdp)) {
                unsigned long pmdval;
                ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
@@ -310,7 +319,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
  */
 static inline void clear_mapping(unsigned long virt)
 {
-       pmd_clear(pmd_offset(pgd_offset_k(virt), virt));
+       pmd_clear(pmd_off_k(virt));
 }
 
 struct mem_types {
@@ -578,7 +587,7 @@ void setup_mm_for_reboot(char mode)
                         PMD_TYPE_SECT;
                if (cpu_arch <= CPU_ARCH_ARMv5)
                        pmdval |= PMD_BIT4;
-               pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
+               pmd = pmd_off(pgd, i << PGDIR_SHIFT);
                pmd[0] = __pmd(pmdval);
                pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
                flush_pmd_entry(pmd);
@@ -675,6 +684,8 @@ void __init memtable_init(struct meminfo *mi)
 
        flush_cache_all();
        flush_tlb_all();
+
+       top_pmd = pmd_off_k(0xffff0000);
 }
 
 /*
index 16dbc4151be43b8e671869b2a52220f47ec0b6ac..fa34a06c0d792cc6fc8cc6314f2c2cbf3f3368b8 100644 (file)
@@ -24,9 +24,6 @@ __asm__(".align 4\nvide: ret");
 
 static void __init init_amd(struct cpuinfo_x86 *c)
 {
-#ifdef CONFIG_X86_SMP
-       int cpu = c == &boot_cpu_data ? 0 : c - cpu_data;
-#endif
        u32 l, h;
        int mbytes = num_physpages >> (20-PAGE_SHIFT);
        int r;
@@ -205,7 +202,9 @@ static void __init init_amd(struct cpuinfo_x86 *c)
         * of two.
         */
        if (c->x86_num_cores > 1) {
-               cpu_core_id[cpu] = cpu >> hweight32(c->x86_num_cores - 1);
+               int cpu = smp_processor_id();
+               /* Fix up the APIC ID following AMD specifications. */
+               cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1);
                printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
                       cpu, c->x86_num_cores, cpu_core_id[cpu]);
        }
index 6be0310e3cd3a15fc70bcf4782228cf73d7e161a..11e6e6f23fa01636331c4fff676e10d13976a709 100644 (file)
@@ -243,6 +243,13 @@ static void __init early_cpu_detect(void)
        }
 
        early_intel_workaround(c);
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
+       phys_proc_id[smp_processor_id()] =
+#endif
+       cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+#endif
 }
 
 void __init generic_identify(struct cpuinfo_x86 * c)
index 9845dabe2613ae91bf456607b59d48400fe5689d..164b211f417474db5e566c4bab14024b10a3077c 100644 (file)
@@ -13,7 +13,6 @@
   
 #define        INCLUDES
 #include "compat_ioctl.c"
-#include <asm/ioctl32.h>
 
 #define IOCTL_NR(a)    ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
 
index c5f1043de9384c2f495705d0ff9c43fd670b8066..53166f3598b25fdd82cde85c1963fefa0e22c742 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  pmu.c, Power Management Unit routines for NEC VR4100 series.
  *
- *  Copyright (C) 2003-2004  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
  *
  *  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
@@ -17,7 +17,9 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/types.h>
 #include <asm/reboot.h>
 #include <asm/system.h>
 
-#define PMUCNT2REG     KSEG1ADDR(0x0f0000c6)
+#define PMU_TYPE1_BASE 0x0b0000a0UL
+#define PMU_TYPE1_SIZE 0x0eUL
+
+#define PMU_TYPE2_BASE 0x0f0000c0UL
+#define PMU_TYPE2_SIZE 0x10UL
+
+#define PMUCNT2REG     0x06
  #define SOFTRST       0x0010
 
+static void __iomem *pmu_base;
+
+#define pmu_read(offset)               readw(pmu_base + (offset))
+#define pmu_write(offset, value)       writew((value), pmu_base + (offset))
+
 static inline void software_reset(void)
 {
-       uint16_t val;
+       uint16_t pmucnt2;
 
        switch (current_cpu_data.cputype) {
        case CPU_VR4122:
        case CPU_VR4131:
        case CPU_VR4133:
-               val = readw(PMUCNT2REG);
-               val |= SOFTRST;
-               writew(val, PMUCNT2REG);
+               pmucnt2 = pmu_read(PMUCNT2REG);
+               pmucnt2 |= SOFTRST;
+               pmu_write(PMUCNT2REG, pmucnt2);
                break;
        default:
                break;
@@ -71,6 +84,34 @@ static void vr41xx_power_off(void)
 
 static int __init vr41xx_pmu_init(void)
 {
+       unsigned long start, size;
+
+       switch (current_cpu_data.cputype) {
+       case CPU_VR4111:
+       case CPU_VR4121:
+               start = PMU_TYPE1_BASE;
+               size = PMU_TYPE1_SIZE;
+               break;
+       case CPU_VR4122:
+       case CPU_VR4131:
+       case CPU_VR4133:
+               start = PMU_TYPE2_BASE;
+               size = PMU_TYPE2_SIZE;
+               break;
+       default:
+               printk("Unexpected CPU of NEC VR4100 series\n");
+               return -ENODEV;
+       }
+
+       if (request_mem_region(start, size, "PMU") == NULL)
+               return -EBUSY;
+
+       pmu_base = ioremap(start, size);
+       if (pmu_base == NULL) {
+               release_mem_region(start, size);
+               return -EBUSY;
+       }
+
        _machine_restart = vr41xx_restart;
        _machine_halt = vr41xx_halt;
        _machine_power_off = vr41xx_power_off;
@@ -78,4 +119,4 @@ static int __init vr41xx_pmu_init(void)
        return 0;
 }
 
-early_initcall(vr41xx_pmu_init);
+core_initcall(vr41xx_pmu_init);
index 6d6f9484b884d357240beaf65266c0d376644e55..b3074cbaa479ac3de6c42242006d8e5c1f33cb42 100644 (file)
@@ -236,9 +236,15 @@ static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
                                       (*prev)->fd, pollfds[i].fd);
                                goto out;
                        }
-                       memcpy(&pollfds[i], &pollfds[i + 1],
-                              (pollfds_num - i - 1) * sizeof(pollfds[0]));
+
                        pollfds_num--;
+
+                       /* This moves the *whole* array after pollfds[i] (though
+                        * it doesn't spot as such)! */
+
+                       memmove(&pollfds[i], &pollfds[i + 1],
+                              (pollfds_num - i) * sizeof(pollfds[0]));
+
                        if(last_irq_ptr == &old_fd->next) 
                                last_irq_ptr = prev;
                        *prev = (*prev)->next;
index 44ee7f6acf7b521ac9e291eb949e0257ecb5d7fd..82cb2a3f127ad84e5c7fea33abceb69a78f0e532 100644 (file)
@@ -303,6 +303,20 @@ config HPET_TIMER
          as it is off-chip.  You can find the HPET spec at
          <http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>.
 
+config X86_PM_TIMER
+       bool "PM timer"
+       default y
+       help
+         Support the ACPI PM timer for time keeping. This is slow,
+         but is useful on some chipsets without HPET on systems with more
+         than one CPU. On a single processor or single socket multi core
+         system it is normally not required.
+         When the PM timer is active 64bit vsyscalls are disabled
+         and should not be enabled (/proc/sys/kernel/vsyscall64 should
+         not be changed).
+         The kernel selects the PM timer only as a last resort, so it is
+         useful to enable just in case.
+
 config HPET_EMULATE_RTC
        bool "Provide RTC interrupt"
        depends on HPET_TIMER && RTC=y
index 9ce51dee30b301972d6d5a8b160b8bef74d17049..569595b74c7ccfc5412053959f5cd68891122848 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-bk7
-# Sat Mar 12 23:43:44 2005
+# Linux kernel version: 2.6.12-rc4
+# Fri May 13 06:39:11 2005
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
@@ -11,8 +11,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_X86_CMPXCHG=y
 CONFIG_EARLY_PRINTK=y
-CONFIG_HPET_TIMER=y
-CONFIG_HPET_EMULATE_RTC=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_GENERIC_IOMAP=y
 
@@ -22,6 +20,7 @@ CONFIG_GENERIC_IOMAP=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -33,7 +32,6 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=18
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
@@ -43,10 +41,11 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
@@ -93,6 +92,9 @@ CONFIG_DISCONTIGMEM=y
 CONFIG_NUMA=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_NR_CPUS=8
+CONFIG_HPET_TIMER=y
+CONFIG_X86_PM_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
 CONFIG_GART_IOMMU=y
 CONFIG_SWIOTLB=y
 CONFIG_X86_MCE=y
@@ -100,6 +102,7 @@ CONFIG_X86_MCE_INTEL=y
 CONFIG_SECCOMP=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ISA_DMA_API=y
 
 #
 # Power management options
@@ -129,7 +132,7 @@ CONFIG_ACPI_NUMA=y
 # CONFIG_ACPI_IBM is not set
 CONFIG_ACPI_TOSHIBA=y
 CONFIG_ACPI_BLACKLIST_YEAR=2001
-CONFIG_ACPI_DEBUG=y
+# CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_BUS=y
 CONFIG_ACPI_EC=y
 CONFIG_ACPI_POWER=y
@@ -141,6 +144,7 @@ CONFIG_ACPI_SYSTEM=y
 # CPU Frequency scaling
 #
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
 # CONFIG_CPU_FREQ_DEBUG is not set
 CONFIG_CPU_FREQ_STAT=y
 # CONFIG_CPU_FREQ_STAT_DETAILS is not set
@@ -150,7 +154,6 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_TABLE=y
 
 #
 # CPUFreq processor drivers
@@ -164,6 +167,7 @@ CONFIG_X86_ACPI_CPUFREQ=y
 # shared options
 #
 CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y
+# CONFIG_X86_SPEEDSTEP_LIB is not set
 
 #
 # Bus options (PCI etc.)
@@ -172,19 +176,17 @@ CONFIG_PCI=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
 CONFIG_UNORDERED_IO=y
+# CONFIG_PCIEPORTBUS is not set
 CONFIG_PCI_MSI=y
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
 
-#
-# PC-card bridges
-#
-
 #
 # PCI Hotplug Support
 #
@@ -254,7 +256,7 @@ CONFIG_LBD=y
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_AS is not set
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
@@ -308,7 +310,8 @@ CONFIG_BLK_DEV_AMD74XX=y
 CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+# CONFIG_PDC202XX_FORCE is not set
 # CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
@@ -353,7 +356,7 @@ CONFIG_BLK_DEV_SD=y
 #
 # SCSI low-level drivers
 #
-CONFIG_BLK_DEV_3W_XXXX_RAID=y
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AACRAID is not set
@@ -384,7 +387,6 @@ CONFIG_SCSI_SATA_VIA=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
@@ -392,7 +394,6 @@ CONFIG_SCSI_SATA_VIA=y
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=y
@@ -401,6 +402,7 @@ CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -437,7 +439,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -502,7 +503,7 @@ CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=y
 
 #
 # ARCnet devices
@@ -525,8 +526,7 @@ CONFIG_MII=y
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
-CONFIG_AMD8111_ETH=y
-# CONFIG_AMD8111E_NAPI is not set
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
 CONFIG_FORCEDETH=y
@@ -536,7 +536,7 @@ CONFIG_FORCEDETH=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
-CONFIG_8139CP=m
+CONFIG_8139CP=y
 CONFIG_8139TOO=y
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
@@ -671,6 +671,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -696,6 +697,7 @@ CONFIG_RTC=y
 #
 CONFIG_AGP=y
 CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
 # CONFIG_DRM is not set
 # CONFIG_MWAVE is not set
 CONFIG_RAW_DRIVER=y
@@ -703,7 +705,7 @@ CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 CONFIG_MAX_RAW_DEVS=256
-CONFIG_HANGCHECK_TIMER=y
+# CONFIG_HANGCHECK_TIMER is not set
 
 #
 # TPM devices
@@ -786,6 +788,8 @@ CONFIG_SOUND_ICH=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -797,8 +801,6 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
 # USB Host Controller Drivers
@@ -826,7 +828,6 @@ CONFIG_USB_PRINTER=y
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_RW_DETECT is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
@@ -965,7 +966,7 @@ CONFIG_AUTOFS_FS=y
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
 # CONFIG_UDF_FS is not set
 
@@ -1092,9 +1093,10 @@ CONFIG_OPROFILE=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_PRINTK_TIME is not set
+CONFIG_LOG_BUF_SHIFT=18
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
index 0a3318e08ab6f123e5a015f4c9cd2198c932b821..5ca4a4598fdad807b5aa0e8143c2aa55525fced2 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_GART_IOMMU)      += pci-gart.o aperture.o
 obj-$(CONFIG_DUMMY_IOMMU)      += pci-nommu.o pci-dma.o
 obj-$(CONFIG_SWIOTLB)          += swiotlb.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
+obj-$(CONFIG_X86_PM_TIMER)     += pmtimer.o
 
 obj-$(CONFIG_MODULES)          += module.o
 
index 7e13545748e0ef3378c87a23c401ba25f34d6c65..f8e6cc4fecd4887acc244fee292f401a96aac59b 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
 #include <asm/mach_apic.h>
+#include <asm/nmi.h>
 
 int apic_verbosity;
 
@@ -925,7 +926,7 @@ __init int oem_force_hpet_timer(void)
        unsigned id;
        DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS);
 
-       bitmap_empty(clustermap, NUM_APIC_CLUSTERS);
+       bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
 
        for (i = 0; i < NR_CPUS; i++) {
                id = bios_cpu_apicid[i];
@@ -1056,7 +1057,7 @@ int __init APIC_init_uniprocessor (void)
                nr_ioapics = 0;
 #endif
        setup_boot_APIC_clock();
-
+       check_nmi_watchdog();
        return 0;
 }
 
index 1086b5fcac21c51ad8acb01a02c6c8a6a971a8c7..28817490fdc69510a527c9974be8bb550aa2a5b6 100644 (file)
@@ -220,13 +220,18 @@ sysret_careful:
        jmp sysret_check
 
        /* Handle a signal */ 
-       /* edx: work flags (arg3) */
 sysret_signal:
        sti
+       testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+       jz    1f
+
+       /* Really a signal */
+       /* edx: work flags (arg3) */
        leaq do_notify_resume(%rip),%rax
        leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
        xorl %esi,%esi # oldset -> arg2
        call ptregscall_common
+1:     movl $_TIF_NEED_RESCHED,%edi
        jmp sysret_check
        
        /* Do syscall tracing */
@@ -484,6 +489,8 @@ retint_careful:
        jmp retint_check
        
 retint_signal:
+       testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+       jz    retint_swapgs
        sti
        SAVE_REST
        movq $-1,ORIG_RAX(%rsp)                         
@@ -492,8 +499,8 @@ retint_signal:
        call do_notify_resume
        RESTORE_REST
        cli
+       movl $_TIF_NEED_RESCHED,%edi
        GET_THREAD_INFO(%rcx)
-       movl $_TIF_WORK_MASK,%edi
        jmp retint_check
 
 #ifdef CONFIG_PREEMPT
index 60be58617eb977e1620beda8e363ba9cfd9fc17c..ac7684324954ad77524852b77922d604e57a0cb0 100644 (file)
@@ -1804,76 +1804,6 @@ device_initcall(ioapic_init_sysfs);
 
 #define IO_APIC_MAX_ID         0xFE
 
-int __init io_apic_get_unique_id (int ioapic, int apic_id)
-{
-       union IO_APIC_reg_00 reg_00;
-       static physid_mask_t apic_id_map;
-       unsigned long flags;
-       int i = 0;
-
-       /*
-        * The P4 platform supports up to 256 APIC IDs on two separate APIC 
-        * buses (one for LAPICs, one for IOAPICs), where predecessors only 
-        * supports up to 16 on one shared APIC bus.
-        * 
-        * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
-        *      advantage of new APIC bus architecture.
-        */
-
-       if (physids_empty(apic_id_map))
-               apic_id_map = phys_cpu_present_map;
-
-       spin_lock_irqsave(&ioapic_lock, flags);
-       reg_00.raw = io_apic_read(ioapic, 0);
-       spin_unlock_irqrestore(&ioapic_lock, flags);
-
-       if (apic_id >= IO_APIC_MAX_ID) {
-               apic_printk(APIC_QUIET, KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
-                       "%d\n", ioapic, apic_id, reg_00.bits.ID);
-               apic_id = reg_00.bits.ID;
-       }
-
-       /*
-        * Every APIC in a system must have a unique ID or we get lots of nice 
-        * 'stuck on smp_invalidate_needed IPI wait' messages.
-        */
-       if (physid_isset(apic_id, apic_id_map)) {
-
-               for (i = 0; i < IO_APIC_MAX_ID; i++) {
-                       if (!physid_isset(i, apic_id_map))
-                               break;
-               }
-
-               if (i == IO_APIC_MAX_ID)
-                       panic("Max apic_id exceeded!\n");
-
-               apic_printk(APIC_VERBOSE, KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
-                       "trying %d\n", ioapic, apic_id, i);
-
-               apic_id = i;
-       } 
-
-       physid_set(apic_id, apic_id_map);
-
-       if (reg_00.bits.ID != apic_id) {
-               reg_00.bits.ID = apic_id;
-
-               spin_lock_irqsave(&ioapic_lock, flags);
-               io_apic_write(ioapic, 0, reg_00.raw);
-               reg_00.raw = io_apic_read(ioapic, 0);
-               spin_unlock_irqrestore(&ioapic_lock, flags);
-
-               /* Sanity check */
-               if (reg_00.bits.ID != apic_id)
-                       panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic);
-       }
-
-       apic_printk(APIC_VERBOSE,KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
-
-       return apic_id;
-}
-
-
 int __init io_apic_get_version (int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
index 7ec031c6ca10fe566e444fcafcb3b1b4995887b9..f86d9db94bfcc437b378fc32024d603c449cfdf1 100644 (file)
@@ -107,6 +107,7 @@ static int __init mpf_checksum(unsigned char *mp, int len)
 static void __init MP_processor_info (struct mpc_config_processor *m)
 {
        int ver;
+       static int found_bsp=0;
 
        if (!(m->mpc_cpuflag & CPU_ENABLED))
                return;
@@ -126,11 +127,6 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
                        " Processor ignored.\n", NR_CPUS);
                return;
        }
-       if (num_processors >= maxcpus) {
-               printk(KERN_WARNING "WARNING: maxcpus limit of %i reached."
-                       " Processor ignored.\n", maxcpus);
-               return;
-       }
 
        num_processors++;
 
@@ -150,7 +146,19 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
                ver = 0x10;
        }
        apic_version[m->mpc_apicid] = ver;
-       bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
+       if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+               /*
+                * bios_cpu_apicid is required to have processors listed
+                * in same order as logical cpu numbers. Hence the first
+                * entry is BSP, and so on.
+                */
+               bios_cpu_apicid[0] = m->mpc_apicid;
+               x86_cpu_to_apicid[0] = m->mpc_apicid;
+               found_bsp = 1;
+       } else {
+               bios_cpu_apicid[num_processors - found_bsp] = m->mpc_apicid;
+               x86_cpu_to_apicid[num_processors - found_bsp] = m->mpc_apicid;
+       }
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -759,7 +767,7 @@ void __init mp_register_ioapic (
        mp_ioapics[idx].mpc_apicaddr = address;
 
        set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
-       mp_ioapics[idx].mpc_apicid = io_apic_get_unique_id(idx, id);
+       mp_ioapics[idx].mpc_apicid = id;
        mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
        
        /* 
index 61de0b34a01e850fedb824115b2e0560ed98ff59..31c0f2e6ac916c8f1cd93f025cf3182b92f1fa3e 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/msr.h>
 #include <asm/proto.h>
 #include <asm/kdebug.h>
+#include <asm/local.h>
 
 /*
  * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
@@ -59,7 +60,8 @@ int panic_on_timeout;
 
 unsigned int nmi_watchdog = NMI_DEFAULT;
 static unsigned int nmi_hz = HZ;
-unsigned int nmi_perfctr_msr;  /* the MSR to reset in NMI handler */
+static unsigned int nmi_perfctr_msr;   /* the MSR to reset in NMI handler */
+static unsigned int nmi_p4_cccr_val;
 
 /* Note that these events don't tick when the CPU idles. This means
    the frequency varies with CPU load. */
@@ -71,61 +73,87 @@ unsigned int nmi_perfctr_msr;       /* the MSR to reset in NMI handler */
 #define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING   0x76
 #define K7_NMI_EVENT           K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
 
-#define P6_EVNTSEL0_ENABLE     (1 << 22)
-#define P6_EVNTSEL_INT         (1 << 20)
-#define P6_EVNTSEL_OS          (1 << 17)
-#define P6_EVNTSEL_USR         (1 << 16)
-#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
-#define P6_NMI_EVENT           P6_EVENT_CPU_CLOCKS_NOT_HALTED
+#define MSR_P4_MISC_ENABLE     0x1A0
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL  (1<<7)
+#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL        (1<<12)
+#define MSR_P4_PERFCTR0                0x300
+#define MSR_P4_CCCR0           0x360
+#define P4_ESCR_EVENT_SELECT(N)        ((N)<<25)
+#define P4_ESCR_OS             (1<<3)
+#define P4_ESCR_USR            (1<<2)
+#define P4_CCCR_OVF_PMI0       (1<<26)
+#define P4_CCCR_OVF_PMI1       (1<<27)
+#define P4_CCCR_THRESHOLD(N)   ((N)<<20)
+#define P4_CCCR_COMPLEMENT     (1<<19)
+#define P4_CCCR_COMPARE                (1<<18)
+#define P4_CCCR_REQUIRED       (3<<16)
+#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
+#define P4_CCCR_ENABLE         (1<<12)
+/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+   CRU_ESCR0 (with any non-null event selector) through a complemented
+   max threshold. [IA32-Vol3, Section 14.9.9] */
+#define MSR_P4_IQ_COUNTER0     0x30C
+#define P4_NMI_CRU_ESCR0       (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+#define P4_NMI_IQ_CCCR0        \
+       (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|     \
+        P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
+
+static __init inline int nmi_known_cpu(void)
+{
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+               return boot_cpu_data.x86 == 15;
+       case X86_VENDOR_INTEL:
+               return boot_cpu_data.x86 == 15;
+       }
+       return 0;
+}
 
 /* Run after command line and cpu_init init, but before all other checks */
 void __init nmi_watchdog_default(void)
 {
        if (nmi_watchdog != NMI_DEFAULT)
                return;
-
-       /* For some reason the IO APIC watchdog doesn't work on the AMD
-          8111 chipset. For now switch to local APIC mode using
-          perfctr0 there.  On Intel CPUs we don't have code to handle
-          the perfctr and the IO-APIC seems to work, so use that.  */
-
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
-               nmi_watchdog = NMI_LOCAL_APIC; 
-               printk(KERN_INFO 
-              "Using local APIC NMI watchdog using perfctr0\n");
-       } else {
-               printk(KERN_INFO "Using IO APIC NMI watchdog\n");
+       if (nmi_known_cpu())
+               nmi_watchdog = NMI_LOCAL_APIC;
+       else
                nmi_watchdog = NMI_IO_APIC;
-       }
 }
 
-/* Why is there no CPUID flag for this? */
-static __init int cpu_has_lapic(void)
+#ifdef CONFIG_SMP
+/* The performance counters used by NMI_LOCAL_APIC don't trigger when
+ * the CPU is idle. To make sure the NMI watchdog really ticks on all
+ * CPUs during the test make them busy.
+ */
+static __init void nmi_cpu_busy(void *data)
 {
-       switch (boot_cpu_data.x86_vendor) { 
-       case X86_VENDOR_INTEL:
-       case X86_VENDOR_AMD: 
-               return boot_cpu_data.x86 >= 6; 
-       /* .... add more cpus here or find a different way to figure this out. */       
-       default:
-               return 0;
-       }       
+       volatile int *endflag = data;
+       local_irq_enable();
+       /* Intentionally don't use cpu_relax here. This is
+          to make sure that the performance counter really ticks,
+          even if there is a simulator or similar that catches the
+          pause instruction. On a real HT machine this is fine because
+          all other CPUs are busy with "useless" delay loops and don't
+          care if they get somewhat less cycles. */
+       while (*endflag == 0)
+               barrier();
 }
+#endif
 
-static int __init check_nmi_watchdog (void)
+int __init check_nmi_watchdog (void)
 {
-       int counts[NR_CPUS];
+       volatile int endflag = 0;
+       int *counts;
        int cpu;
 
-       if (nmi_watchdog == NMI_NONE)
-               return 0;
+       counts = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
+       if (!counts)
+               return -1;
 
-       if (nmi_watchdog == NMI_LOCAL_APIC && !cpu_has_lapic())  {
-               nmi_watchdog = NMI_NONE;
-               return -1; 
-       }       
+       printk(KERN_INFO "testing NMI watchdog ... ");
 
-       printk(KERN_INFO "Testing NMI watchdog ... ");
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
 
        for (cpu = 0; cpu < NR_CPUS; cpu++)
                counts[cpu] = cpu_pda[cpu].__nmi_count; 
@@ -133,15 +161,22 @@ static int __init check_nmi_watchdog (void)
        mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
        for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               if (!cpu_online(cpu))
+                       continue;
                if (cpu_pda[cpu].__nmi_count - counts[cpu] <= 5) {
-                       printk("CPU#%d: NMI appears to be stuck (%d)!\n", 
+                       endflag = 1;
+                       printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
                               cpu,
+                              counts[cpu],
                               cpu_pda[cpu].__nmi_count);
                        nmi_active = 0;
                        lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG;
+                       nmi_perfctr_msr = 0;
+                       kfree(counts);
                        return -1;
                }
        }
+       endflag = 1;
        printk("OK.\n");
 
        /* now that we know it works we can reduce NMI frequency to
@@ -149,10 +184,9 @@ static int __init check_nmi_watchdog (void)
        if (nmi_watchdog == NMI_LOCAL_APIC)
                nmi_hz = 1;
 
+       kfree(counts);
        return 0;
 }
-/* Have this called later during boot so counters are updating */
-late_initcall(check_nmi_watchdog);
 
 int __init setup_nmi_watchdog(char *str)
 {
@@ -170,7 +204,7 @@ int __init setup_nmi_watchdog(char *str)
 
        if (nmi >= NMI_INVALID)
                return 0;
-               nmi_watchdog = nmi;
+       nmi_watchdog = nmi;
        return 1;
 }
 
@@ -185,7 +219,10 @@ static void disable_lapic_nmi_watchdog(void)
                wrmsr(MSR_K7_EVNTSEL0, 0, 0);
                break;
        case X86_VENDOR_INTEL:
-               wrmsr(MSR_IA32_EVNTSEL0, 0, 0);
+               if (boot_cpu_data.x86 == 15) {
+                       wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+                       wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+               }
                break;
        }
        nmi_active = -1;
@@ -253,7 +290,7 @@ void enable_timer_nmi_watchdog(void)
 
 static int nmi_pm_active; /* nmi_active before suspend */
 
-static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
+static int lapic_nmi_suspend(struct sys_device *dev, u32 state)
 {
        nmi_pm_active = nmi_active;
        disable_lapic_nmi_watchdog();
@@ -300,22 +337,27 @@ late_initcall(init_lapic_nmi_sysfs);
  * Original code written by Keith Owens.
  */
 
+static void clear_msr_range(unsigned int base, unsigned int n)
+{
+       unsigned int i;
+
+       for(i = 0; i < n; ++i)
+               wrmsr(base+i, 0, 0);
+}
+
 static void setup_k7_watchdog(void)
 {
        int i;
        unsigned int evntsel;
 
-       /* No check, so can start with slow frequency */
-       nmi_hz = 1; 
-
-       /* XXX should check these in EFER */
-
        nmi_perfctr_msr = MSR_K7_PERFCTR0;
 
        for(i = 0; i < 4; ++i) {
                /* Simulator may not support it */
-               if (checking_wrmsrl(MSR_K7_EVNTSEL0+i, 0UL))
+               if (checking_wrmsrl(MSR_K7_EVNTSEL0+i, 0UL)) {
+                       nmi_perfctr_msr = 0;
                        return;
+               }
                wrmsrl(MSR_K7_PERFCTR0+i, 0UL);
        }
 
@@ -325,12 +367,54 @@ static void setup_k7_watchdog(void)
                | K7_NMI_EVENT;
 
        wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
-       wrmsrl(MSR_K7_PERFCTR0, -((u64)cpu_khz*1000) / nmi_hz);
+       wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
        apic_write(APIC_LVTPC, APIC_DM_NMI);
        evntsel |= K7_EVNTSEL_ENABLE;
        wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
 }
 
+
+static int setup_p4_watchdog(void)
+{
+       unsigned int misc_enable, dummy;
+
+       rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
+       if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+               return 0;
+
+       nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+       nmi_p4_cccr_val = P4_NMI_IQ_CCCR0;
+#ifdef CONFIG_SMP
+       if (smp_num_siblings == 2)
+               nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1;
+#endif
+
+       if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+               clear_msr_range(0x3F1, 2);
+       /* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+          docs doesn't fully define it, so leave it alone for now. */
+       if (boot_cpu_data.x86_model >= 0x3) {
+               /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */
+               clear_msr_range(0x3A0, 26);
+               clear_msr_range(0x3BC, 3);
+       } else {
+               clear_msr_range(0x3A0, 31);
+       }
+       clear_msr_range(0x3C0, 6);
+       clear_msr_range(0x3C8, 6);
+       clear_msr_range(0x3E0, 2);
+       clear_msr_range(MSR_P4_CCCR0, 18);
+       clear_msr_range(MSR_P4_PERFCTR0, 18);
+
+       wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
+       wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
+       Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
+       wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
+       apic_write(APIC_LVTPC, APIC_DM_NMI);
+       wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
+       return 1;
+}
+
 void setup_apic_nmi_watchdog(void)
 {
        switch (boot_cpu_data.x86_vendor) {
@@ -341,6 +425,13 @@ void setup_apic_nmi_watchdog(void)
                        return;
                setup_k7_watchdog();
                break;
+       case X86_VENDOR_INTEL:
+               if (boot_cpu_data.x86 != 15)
+                       return;
+               if (!setup_p4_watchdog())
+                       return;
+               break;
+
        default:
                return;
        }
@@ -355,56 +446,67 @@ void setup_apic_nmi_watchdog(void)
  *
  * as these watchdog NMI IRQs are generated on every CPU, we only
  * have to check the current processor.
- *
- * since NMIs don't listen to _any_ locks, we have to be extremely
- * careful not to rely on unsafe variables. The printk might lock
- * up though, so we have to break up any console locks first ...
- * [when there will be more tty-related locks, break them up
- *  here too!]
  */
 
-static unsigned int
-       last_irq_sums [NR_CPUS],
-       alert_counter [NR_CPUS];
+static DEFINE_PER_CPU(unsigned, last_irq_sum);
+static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(int, nmi_touch);
 
 void touch_nmi_watchdog (void)
 {
        int i;
 
        /*
-        * Just reset the alert counters, (other CPUs might be
-        * spinning on locks we hold):
+        * Tell other CPUs to reset their alert counters. We cannot
+        * do it ourselves because the alert count increase is not
+        * atomic.
         */
        for (i = 0; i < NR_CPUS; i++)
-               alert_counter[i] = 0;
+               per_cpu(nmi_touch, i) = 1;
 }
 
 void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
 {
-       int sum, cpu;
+       int sum;
+       int touched = 0;
 
-       cpu = safe_smp_processor_id();
        sum = read_pda(apic_timer_irqs);
-       if (last_irq_sums[cpu] == sum) {
+       if (__get_cpu_var(nmi_touch)) {
+               __get_cpu_var(nmi_touch) = 0;
+               touched = 1;
+       }
+       if (!touched && __get_cpu_var(last_irq_sum) == sum) {
                /*
                 * Ayiee, looks like this CPU is stuck ...
                 * wait a few IRQs (5 seconds) before doing the oops ...
                 */
-               alert_counter[cpu]++;
-               if (alert_counter[cpu] == 5*nmi_hz) {
+               local_inc(&__get_cpu_var(alert_counter));
+               if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz) {
                        if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
                                                        == NOTIFY_STOP) {
-                               alert_counter[cpu] = 0; 
+                               local_set(&__get_cpu_var(alert_counter), 0);
                                return;
                        } 
                        die_nmi("NMI Watchdog detected LOCKUP on CPU%d", regs);
                }
        } else {
-               last_irq_sums[cpu] = sum;
-               alert_counter[cpu] = 0;
+               __get_cpu_var(last_irq_sum) = sum;
+               local_set(&__get_cpu_var(alert_counter), 0);
        }
-       if (nmi_perfctr_msr)
+       if (nmi_perfctr_msr) {
+               if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
+                       /*
+                        * P4 quirks:
+                        * - An overflown perfctr will assert its interrupt
+                        *   until the OVF flag in its CCCR is cleared.
+                        * - LVTPC is masked on interrupt and must be
+                        *   unmasked by the LVTPC handler.
+                        */
+                       wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
+                       apic_write(APIC_LVTPC, APIC_DM_NMI);
+               }
                wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+       }
 }
 
 static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c
new file mode 100644 (file)
index 0000000..feb5f10
--- /dev/null
@@ -0,0 +1,101 @@
+/* Ported over from i386 by AK, original copyright was:
+ *
+ * (C) Dominik Brodowski <linux@brodo.de> 2003
+ *
+ * Driver to use the Power Management Timer (PMTMR) available in some
+ * southbridges as primary timing source for the Linux kernel.
+ *
+ * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
+ * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
+ *
+ * This file is licensed under the GPL v2.
+ *
+ * Dropped all the hardware bug workarounds for now. Hopefully they
+ * are not needed on 64bit chipsets.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <asm/io.h>
+#include <asm/proto.h>
+#include <asm/msr.h>
+#include <asm/vsyscall.h>
+
+/* The I/O port the PMTMR resides at.
+ * The location is detected during setup_arch(),
+ * in arch/i386/kernel/acpi/boot.c */
+u32 pmtmr_ioport;
+
+/* value of the Power timer at last timer interrupt */
+static u32 offset_delay;
+static u32 last_pmtmr_tick;
+
+#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
+
+static inline u32 cyc2us(u32 cycles)
+{
+       /* The Power Management Timer ticks at 3.579545 ticks per microsecond.
+        * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
+        *
+        * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
+        * easily be multiplied with 286 (=0x11E) without having to fear
+        * u32 overflows.
+        */
+       cycles *= 286;
+       return (cycles >> 10);
+}
+
+int pmtimer_mark_offset(void)
+{
+       static int first_run = 1;
+       unsigned long tsc;
+       u32 lost;
+
+       u32 tick = inl(pmtmr_ioport);
+       u32 delta;
+
+       delta = cyc2us((tick - last_pmtmr_tick) & ACPI_PM_MASK);
+
+       last_pmtmr_tick = tick;
+       monotonic_base += delta * NSEC_PER_USEC;
+
+       delta += offset_delay;
+
+       lost = delta / (USEC_PER_SEC / HZ);
+       offset_delay = delta % (USEC_PER_SEC / HZ);
+
+       rdtscll(tsc);
+       vxtime.last_tsc = tsc - offset_delay * cpu_khz;
+
+       /* don't calculate delay for first run,
+          or if we've got less then a tick */
+       if (first_run || (lost < 1)) {
+               first_run = 0;
+               offset_delay = 0;
+       }
+
+       return lost - 1;
+}
+
+unsigned int do_gettimeoffset_pm(void)
+{
+       u32 now, offset, delta = 0;
+
+       offset = last_pmtmr_tick;
+       now = inl(pmtmr_ioport);
+       delta = (now - offset) & ACPI_PM_MASK;
+
+       return offset_delay + cyc2us(delta);
+}
+
+
+static int __init nopmtimer_setup(char *s)
+{
+       pmtmr_ioport = 0;
+       return 0;
+}
+
+__setup("nopmtimer", nopmtimer_setup);
index e26e86bb56fe53381e2016e4f478dbdc37ec0294..60dc9b98951d0f682887c461852073eca81d46d7 100644 (file)
@@ -257,13 +257,13 @@ static int putreg(struct task_struct *child,
                        value &= 0xffff;
                        return 0;
                case offsetof(struct user_regs_struct,fs_base):
-                       if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
-                               return -EIO; 
+                       if (value >= TASK_SIZE)
+                               return -EIO;
                        child->thread.fs = value;
                        return 0;
                case offsetof(struct user_regs_struct,gs_base):
-                       if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
-                               return -EIO; 
+                       if (value >= TASK_SIZE)
+                               return -EIO;
                        child->thread.gs = value;
                        return 0;
                case offsetof(struct user_regs_struct, eflags):
@@ -277,6 +277,11 @@ static int putreg(struct task_struct *child,
                                return -EIO;
                        value &= 0xffff;
                        break;
+               case offsetof(struct user_regs_struct, rip):
+                       /* Check if the new RIP address is canonical */
+                       if (value >= TASK_SIZE)
+                               return -EIO;
+                       break;
        }
        put_stack_long(child, regno - sizeof(struct pt_regs), value);
        return 0;
index 2129cf9ba6b2fc066194474c058f821eefe22f4c..b9fd0252c279565075afd5fe0c20be37270f6c16 100644 (file)
@@ -727,11 +727,12 @@ static void __init display_cacheinfo(struct cpuinfo_x86 *c)
 static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
-       int cpu = c->x86_apicid;
+       int cpu = smp_processor_id();
        int node = 0;
        if (c->x86_num_cores == 1)
                return;
-       cpu_core_id[cpu] = cpu >> hweight32(c->x86_num_cores - 1);
+       /* Fix up the APIC ID following the AMD specification. */
+       cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1);
 
 #ifdef CONFIG_NUMA
        /* When an ACPI SRAT table is available use the mappings from SRAT
@@ -745,6 +746,9 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
                node = cpu_to_node[cpu];
        }
 #endif
+       /* For now: - better than BAD_APIC_ID at least*/
+       phys_proc_id[cpu] = cpu_core_id[cpu];
+
        printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n",
                        cpu, c->x86_num_cores, node, cpu_core_id[cpu]);
 #endif
@@ -925,7 +929,6 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c)
        c->x86_clflush_size = 64;
        c->x86_cache_alignment = c->x86_clflush_size;
        c->x86_num_cores = 1;
-       c->x86_apicid = c == &boot_cpu_data ? 0 : c - cpu_data;
        c->extended_cpuid_level = 0;
        memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
@@ -954,11 +957,15 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c)
                } 
                if (c->x86_capability[0] & (1<<19)) 
                        c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
-               c->x86_apicid = misc >> 24;
        } else {
                /* Have CPUID level 0 only - unheard of */
                c->x86 = 4;
        }
+
+#ifdef CONFIG_SMP
+       phys_proc_id[smp_processor_id()] =
+       cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+#endif
 }
 
 /*
@@ -1088,7 +1095,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
                /* Other (Linux-defined) */
-               "cxmmx", NULL, "cyrix_arr", "centaur_mcr", "k8c+",
+               "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
                "constant_tsc", NULL, NULL,
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
index 73f7e8b9543aa55051e6a912e231db6ad6c8aa3b..5abdee1e16a59c581e618f1fb0ea8473ddadd10a 100644 (file)
@@ -56,6 +56,7 @@
 #include <asm/kdebug.h>
 #include <asm/tlbflush.h>
 #include <asm/proto.h>
+#include <asm/nmi.h>
 
 /* Change for real CPU hotplug. Note other files need to be fixed
    first too. */
@@ -125,96 +126,210 @@ static void __cpuinit smp_store_cpu_info(int id)
 
        *c = boot_cpu_data;
        identify_cpu(c);
+       print_cpu_info(c);
 }
 
 /*
- * Synchronize TSCs of CPUs
+ * New Funky TSC sync algorithm borrowed from IA64.
+ * Main advantage is that it doesn't reset the TSCs fully and
+ * in general looks more robust and it works better than my earlier
+ * attempts. I believe it was written by David Mosberger. Some minor
+ * adjustments for x86-64 by me -AK
  *
- * This new algorithm is less accurate than the old "zero TSCs"
- * one, but we cannot zero TSCs anymore in the new hotplug CPU
- * model.
+ * Original comment reproduced below.
+ *
+ * Synchronize TSC of the current (slave) CPU with the TSC of the
+ * MASTER CPU (normally the time-keeper CPU).  We use a closed loop to
+ * eliminate the possibility of unaccounted-for errors (such as
+ * getting a machine check in the middle of a calibration step).  The
+ * basic idea is for the slave to ask the master what itc value it has
+ * and to read its own itc before and after the master responds.  Each
+ * iteration gives us three timestamps:
+ *
+ *     slave           master
+ *
+ *     t0 ---\
+ *             ---\
+ *                --->
+ *                     tm
+ *                /---
+ *            /---
+ *     t1 <---
+ *
+ *
+ * The goal is to adjust the slave's TSC such that tm falls exactly
+ * half-way between t0 and t1.  If we achieve this, the clocks are
+ * synchronized provided the interconnect between the slave and the
+ * master is symmetric.  Even if the interconnect were asymmetric, we
+ * would still know that the synchronization error is smaller than the
+ * roundtrip latency (t0 - t1).
+ *
+ * When the interconnect is quiet and symmetric, this lets us
+ * synchronize the TSC to within one or two cycles.  However, we can
+ * only *guarantee* that the synchronization is accurate to within a
+ * round-trip time, which is typically in the range of several hundred
+ * cycles (e.g., ~500 cycles).  In practice, this means that the TSCs
+ * are usually almost perfectly synchronized, but we shouldn't assume
+ * that the accuracy is much better than half a micro second or so.
+ *
+ * [there are other errors like the latency of RDTSC and of the
+ * WRMSR. These can also account to hundreds of cycles. So it's
+ * probably worse. It claims 153 cycles error on a dual Opteron,
+ * but I suspect the numbers are actually somewhat worse -AK]
  */
 
-static atomic_t __cpuinitdata tsc_flag;
+#define MASTER 0
+#define SLAVE  (SMP_CACHE_BYTES/8)
+
+/* Intentionally don't use cpu_relax() while TSC synchronization
+   because we don't want to go into funky power save modi or cause
+   hypervisors to schedule us away.  Going to sleep would likely affect
+   latency and low latency is the primary objective here. -AK */
+#define no_cpu_relax() barrier()
+
 static __cpuinitdata DEFINE_SPINLOCK(tsc_sync_lock);
-static unsigned long long __cpuinitdata bp_tsc, ap_tsc;
+static volatile __cpuinitdata unsigned long go[SLAVE + 1];
+static int notscsync __cpuinitdata;
+
+#undef DEBUG_TSC_SYNC
 
-#define NR_LOOPS 5
+#define NUM_ROUNDS     64      /* magic value */
+#define NUM_ITERS      5       /* likewise */
 
-static void __cpuinit sync_tsc_bp_init(int init)
+/* Callback on boot CPU */
+static __cpuinit void sync_master(void *arg)
 {
-       if (init)
-               _raw_spin_lock(&tsc_sync_lock);
-       else
-               _raw_spin_unlock(&tsc_sync_lock);
-       atomic_set(&tsc_flag, 0);
+       unsigned long flags, i;
+
+       if (smp_processor_id() != boot_cpu_id)
+               return;
+
+       go[MASTER] = 0;
+
+       local_irq_save(flags);
+       {
+               for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) {
+                       while (!go[MASTER])
+                               no_cpu_relax();
+                       go[MASTER] = 0;
+                       rdtscll(go[SLAVE]);
+               }
+       }
+       local_irq_restore(flags);
 }
 
 /*
- * Synchronize TSC on AP with BP.
+ * Return the number of cycles by which our tsc differs from the tsc
+ * on the master (time-keeper) CPU.  A positive number indicates our
+ * tsc is ahead of the master, negative that it is behind.
  */
-static void __cpuinit __sync_tsc_ap(void)
+static inline long
+get_delta(long *rt, long *master)
 {
-       if (!cpu_has_tsc)
-               return;
-       Dprintk("AP %d syncing TSC\n", smp_processor_id());
+       unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0;
+       unsigned long tcenter, t0, t1, tm;
+       int i;
 
-       while (atomic_read(&tsc_flag) != 0)
-               cpu_relax();
-       atomic_inc(&tsc_flag);
-       mb();
-       _raw_spin_lock(&tsc_sync_lock);
-       wrmsrl(MSR_IA32_TSC, bp_tsc);
-       _raw_spin_unlock(&tsc_sync_lock);
-       rdtscll(ap_tsc);
-       mb();
-       atomic_inc(&tsc_flag);
-       mb();
+       for (i = 0; i < NUM_ITERS; ++i) {
+               rdtscll(t0);
+               go[MASTER] = 1;
+               while (!(tm = go[SLAVE]))
+                       no_cpu_relax();
+               go[SLAVE] = 0;
+               rdtscll(t1);
+
+               if (t1 - t0 < best_t1 - best_t0)
+                       best_t0 = t0, best_t1 = t1, best_tm = tm;
+       }
+
+       *rt = best_t1 - best_t0;
+       *master = best_tm - best_t0;
+
+       /* average best_t0 and best_t1 without overflow: */
+       tcenter = (best_t0/2 + best_t1/2);
+       if (best_t0 % 2 + best_t1 % 2 == 2)
+               ++tcenter;
+       return tcenter - best_tm;
 }
 
-static void __cpuinit sync_tsc_ap(void)
+static __cpuinit void sync_tsc(void)
 {
-       int i;
-       for (i = 0; i < NR_LOOPS; i++)
-               __sync_tsc_ap();
+       int i, done = 0;
+       long delta, adj, adjust_latency = 0;
+       unsigned long flags, rt, master_time_stamp, bound;
+#if DEBUG_TSC_SYNC
+       static struct syncdebug {
+               long rt;        /* roundtrip time */
+               long master;    /* master's timestamp */
+               long diff;      /* difference between midpoint and master's timestamp */
+               long lat;       /* estimate of tsc adjustment latency */
+       } t[NUM_ROUNDS] __cpuinitdata;
+#endif
+
+       go[MASTER] = 1;
+
+       smp_call_function(sync_master, NULL, 1, 0);
+
+       while (go[MASTER])      /* wait for master to be ready */
+               no_cpu_relax();
+
+       spin_lock_irqsave(&tsc_sync_lock, flags);
+       {
+               for (i = 0; i < NUM_ROUNDS; ++i) {
+                       delta = get_delta(&rt, &master_time_stamp);
+                       if (delta == 0) {
+                               done = 1;       /* let's lock on to this... */
+                               bound = rt;
+                       }
+
+                       if (!done) {
+                               unsigned long t;
+                               if (i > 0) {
+                                       adjust_latency += -delta;
+                                       adj = -delta + adjust_latency/4;
+                               } else
+                                       adj = -delta;
+
+                               rdtscll(t);
+                               wrmsrl(MSR_IA32_TSC, t + adj);
+                       }
+#if DEBUG_TSC_SYNC
+                       t[i].rt = rt;
+                       t[i].master = master_time_stamp;
+                       t[i].diff = delta;
+                       t[i].lat = adjust_latency/4;
+#endif
+               }
+       }
+       spin_unlock_irqrestore(&tsc_sync_lock, flags);
+
+#if DEBUG_TSC_SYNC
+       for (i = 0; i < NUM_ROUNDS; ++i)
+               printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",
+                      t[i].rt, t[i].master, t[i].diff, t[i].lat);
+#endif
+
+       printk(KERN_INFO
+              "CPU %d: synchronized TSC with CPU %u (last diff %ld cycles, "
+              "maxerr %lu cycles)\n",
+              smp_processor_id(), boot_cpu_id, delta, rt);
 }
 
-/*
- * Synchronize TSC from BP to AP.
- */
-static void __cpuinit __sync_tsc_bp(int cpu)
+static void __cpuinit tsc_sync_wait(void)
 {
-       if (!cpu_has_tsc)
+       if (notscsync || !cpu_has_tsc)
                return;
-
-       /* Wait for AP */
-       while (atomic_read(&tsc_flag) == 0)
-               cpu_relax();
-       /* Save BPs TSC */
-       sync_core();
-       rdtscll(bp_tsc);
-       /* Don't do the sync core here to avoid too much latency. */
-       mb();
-       /* Start the AP */
-       _raw_spin_unlock(&tsc_sync_lock);
-       /* Wait for AP again */
-       while (atomic_read(&tsc_flag) < 2)
-               cpu_relax();
-       rdtscl(bp_tsc);
-       barrier();
+       printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n", smp_processor_id(),
+                       boot_cpu_id);
+       sync_tsc();
 }
 
-static void __cpuinit sync_tsc_bp(int cpu)
+static __init int notscsync_setup(char *s)
 {
-       int i;
-       for (i = 0; i < NR_LOOPS - 1; i++) {
-               __sync_tsc_bp(cpu);
-               sync_tsc_bp_init(1);
-       }
-       __sync_tsc_bp(cpu);
-       printk(KERN_INFO "Synced TSC of CPU %d difference %Ld\n",
-              cpu, ap_tsc - bp_tsc);
+       notscsync = 1;
+       return 0;
 }
+__setup("notscsync", notscsync_setup);
 
 static atomic_t init_deasserted __cpuinitdata;
 
@@ -315,11 +430,6 @@ void __cpuinit start_secondary(void)
        cpu_init();
        smp_callin();
 
-       /*
-        * Synchronize the TSC with the BP
-        */
-       sync_tsc_ap();
-
        /* otherwise gcc will move up the smp_processor_id before the cpu_init */
        barrier();
 
@@ -334,7 +444,6 @@ void __cpuinit start_secondary(void)
                enable_8259A_irq(0);
        }
 
-
        enable_APIC_timer();
 
        /*
@@ -343,6 +452,11 @@ void __cpuinit start_secondary(void)
        cpu_set(smp_processor_id(), cpu_online_map);
        mb();
 
+       /* Wait for TSC sync to not schedule things before.
+          We still process interrupts, which could see an inconsistent
+          time in that window unfortunately. */
+       tsc_sync_wait();
+
        cpu_idle();
 }
 
@@ -531,7 +645,6 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
                printk("failed fork for CPU %d\n", cpu);
                return PTR_ERR(idle);
        }
-       x86_cpu_to_apicid[cpu] = apicid;
 
        cpu_pda[cpu].pcurrent = idle;
 
@@ -600,8 +713,6 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
 
                if (cpu_isset(cpu, cpu_callin_map)) {
                        /* number CPUs logically, starting from 1 (BSP is 0) */
-                       Dprintk("OK.\n");
-                       print_cpu_info(&cpu_data[cpu]);
                        Dprintk("CPU has booted.\n");
                } else {
                        boot_error = 1;
@@ -842,7 +953,6 @@ void __cpuinit smp_prepare_cpus(unsigned int max_cpus)
                      GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_id);
                /* Or can we switch back to PIC here? */
        }
-       x86_cpu_to_apicid[0] = boot_cpu_id;
 
        /*
         * Now start the IO-APICs
@@ -889,18 +999,14 @@ int __cpuinit __cpu_up(unsigned int cpu)
                printk("__cpu_up: bad cpu %d\n", cpu);
                return -EINVAL;
        }
-       sync_tsc_bp_init(1);
 
        /* Boot it! */
        err = do_boot_cpu(cpu, apicid);
        if (err < 0) {
-               sync_tsc_bp_init(0);
                Dprintk("do_boot_cpu failed %d\n", err);
                return err;
        }
 
-       sync_tsc_bp(cpu);
-
        /* Unleash the CPU! */
        Dprintk("waiting for cpu %d\n", cpu);
 
@@ -923,4 +1029,6 @@ void __cpuinit smp_cpus_done(unsigned int max_cpus)
 
        detect_siblings();
        time_init_gtod();
+
+       check_nmi_watchdog();
 }
index 0e3b60e1ac5b54f60d4a2a7cff4492c8ddef9774..735b6767c8ed78eda64acda6cba265cbfc8df44e 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/sysdev.h>
 #include <linux/bcd.h>
 #include <linux/kallsyms.h>
+#include <linux/acpi.h>
+#include <acpi/achware.h>      /* for PM timer frequency */
 #include <asm/8253pit.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
@@ -396,6 +398,10 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        (offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick;
 
                vxtime.last = offset;
+#ifdef CONFIG_X86_PM_TIMER
+       } else if (vxtime.mode == VXTIME_PMTMR) {
+               lost = pmtimer_mark_offset();
+#endif
        } else {
                offset = (((tsc - vxtime.last_tsc) *
                           vxtime.tsc_quot) >> 32) - (USEC_PER_SEC / HZ);
@@ -898,6 +904,13 @@ void __init time_init(void)
                        hpet_period;
                cpu_khz = hpet_calibrate_tsc();
                timename = "HPET";
+#ifdef CONFIG_X86_PM_TIMER
+       } else if (pmtmr_ioport) {
+               vxtime_hz = PM_TIMER_FREQUENCY;
+               timename = "PM";
+               pit_init();
+               cpu_khz = pit_calibrate_tsc();
+#endif
        } else {
                pit_init();
                cpu_khz = pit_calibrate_tsc();
@@ -922,6 +935,27 @@ void __init time_init(void)
 #endif
 }
 
+/*
+ * Make an educated guess if the TSC is trustworthy and synchronized
+ * over all CPUs.
+ */
+static __init int unsynchronized_tsc(void)
+{
+#ifdef CONFIG_SMP
+       if (oem_force_hpet_timer())
+               return 1;
+       /* Intel systems are normally all synchronized. Exceptions
+          are handled in the OEM check above. */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+               return 0;
+       /* All in a single socket - should be synchronized */
+       if (cpus_weight(cpu_core_map[0]) == num_online_cpus())
+               return 0;
+#endif
+       /* Assume multi socket systems are not synchronized */
+       return num_online_cpus() > 1;
+}
+
 /*
  * Decide after all CPUs are booted what mode gettimeofday should use.
  */
@@ -929,29 +963,23 @@ void __init time_init_gtod(void)
 {
        char *timetype;
 
-       /*
-        * AMD systems with more than one CPU don't have fully synchronized
-        * TSCs. Always use HPET gettimeofday for these, although it is slower.
-        * Intel SMP systems usually have synchronized TSCs, so use always
-        * the TSC.
-        *
-        * Exceptions:
-        * IBM Summit2 checked by oem_force_hpet_timer().
-        * AMD dual core may also not need HPET. Check me.
-        *
-        * Can be turned off with "notsc".
-        */
-       if (num_online_cpus() > 1 &&
-           boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-               notsc = 1;
-       /* Some systems will want to disable TSC and use HPET. */
-       if (oem_force_hpet_timer())
+       if (unsynchronized_tsc())
                notsc = 1;
        if (vxtime.hpet_address && notsc) {
                timetype = "HPET";
                vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
                vxtime.mode = VXTIME_HPET;
                do_gettimeoffset = do_gettimeoffset_hpet;
+#ifdef CONFIG_X86_PM_TIMER
+       /* Using PM for gettimeofday is quite slow, but we have no other
+          choice because the TSC is too unreliable on some systems. */
+       } else if (pmtmr_ioport && !vxtime.hpet_address && notsc) {
+               timetype = "PM";
+               do_gettimeoffset = do_gettimeoffset_pm;
+               vxtime.mode = VXTIME_PMTMR;
+               sysctl_vsyscall = 0;
+               printk(KERN_INFO "Disabling vsyscall due to use of PM timer\n");
+#endif
        } else {
                timetype = vxtime.hpet_address ? "HPET/TSC" : "PIT/TSC";
                vxtime.mode = VXTIME_TSC;
index b4b8dc59663ad447f6228fff15209067928b642e..2e5734425949648ea92bd8d7fd9e65e6f99a8ed5 100644 (file)
@@ -65,7 +65,7 @@ static force_inline void do_vgettimeofday(struct timeval * tv)
                usec = (__xtime.tv_nsec / 1000) +
                        (__jiffies - __wall_jiffies) * (1000000 / HZ);
 
-               if (__vxtime.mode == VXTIME_TSC) {
+               if (__vxtime.mode != VXTIME_HPET) {
                        sync_core();
                        rdtscll(t);
                        if (t < __vxtime.last_tsc)
@@ -217,8 +217,9 @@ static int __init vsyscall_init(void)
        BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
        BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
        map_vsyscall();
-       sysctl_vsyscall = 1;
+#ifdef CONFIG_SYSCTL
        register_sysctl_table(kernel_root_table2, 0);
+#endif
        return 0;
 }
 
index e0330921676413d100b6a1f2cf2c6f579133e3d8..5d6b2114cc9a4e5d30b9736a339dad5bc03839fc 100644 (file)
@@ -234,6 +234,8 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
 
 /*
  * Handle a fault on the vmalloc or module mapping area
+ *
+ * This assumes no large pages in there.
  */
 static int vmalloc_fault(unsigned long address)
 {
@@ -272,7 +274,10 @@ static int vmalloc_fault(unsigned long address)
        if (!pte_present(*pte_ref))
                return -1;
        pte = pte_offset_kernel(pmd, address);
-       if (!pte_present(*pte) || pte_page(*pte) != pte_page(*pte_ref))
+       /* Don't use pte_page here, because the mappings can point
+          outside mem_map, and the NUMA hash lookup cannot handle
+          that. */
+       if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref))
                BUG();
        __flush_tlb_all();
        return 0;
@@ -346,7 +351,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
         * protection error (error_code & 1) == 0.
         */
        if (unlikely(address >= TASK_SIZE)) {
-               if (!(error_code & 5)) {
+               if (!(error_code & 5) &&
+                     ((address >= VMALLOC_START && address < VMALLOC_END) ||
+                      (address >= MODULES_VADDR && address < MODULES_END))) {
                        if (vmalloc_fault(address) < 0)
                                goto bad_area_nosemaphore;
                        return;
index 74ec8554b195de6c5a9b87ce5d39f08d9c5da544..c6fb0cb69992bbf14a2f42d4ddde10b298cd9316 100644 (file)
@@ -272,7 +272,7 @@ void iounmap(volatile void __iomem *addr)
        if ((p->flags >> 20) &&
                p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) {
                /* p->size includes the guard page, but cpa doesn't like that */
-               change_page_attr(virt_to_page(__va(p->phys_addr)),
+               change_page_attr_addr((unsigned long)__va(p->phys_addr),
                                 p->size >> PAGE_SHIFT,
                                 PAGE_KERNEL);
                global_flush_tlb();
index f691d31fa9ee0cbe7a1817408ea845584bd2a8b9..3fcf6e887e87d7280a9765450b237e9933af035a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <asm/scatterlist.h>
 #include <linux/crypto.h>
+#include <linux/string.h>
 
 #define NULL_KEY_SIZE          0
 #define NULL_BLOCK_SIZE                1
 
 static int null_compress(void *ctx, const u8 *src, unsigned int slen,
                          u8 *dst, unsigned int *dlen)
-{ return 0; }
-
-static int null_decompress(void *ctx, const u8 *src, unsigned int slen,
-                           u8 *dst, unsigned int *dlen)
-{ return 0; }
+{
+       if (slen > *dlen)
+               return -EINVAL;
+       memcpy(dst, src, slen);
+       *dlen = slen;
+       return 0;
+}
 
 static void null_init(void *ctx)
 { }
@@ -47,11 +50,10 @@ static int null_setkey(void *ctx, const u8 *key,
                        unsigned int keylen, u32 *flags)
 { return 0; }
 
-static void null_encrypt(void *ctx, u8 *dst, const u8 *src)
-{ }
-
-static void null_decrypt(void *ctx, u8 *dst, const u8 *src)
-{ }
+static void null_crypt(void *ctx, u8 *dst, const u8 *src)
+{
+       memcpy(dst, src, NULL_BLOCK_SIZE);
+}
 
 static struct crypto_alg compress_null = {
        .cra_name               =       "compress_null",
@@ -62,7 +64,7 @@ static struct crypto_alg compress_null = {
        .cra_list               =       LIST_HEAD_INIT(compress_null.cra_list),
        .cra_u                  =       { .compress = {
        .coa_compress           =       null_compress,
-       .coa_decompress         =       null_decompress } }
+       .coa_decompress         =       null_compress } }
 };
 
 static struct crypto_alg digest_null = {
@@ -90,8 +92,8 @@ static struct crypto_alg cipher_null = {
        .cia_min_keysize        =       NULL_KEY_SIZE,
        .cia_max_keysize        =       NULL_KEY_SIZE,
        .cia_setkey             =       null_setkey,
-       .cia_encrypt            =       null_encrypt,
-       .cia_decrypt            =       null_decrypt } }
+       .cia_encrypt            =       null_crypt,
+       .cia_decrypt            =       null_crypt } }
 };
 
 MODULE_ALIAS("compress_null");
index 5e03f5157ef93b2d2b3bc447a36ceba566a2336d..6d7bcc9da9e72f806d0c3fe77aacca8c1ec896e3 100644 (file)
@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        }
        return ret;
 }
+
+EXPORT_SYMBOL_GPL(blkdev_ioctl);
index 1a1fa3ccb91375031556815e71fa858cdc48ab60..b9a6b7ad64f383c4056a3d9ff9d7b35dc56209e2 100644 (file)
@@ -914,8 +914,10 @@ static int pkt_handle_queue(struct pktcdvd_device *pd)
                bio = node->bio;
                zone = ZONE(bio->bi_sector, pd);
                list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
-                       if (p->sector == zone)
+                       if (p->sector == zone) {
+                               bio = NULL;
                                goto try_next_bio;
+                       }
                }
                break;
 try_next_bio:
@@ -2406,7 +2408,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
        case CDROM_LAST_WRITTEN:
        case CDROM_SEND_PACKET:
        case SCSI_IOCTL_SEND_COMMAND:
-               return ioctl_by_bdev(pd->bdev, cmd, arg);
+               return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
 
        case CDROMEJECT:
                /*
@@ -2414,7 +2416,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                 * have to unlock it or else the eject command fails.
                 */
                pkt_lock_door(pd, 0);
-               return ioctl_by_bdev(pd->bdev, cmd, arg);
+               return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
 
        default:
                printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
index a2e33ec796151ab4f96f4a869447f87088f0e300..131465e8de5aa72b6e8f5621a6b000c97862f73a 100644 (file)
@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp,
 {
        struct block_device *bdev = filp->private_data;
 
-       return ioctl_by_bdev(bdev, command, arg);
+       return blkdev_ioctl(bdev->bd_inode, filp, command, arg);
 }
 
 static void bind_device(struct raw_config_request *rq)
index c337978dc966b7e955a1ed736e8fd7bad47a062b..b14d642439ed1343ba30e8db18769176d80a9b63 100644 (file)
@@ -382,6 +382,7 @@ static struct pci_device_id i8xx_tco_pci_tbl[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2,      PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,      PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,      PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,       PCI_ANY_ID, PCI_ANY_ID, },
        { 0, },                 /* End of list */
 };
 MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
index bdff5ac580531c2bf1cdbc4faf79700552e5c762..4b1e43b4118b696eec9a0d1a7609d9099110e863 100644 (file)
@@ -516,6 +516,6 @@ void proc_ide_create(void)
 
 void proc_ide_destroy(void)
 {
-       remove_proc_entry("ide/drivers", proc_ide_root);
+       remove_proc_entry("drivers", proc_ide_root);
        remove_proc_entry("ide", NULL);
 }
index 78b201fb5e8ab792c622bddcc69e396039a8b772..7d58af1ae306f2574c5217a2b4477f9ef1e378f0 100644 (file)
@@ -84,11 +84,6 @@ config IEEE1394_PCILYNX
          To compile this driver as a module, say M here: the
          module will be called pcilynx.
 
-# Non-maintained pcilynx options
-# if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
-#     bool '    Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
-#     bool '    Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS
-# fi
 config IEEE1394_OHCI1394
        tristate "OHCI-1394 support"
        depends on PCI && IEEE1394
index 1c5845f7e4ab3103675db0a54edb04c4a4adf6cb..a294e45c77cdfb09c7338ca07c2777514427ed7a 100644 (file)
@@ -520,7 +520,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
 
        if (!packet->no_waiter || packet->expect_response) {
                atomic_inc(&packet->refcnt);
-               packet->sendtime = jiffies;
+               packet->sendtime = jiffies + 10 * HZ;
                skb_queue_tail(&host->pending_packet_queue, packet->skb);
        }
 
@@ -1248,7 +1248,6 @@ EXPORT_SYMBOL(hpsb_make_phypacket);
 EXPORT_SYMBOL(hpsb_make_isopacket);
 EXPORT_SYMBOL(hpsb_read);
 EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
 EXPORT_SYMBOL(hpsb_packet_success);
 
 /** highlevel.c **/
index 09908b9564d8b944d5029f83b03f405846890fc4..0aa876360f9be647e307923a325bcda390970979 100644 (file)
@@ -535,6 +535,7 @@ hpsb_write_fail:
         return retval;
 }
 
+#if 0
 
 int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
              u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
@@ -599,3 +600,5 @@ int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
 
        return retval;
 }
+
+#endif  /*  0  */
index 526a43ceb49602f6130869826b21ab91d2a1dad8..45ba784fe6da044b4114cfa40f1a26f96bb0fdc2 100644 (file)
@@ -53,12 +53,5 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
              u64 addr, quadlet_t *buffer, size_t length);
 int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
               u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-             u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
-int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-               u64 addr, int extcode, octlet_t *data, octlet_t arg);
-int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
-                   quadlet_t *buffer, size_t length, u32 specifier_id,
-                   unsigned int version);
 
 #endif /* _IEEE1394_TRANSACTIONS_H */
index a1e30a66297bcbff0de7d95c9257710ecfb6ea0a..83e66ed97ab53640480728c816b810e7c67319a5 100644 (file)
@@ -1005,8 +1005,7 @@ static struct unit_directory *nodemgr_process_unit_directory
        return ud;
 
 unit_directory_error:
-       if (ud != NULL)
-               kfree(ud);
+       kfree(ud);
        return NULL;
 }
 
index 6cb0b586c29761d2e3873219a692f83ace1017d6..36e25ac823dc73c2f69c58e391dd4382af59de55 100644 (file)
@@ -2931,7 +2931,7 @@ static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
                kfree(d->prg_cpu);
                kfree(d->prg_bus);
        }
-       if (d->spb) kfree(d->spb);
+       kfree(d->spb);
 
        /* Mark this context as freed. */
        d->ohci = NULL;
index d1758d409610b3906823fb186a8a1325c70fd1dd..cc66c1cae250c1cb105599810637e1ff77ba58bb 100644 (file)
@@ -236,6 +236,9 @@ struct ti_ohci {
 
 static inline int cross_bound(unsigned long addr, unsigned int size)
 {
+       if (size == 0)
+               return 0;
+
        if (size > PAGE_SIZE)
                return 1;
 
index a261d2b0e5ac7b40ed039fd51a4d385c5d0e4aca..bdb3a85cafa68507a82616e88b55952f3ff0a057 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/kdev_t.h>
+#include <linux/dma-mapping.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -834,327 +835,6 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
  * IEEE-1394 functionality section END *
  ***************************************/
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-/* VFS functions for local bus / aux device access.  Access to those
- * is implemented as a character device instead of block devices
- * because buffers are not wanted for this.  Therefore llseek (from
- * VFS) can be used for these char devices with obvious effects.
- */
-static int mem_open(struct inode*, struct file*);
-static int mem_release(struct inode*, struct file*);
-static unsigned int aux_poll(struct file*, struct poll_table_struct*);
-static loff_t mem_llseek(struct file*, loff_t, int);
-static ssize_t mem_read (struct file*, char*, size_t, loff_t*);
-static ssize_t mem_write(struct file*, const char*, size_t, loff_t*);
-
-
-static struct file_operations aux_ops = {
-       .owner =        THIS_MODULE,
-        .read =         mem_read,
-        .write =        mem_write,
-        .poll =         aux_poll,
-        .llseek =       mem_llseek,
-        .open =         mem_open,
-        .release =      mem_release,
-};
-
-
-static void aux_setup_pcls(struct ti_lynx *lynx)
-{
-        struct ti_pcl pcl;
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.user_data = pcl_bus(lynx, lynx->dmem_pcl);
-        put_pcl(lynx, lynx->dmem_pcl, &pcl);
-}
-
-static int mem_open(struct inode *inode, struct file *file)
-{
-        int cid = iminor(inode);
-        enum { t_rom, t_aux, t_ram } type;
-        struct memdata *md;
-
-        if (cid < PCILYNX_MINOR_AUX_START) {
-                /* just for completeness */
-                return -ENXIO;
-        } else if (cid < PCILYNX_MINOR_ROM_START) {
-                cid -= PCILYNX_MINOR_AUX_START;
-                if (cid >= num_of_cards || !cards[cid].aux_port)
-                        return -ENXIO;
-                type = t_aux;
-        } else if (cid < PCILYNX_MINOR_RAM_START) {
-                cid -= PCILYNX_MINOR_ROM_START;
-                if (cid >= num_of_cards || !cards[cid].local_rom)
-                        return -ENXIO;
-                type = t_rom;
-        } else {
-                /* WARNING: Know what you are doing when opening RAM.
-                 * It is currently used inside the driver! */
-                cid -= PCILYNX_MINOR_RAM_START;
-                if (cid >= num_of_cards || !cards[cid].local_ram)
-                        return -ENXIO;
-                type = t_ram;
-        }
-
-        md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);
-        if (md == NULL)
-                return -ENOMEM;
-
-        md->lynx = &cards[cid];
-        md->cid = cid;
-
-        switch (type) {
-        case t_rom:
-                md->type = rom;
-                break;
-        case t_ram:
-                md->type = ram;
-                break;
-        case t_aux:
-                atomic_set(&md->aux_intr_last_seen,
-                           atomic_read(&cards[cid].aux_intr_seen));
-                md->type = aux;
-                break;
-        }
-
-        file->private_data = md;
-
-        return 0;
-}
-
-static int mem_release(struct inode *inode, struct file *file)
-{
-        kfree(file->private_data);
-        return 0;
-}
-
-static unsigned int aux_poll(struct file *file, poll_table *pt)
-{
-        struct memdata *md = (struct memdata *)file->private_data;
-        int cid = md->cid;
-        unsigned int mask;
-
-        /* reading and writing is always allowed */
-        mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
-
-        if (md->type == aux) {
-                poll_wait(file, &cards[cid].aux_intr_wait, pt);
-
-                if (atomic_read(&md->aux_intr_last_seen)
-                    != atomic_read(&cards[cid].aux_intr_seen)) {
-                        mask |= POLLPRI;
-                        atomic_inc(&md->aux_intr_last_seen);
-                }
-        }
-
-        return mask;
-}
-
-loff_t mem_llseek(struct file *file, loff_t offs, int orig)
-{
-        loff_t newoffs;
-
-        switch (orig) {
-        case 0:
-                newoffs = offs;
-                break;
-        case 1:
-                newoffs = offs + file->f_pos;
-                break;
-        case 2:
-                newoffs = PCILYNX_MAX_MEMORY + 1 + offs;
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL;
-
-        file->f_pos = newoffs;
-        return newoffs;
-}
-
-/*
- * do not DMA if count is too small because this will have a serious impact
- * on performance - the value 2400 was found by experiment and may not work
- * everywhere as good as here - use mem_mindma option for modules to change
- */
-static short mem_mindma = 2400;
-module_param(mem_mindma, short, 0444);
-MODULE_PARM_DESC(mem_mindma, "Minimum amount of data required to use DMA");
-
-static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count,
-                           int offset)
-{
-        pcltmp_t pcltmp;
-        struct ti_pcl *pcl;
-        size_t retval;
-        int i;
-        DECLARE_WAITQUEUE(wait, current);
-
-        count &= ~3;
-        count = min(count, 53196);
-        retval = count;
-
-        if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))
-            & DMA_CHAN_CTRL_BUSY) {
-                PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!");
-        }
-
-        reg_write(md->lynx, LBUS_ADDR, md->type | offset);
-
-        pcl = edit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp);
-        pcl->buffer[0].control = PCL_CMD_LBUS_TO_PCI | min(count, 4092);
-        pcl->buffer[0].pointer = physbuf;
-        count -= 4092;
-
-        i = 0;
-        while (count > 0) {
-                i++;
-                pcl->buffer[i].control = min(count, 4092);
-                pcl->buffer[i].pointer = physbuf + i * 4092;
-                count -= 4092;
-        }
-        pcl->buffer[i].control |= PCL_LAST_BUFF;
-        commit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp);
-
-        set_current_state(TASK_INTERRUPTIBLE);
-        add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);
-        run_sub_pcl(md->lynx, md->lynx->dmem_pcl, 2, CHANNEL_LOCALBUS);
-
-        schedule();
-        while (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))
-               & DMA_CHAN_CTRL_BUSY) {
-                if (signal_pending(current)) {
-                        retval = -EINTR;
-                        break;
-                }
-                schedule();
-        }
-
-        reg_write(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS), 0);
-        remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);
-
-        if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))
-            & DMA_CHAN_CTRL_BUSY) {
-                PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!");
-        }
-
-        return retval;
-}
-
-static ssize_t mem_read(struct file *file, char *buffer, size_t count,
-                        loff_t *offset)
-{
-        struct memdata *md = (struct memdata *)file->private_data;
-        ssize_t bcount;
-        size_t alignfix;
-       loff_t off = *offset; /* avoid useless 64bit-arithmetic */
-        ssize_t retval;
-        void *membase;
-
-        if ((off + count) > PCILYNX_MAX_MEMORY+1) {
-                count = PCILYNX_MAX_MEMORY+1 - off;
-        }
-        if (count == 0 || off > PCILYNX_MAX_MEMORY) {
-                return -ENOSPC;
-        }
-
-        switch (md->type) {
-        case rom:
-                membase = md->lynx->local_rom;
-                break;
-        case ram:
-                membase = md->lynx->local_ram;
-                break;
-        case aux:
-                membase = md->lynx->aux_port;
-                break;
-        default:
-                panic("pcilynx%d: unsupported md->type %d in %s",
-                      md->lynx->id, md->type, __FUNCTION__);
-        }
-
-        down(&md->lynx->mem_dma_mutex);
-
-        if (count < mem_mindma) {
-                memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, count);
-                goto out;
-        }
-
-        bcount = count;
-        alignfix = 4 - (off % 4);
-        if (alignfix != 4) {
-                if (bcount < alignfix) {
-                        alignfix = bcount;
-                }
-                memcpy_fromio(md->lynx->mem_dma_buffer, membase+off,
-                              alignfix);
-                if (bcount == alignfix) {
-                        goto out;
-                }
-                bcount -= alignfix;
-                off += alignfix;
-        }
-
-        while (bcount >= 4) {
-                retval = mem_dmaread(md, md->lynx->mem_dma_buffer_dma
-                                     + count - bcount, bcount, off);
-                if (retval < 0) return retval;
-
-                bcount -= retval;
-                off += retval;
-        }
-
-        if (bcount) {
-                memcpy_fromio(md->lynx->mem_dma_buffer + count - bcount,
-                              membase+off, bcount);
-        }
-
- out:
-        retval = copy_to_user(buffer, md->lynx->mem_dma_buffer, count);
-        up(&md->lynx->mem_dma_mutex);
-
-       if (retval) return -EFAULT;
-        *offset += count;
-        return count;
-}
-
-
-static ssize_t mem_write(struct file *file, const char *buffer, size_t count,
-                         loff_t *offset)
-{
-        struct memdata *md = (struct memdata *)file->private_data;
-
-        if (((*offset) + count) > PCILYNX_MAX_MEMORY+1) {
-                count = PCILYNX_MAX_MEMORY+1 - *offset;
-        }
-        if (count == 0 || *offset > PCILYNX_MAX_MEMORY) {
-                return -ENOSPC;
-        }
-
-        /* FIXME: dereferencing pointers to PCI mem doesn't work everywhere */
-        switch (md->type) {
-        case aux:
-               if (copy_from_user(md->lynx->aux_port+(*offset), buffer, count))
-                       return -EFAULT;
-                break;
-        case ram:
-               if (copy_from_user(md->lynx->local_ram+(*offset), buffer, count))
-                       return -EFAULT;
-                break;
-        case rom:
-                /* the ROM may be writeable */
-               if (copy_from_user(md->lynx->local_rom+(*offset), buffer, count))
-                       return -EFAULT;
-                break;
-        }
-
-        file->f_pos += count;
-        return count;
-}
-#endif /* CONFIG_IEEE1394_PCILYNX_PORTS */
-
 
 /********************************************************
  * Global stuff (interrupt handler, init/shutdown code) *
@@ -1181,18 +861,6 @@ static irqreturn_t lynx_irq_handler(int irq, void *dev_id,
         reg_write(lynx, LINK_INT_STATUS, linkint);
         reg_write(lynx, PCI_INT_STATUS, intmask);
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (intmask & PCI_INT_AUX_INT) {
-                atomic_inc(&lynx->aux_intr_seen);
-                wake_up_interruptible(&lynx->aux_intr_wait);
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_LOCALBUS)) {
-                wake_up_interruptible(&lynx->mem_dma_intr_wait);
-        }
-#endif
-
-
         if (intmask & PCI_INT_1394) {
                 if (linkint & LINK_INT_PHY_TIMEOUT) {
                         PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");
@@ -1484,15 +1152,9 @@ static void remove_card(struct pci_dev *dev)
                 pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
                                     lynx->rcv_page_dma);
         case have_aux_buf:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-                pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
-                                    lynx->mem_dma_buffer_dma);
-#endif
         case have_pcl_mem:
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
                 pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
                                     lynx->pcl_mem_dma);
-#endif
         case clear:
                 /* do nothing - already freed */
                 ;
@@ -1524,7 +1186,7 @@ static int __devinit add_card(struct pci_dev *dev,
 
         error = -ENXIO;
 
-        if (pci_set_dma_mask(dev, 0xffffffff))
+        if (pci_set_dma_mask(dev, DMA_32BIT_MASK))
                 FAIL("DMA address limits not supported for PCILynx hardware");
         if (pci_enable_device(dev))
                 FAIL("failed to enable PCILynx hardware");
@@ -1546,7 +1208,6 @@ static int __devinit add_card(struct pci_dev *dev,
         spin_lock_init(&lynx->lock);
         spin_lock_init(&lynx->phy_reg_lock);
 
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
         lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,
                                              &lynx->pcl_mem_dma);
 
@@ -1558,16 +1219,6 @@ static int __devinit add_card(struct pci_dev *dev,
         } else {
                 FAIL("failed to allocate PCL memory area");
         }
-#endif
-
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        lynx->mem_dma_buffer = pci_alloc_consistent(dev, 65536,
-                                                    &lynx->mem_dma_buffer_dma);
-        if (lynx->mem_dma_buffer == NULL) {
-                FAIL("failed to allocate DMA buffer for aux");
-        }
-        lynx->state = have_aux_buf;
-#endif
 
         lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,
                                               &lynx->rcv_page_dma);
@@ -1597,13 +1248,6 @@ static int __devinit add_card(struct pci_dev *dev,
                 FAIL("failed to remap registers - card not accessible");
         }
 
-#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM
-        if (lynx->local_ram == NULL) {
-                FAIL("failed to remap local RAM which is required for "
-                     "operation");
-        }
-#endif
-
         reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
         /* Fix buggy cards with autoboot pin not tied low: */
         reg_write(lynx, DMA0_CHAN_CTRL, 0);
@@ -1624,13 +1268,6 @@ static int __devinit add_card(struct pci_dev *dev,
 
         /* alloc_pcl return values are not checked, it is expected that the
          * provided PCL space is sufficient for the initial allocations */
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (lynx->aux_port != NULL) {
-                lynx->dmem_pcl = alloc_pcl(lynx);
-                aux_setup_pcls(lynx);
-                sema_init(&lynx->mem_dma_mutex, 1);
-        }
-#endif
         lynx->rcv_pcl = alloc_pcl(lynx);
         lynx->rcv_pcl_start = alloc_pcl(lynx);
         lynx->async.pcl = alloc_pcl(lynx);
@@ -1647,12 +1284,6 @@ static int __devinit add_card(struct pci_dev *dev,
 
         reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT);
-        init_waitqueue_head(&lynx->mem_dma_intr_wait);
-        init_waitqueue_head(&lynx->aux_intr_wait);
-#endif
-
        tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh,
                     (unsigned long)lynx);
 
@@ -1944,37 +1575,18 @@ static int __init pcilynx_init(void)
 {
         int ret;
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
-                PRINT_G(KERN_ERR, "allocation of char major number %d failed",
-                        PCILYNX_MAJOR);
-                return -EBUSY;
-        }
-#endif
-
         ret = pci_register_driver(&lynx_pci_driver);
         if (ret < 0) {
                 PRINT_G(KERN_ERR, "PCI module init failed");
-                goto free_char_dev;
+                return ret;
         }
 
         return 0;
-
- free_char_dev:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
-
-        return ret;
 }
 
 static void __exit pcilynx_cleanup(void)
 {
         pci_unregister_driver(&lynx_pci_driver);
-
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
 }
 
 
index 644ec55d3d469b945b68f3cd51fae5651509b875..d631aa8383ada2311102469f6fb545fce1e88b70 100644 (file)
@@ -55,16 +55,6 @@ struct ti_lynx {
         void __iomem *aux_port;
        quadlet_t bus_info_block[5];
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        atomic_t aux_intr_seen;
-        wait_queue_head_t aux_intr_wait;
-
-        void *mem_dma_buffer;
-        dma_addr_t mem_dma_buffer_dma;
-        struct semaphore mem_dma_mutex;
-        wait_queue_head_t mem_dma_intr_wait;
-#endif
-
         /*
          * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
          * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
@@ -72,11 +62,9 @@ struct ti_lynx {
          */
         u8 pcl_bmap[LOCALRAM_SIZE / 1024];
 
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
        /* point to PCLs memory area if needed */
        void *pcl_mem;
         dma_addr_t pcl_mem_dma;
-#endif
 
         /* PCLs for local mem / aux transfers */
         pcl_t dmem_pcl;
@@ -378,39 +366,6 @@ struct ti_pcl {
 #define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
 
 
-#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM
-
-static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           const struct ti_pcl *pcl)
-{
-        int i;
-        u32 *in = (u32 *)pcl;
-        u32 *out = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl));
-
-        for (i = 0; i < 32; i++, out++, in++) {
-                writel(*in, out);
-        }
-}
-
-static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           struct ti_pcl *pcl)
-{
-        int i;
-        u32 *out = (u32 *)pcl;
-        u32 *in = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl));
-
-        for (i = 0; i < 32; i++, out++, in++) {
-                *out = readl(in);
-        }
-}
-
-static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
-{
-        return pci_resource_start(lynx->dev, 1) + pclid * sizeof(struct ti_pcl);
-}
-
-#else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
-
 static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
                            const struct ti_pcl *pcl)
 {
@@ -431,10 +386,8 @@ static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
         return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
 }
 
-#endif /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
-
 
-#if defined (CONFIG_IEEE1394_PCILYNX_LOCALRAM) || defined (__BIG_ENDIAN)
+#if defined (__BIG_ENDIAN)
 typedef struct ti_pcl pcltmp_t;
 
 static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
index 4bedf7113f407e56bc1e509e255eab669cc2fe27..d68c4658f2fc1d11b10efed4f0269e56514bbf95 100644 (file)
  *
  */
 
+/* Markus Tavenrath <speedygoo@speedygoo.de> :
+   - fixed checks for valid buffer-numbers in video1394_icotl
+   - changed the ways the dma prg's are used, now it's possible to use
+     even a single dma buffer
+*/
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -112,6 +117,7 @@ struct dma_iso_ctx {
        struct it_dma_prg **it_prg;
 
        unsigned int *buffer_status;
+       unsigned int *buffer_prg_assignment;
         struct timeval *buffer_time; /* time when the buffer was received */
        unsigned int *last_used_cmd; /* For ISO Transmit with
                                        variable sized packets only ! */
@@ -180,23 +186,14 @@ static int free_dma_iso_ctx(struct dma_iso_ctx *d)
                kfree(d->prg_reg);
        }
 
-       if (d->ir_prg)
-               kfree(d->ir_prg);
-
-       if (d->it_prg)
-               kfree(d->it_prg);
-
-       if (d->buffer_status)
-               kfree(d->buffer_status);
-       if (d->buffer_time)
-               kfree(d->buffer_time);
-       if (d->last_used_cmd)
-               kfree(d->last_used_cmd);
-       if (d->next_buffer)
-               kfree(d->next_buffer);
-
+       kfree(d->ir_prg);
+       kfree(d->it_prg);
+       kfree(d->buffer_status);
+       kfree(d->buffer_prg_assignment);
+       kfree(d->buffer_time);
+       kfree(d->last_used_cmd);
+       kfree(d->next_buffer);
        list_del(&d->link);
-
        kfree(d);
 
        return 0;
@@ -230,7 +227,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
        /* Init the regions for easy cleanup */
        dma_region_init(&d->dma);
 
-       if (dma_region_alloc(&d->dma, d->num_desc * d->buf_size, ohci->dev,
+       if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev,
                             PCI_DMA_BIDIRECTIONAL)) {
                PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer");
                free_dma_iso_ctx(d);
@@ -342,6 +339,8 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
 
        d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int),
                                   GFP_KERNEL);
+       d->buffer_prg_assignment = kmalloc(d->num_desc * sizeof(unsigned int),
+                                  GFP_KERNEL);
        d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval),
                                   GFP_KERNEL);
        d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int),
@@ -354,6 +353,11 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
                free_dma_iso_ctx(d);
                return NULL;
        }
+       if (d->buffer_prg_assignment == NULL) {
+               PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_prg_assignment");
+               free_dma_iso_ctx(d);
+               return NULL;
+       }
        if (d->buffer_time == NULL) {
                PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_time");
                free_dma_iso_ctx(d);
@@ -370,6 +374,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
                return NULL;
        }
        memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
+       memset(d->buffer_prg_assignment, 0, d->num_desc * sizeof(unsigned int));
        memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval));
        memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int));
        memset(d->next_buffer, -1, d->num_desc * sizeof(int));
@@ -379,7 +384,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
        PRINT(KERN_INFO, ohci->host->id, "Iso %s DMA: %d buffers "
              "of size %d allocated for a frame size %d, each with %d prgs",
              (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
-             d->num_desc, d->buf_size, d->frame_size, d->nb_cmd);
+             d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd);
 
        return d;
 }
@@ -394,11 +399,36 @@ static void reset_ir_status(struct dma_iso_ctx *d, int n)
        d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
 }
 
+static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags)
+{
+       struct dma_cmd *ir_prg = d->ir_prg[n];
+       unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
+       int i;
+
+       d->buffer_prg_assignment[n] = buffer;
+
+       ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
+                               (unsigned long)d->dma.kvirt));
+       ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+                               (buf + 4) - (unsigned long)d->dma.kvirt));
+
+       for (i=2;i<d->nb_cmd-1;i++) {
+               ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+                                               (buf+(i-1)*PAGE_SIZE) -
+                                               (unsigned long)d->dma.kvirt));
+       }
+
+       ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
+                                 DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
+       ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+                                 (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt));
+}
+
 static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
 {
        struct dma_cmd *ir_prg = d->ir_prg[n];
        struct dma_prog_region *ir_reg = &d->prg_reg[n];
-       unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size;
+       unsigned long buf = (unsigned long)d->dma.kvirt;
        int i;
 
        /* the first descriptor will read only 4 bytes */
@@ -508,7 +538,7 @@ static void wakeup_dma_ir_ctx(unsigned long l)
        for (i = 0; i < d->num_desc; i++) {
                if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
                        reset_ir_status(d, i);
-                       d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+                       d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
                        do_gettimeofday(&d->buffer_time[i]);
                }
        }
@@ -585,7 +615,7 @@ static void wakeup_dma_it_ctx(unsigned long l)
                        int next = d->next_buffer[i];
                        put_timestamp(ohci, d, next);
                        d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
-                       d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+                       d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
                }
        }
 
@@ -595,11 +625,25 @@ static void wakeup_dma_it_ctx(unsigned long l)
                wake_up_interruptible(&d->waitq);
 }
 
+static void reprogram_dma_it_prg(struct dma_iso_ctx  *d, int n, int buffer)
+{
+       struct it_dma_prg *it_prg = d->it_prg[n];
+       unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
+       int i;
+
+       d->buffer_prg_assignment[n] = buffer;
+       for (i=0;i<d->nb_cmd;i++) {
+         it_prg[i].end.address =
+               cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+                       (buf+i*d->packet_size) - (unsigned long)d->dma.kvirt));
+       }
+}
+
 static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
 {
        struct it_dma_prg *it_prg = d->it_prg[n];
        struct dma_prog_region *it_reg = &d->prg_reg[n];
-       unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size;
+       unsigned long buf = (unsigned long)d->dma.kvirt;
        int i;
        d->last_used_cmd[n] = d->nb_cmd - 1;
        for (i=0;i<d->nb_cmd;i++) {
@@ -796,7 +840,7 @@ static int __video1394_ioctl(struct file *file,
 
                if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
                        d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
-                                             v.nb_buffers, v.buf_size,
+                                             v.nb_buffers + 1, v.buf_size,
                                              v.channel, 0);
 
                        if (d == NULL) {
@@ -817,7 +861,7 @@ static int __video1394_ioctl(struct file *file,
                }
                else {
                        d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
-                                             v.nb_buffers, v.buf_size,
+                                             v.nb_buffers + 1, v.buf_size,
                                              v.channel, v.packet_size);
 
                        if (d == NULL) {
@@ -889,6 +933,7 @@ static int __video1394_ioctl(struct file *file,
        {
                struct video1394_wait v;
                struct dma_iso_ctx *d;
+               int next_prg;
 
                if (copy_from_user(&v, argp, sizeof(v)))
                        return -EFAULT;
@@ -896,7 +941,7 @@ static int __video1394_ioctl(struct file *file,
                d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
                if (d == NULL) return -EFAULT;
 
-               if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+               if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) {
                        PRINT(KERN_ERR, ohci->host->id,
                              "Buffer %d out of range",v.buffer);
                        return -EINVAL;
@@ -913,12 +958,14 @@ static int __video1394_ioctl(struct file *file,
 
                d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
 
+               next_prg = (d->last_buffer + 1) % d->num_desc;
                if (d->last_buffer>=0)
                        d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
-                               cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0)
+                               cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0)
                                        & 0xfffffff0) | 0x1);
 
-               d->last_buffer = v.buffer;
+               d->last_buffer = next_prg;
+               reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags);
 
                d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
 
@@ -930,7 +977,7 @@ static int __video1394_ioctl(struct file *file,
 
                        /* Tell the controller where the first program is */
                        reg_write(ohci, d->cmdPtr,
-                               dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x1);
+                                 dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1);
 
                        /* Run IR context */
                        reg_write(ohci, d->ctrlSet, 0x8000);
@@ -951,7 +998,7 @@ static int __video1394_ioctl(struct file *file,
        {
                struct video1394_wait v;
                struct dma_iso_ctx *d;
-               int i;
+               int i = 0;
 
                if (copy_from_user(&v, argp, sizeof(v)))
                        return -EFAULT;
@@ -959,7 +1006,7 @@ static int __video1394_ioctl(struct file *file,
                d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
                if (d == NULL) return -EFAULT;
 
-               if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+               if ((v.buffer<0) || (v.buffer>d->num_desc - 1)) {
                        PRINT(KERN_ERR, ohci->host->id,
                              "Buffer %d out of range",v.buffer);
                        return -EINVAL;
@@ -1005,9 +1052,9 @@ static int __video1394_ioctl(struct file *file,
                 * Look ahead to see how many more buffers have been received
                 */
                i=0;
-               while (d->buffer_status[(v.buffer+1)%d->num_desc]==
+               while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]==
                       VIDEO1394_BUFFER_READY) {
-                       v.buffer=(v.buffer+1)%d->num_desc;
+                       v.buffer=(v.buffer+1)%(d->num_desc - 1);
                        i++;
                }
                spin_unlock_irqrestore(&d->lock, flags);
@@ -1023,6 +1070,7 @@ static int __video1394_ioctl(struct file *file,
                struct video1394_wait v;
                unsigned int *psizes = NULL;
                struct dma_iso_ctx *d;
+               int next_prg;
 
                if (copy_from_user(&v, argp, sizeof(v)))
                        return -EFAULT;
@@ -1030,7 +1078,7 @@ static int __video1394_ioctl(struct file *file,
                d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
                if (d == NULL) return -EFAULT;
 
-               if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+               if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) {
                        PRINT(KERN_ERR, ohci->host->id,
                              "Buffer %d out of range",v.buffer);
                        return -EINVAL;
@@ -1056,19 +1104,19 @@ static int __video1394_ioctl(struct file *file,
 
                spin_lock_irqsave(&d->lock,flags);
 
+               // last_buffer is last_prg
+               next_prg = (d->last_buffer + 1) % d->num_desc;
                if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
                        PRINT(KERN_ERR, ohci->host->id,
                              "Buffer %d is already used",v.buffer);
                        spin_unlock_irqrestore(&d->lock,flags);
-                       if (psizes)
-                               kfree(psizes);
+                       kfree(psizes);
                        return -EBUSY;
                }
 
                if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
                        initialize_dma_it_prg_var_packet_queue(
-                               d, v.buffer, psizes,
-                               ohci);
+                               d, next_prg, psizes, ohci);
                }
 
                d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
@@ -1076,16 +1124,17 @@ static int __video1394_ioctl(struct file *file,
                if (d->last_buffer >= 0) {
                        d->it_prg[d->last_buffer]
                                [ d->last_used_cmd[d->last_buffer] ].end.branchAddress =
-                                       cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer],
+                                       cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
                                                0) & 0xfffffff0) | 0x3);
 
                        d->it_prg[d->last_buffer]
                                [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
-                                       cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer],
+                                       cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
                                                0) & 0xfffffff0) | 0x3);
-                       d->next_buffer[d->last_buffer] = v.buffer;
+                       d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1);
                }
-               d->last_buffer = v.buffer;
+               d->last_buffer = next_prg;
+               reprogram_dma_it_prg(d, d->last_buffer, v.buffer);
                d->next_buffer[d->last_buffer] = -1;
 
                d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0;
@@ -1100,7 +1149,7 @@ static int __video1394_ioctl(struct file *file,
 
                        /* Tell the controller where the first program is */
                        reg_write(ohci, d->cmdPtr,
-                               dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x3);
+                               dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3);
 
                        /* Run IT context */
                        reg_write(ohci, d->ctrlSet, 0x8000);
@@ -1116,9 +1165,7 @@ static int __video1394_ioctl(struct file *file,
                        }
                }
 
-               if (psizes)
-                       kfree(psizes);
-
+               kfree(psizes);
                return 0;
 
        }
@@ -1133,7 +1180,7 @@ static int __video1394_ioctl(struct file *file,
                d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
                if (d == NULL) return -EFAULT;
 
-               if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+               if ((v.buffer<0) || (v.buffer>=d->num_desc-1)) {
                        PRINT(KERN_ERR, ohci->host->id,
                              "Buffer %d out of range",v.buffer);
                        return -EINVAL;
index ff66ed4ee2cd0d77a0123560b854ca9f8bfc8368..79c332f16fc70c8cea2b18e27d9ebbca3856accb 100644 (file)
@@ -465,8 +465,10 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
                        if (atkbd->softrepeat) return 0;
 
                        i = j = 0;
-                       while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++;
-                       while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++;
+                       while (i < 31 && period[i] < dev->rep[REP_PERIOD])
+                               i++;
+                       while (j < 3 && delay[j] < dev->rep[REP_DELAY])
+                               j++;
                        dev->rep[REP_PERIOD] = period[i];
                        dev->rep[REP_DELAY] = delay[j];
                        param[0] = i | (j << 5);
index 1f85a9718c89847e16053c1cae1614cd4e16a439..42a9f7f6f8cb2a9b31e65404959dfbb1305be942 100644 (file)
@@ -341,6 +341,8 @@ static int alps_reconnect(struct psmouse *psmouse)
        unsigned char param[4];
        int version;
 
+       psmouse_reset(psmouse);
+
        if (!(priv->i = alps_get_model(psmouse, &version)))
                return -1;
 
@@ -395,7 +397,7 @@ int alps_init(struct psmouse *psmouse)
        }
 
        if (param[0] & 0x04) {
-               printk(KERN_INFO "  Enabling hardware tapping\n");
+               printk(KERN_INFO "alps.c: Enabling hardware tapping\n");
                if (alps_tap_mode(psmouse, 1))
                        printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
        }
index 3313e2daeab022dc1d391ddc19be97bd23b286b7..0beacb77ee18372585282a5aab58b04f06a615a9 100644 (file)
@@ -388,6 +388,24 @@ static ssize_t serio_show_id_extra(struct device *dev, char *buf)
        return sprintf(buf, "%02x\n", serio->id.extra);
 }
 
+static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL);
+static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL);
+static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL);
+static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL);
+
+static struct attribute *serio_device_id_attrs[] = {
+       &dev_attr_type.attr,
+       &dev_attr_proto.attr,
+       &dev_attr_id.attr,
+       &dev_attr_extra.attr,
+       NULL
+};
+
+static struct attribute_group serio_id_attr_group = {
+       .name   = "id",
+       .attrs  = serio_device_id_attrs,
+};
+
 static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
 {
        struct serio *serio = to_serio_port(dev);
@@ -444,10 +462,6 @@ static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t c
 
 static struct device_attribute serio_device_attrs[] = {
        __ATTR(description, S_IRUGO, serio_show_description, NULL),
-       __ATTR(id_type, S_IRUGO, serio_show_id_type, NULL),
-       __ATTR(id_proto, S_IRUGO, serio_show_id_proto, NULL),
-       __ATTR(id_id, S_IRUGO, serio_show_id_id, NULL),
-       __ATTR(id_extra, S_IRUGO, serio_show_id_extra, NULL),
        __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
        __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
        __ATTR_NULL
@@ -498,6 +512,7 @@ static void serio_add_port(struct serio *serio)
        if (serio->start)
                serio->start(serio);
        device_add(&serio->dev);
+       sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
        serio->registered = 1;
 }
 
@@ -526,6 +541,7 @@ static void serio_destroy_port(struct serio *serio)
        }
 
        if (serio->registered) {
+               sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
                device_del(&serio->dev);
                list_del_init(&serio->node);
                serio->registered = 0;
@@ -779,7 +795,6 @@ static int serio_resume(struct device *dev)
        struct serio *serio = to_serio_port(dev);
 
        if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
-               serio_disconnect_port(serio);
                /*
                 * Driver re-probing can take a while, so better let kseriod
                 * deal with it.
index 22f73683952bffaa99155e16f8a3bc666bb3e770..f6b85222ba3dc9033fff294d6f45e7cc2f6986e3 100644 (file)
@@ -27,11 +27,15 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_MOUSE);
 
 #define SERPORT_BUSY   1
+#define SERPORT_ACTIVE 2
+#define SERPORT_DEAD   3
 
 struct serport {
        struct tty_struct *tty;
        wait_queue_head_t wait;
        struct serio *serio;
+       struct serio_device_id id;
+       spinlock_t lock;
        unsigned long flags;
 };
 
@@ -45,11 +49,29 @@ static int serport_serio_write(struct serio *serio, unsigned char data)
        return -(serport->tty->driver->write(serport->tty, &data, 1) != 1);
 }
 
+static int serport_serio_open(struct serio *serio)
+{
+       struct serport *serport = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&serport->lock, flags);
+       set_bit(SERPORT_ACTIVE, &serport->flags);
+       spin_unlock_irqrestore(&serport->lock, flags);
+
+       return 0;
+}
+
+
 static void serport_serio_close(struct serio *serio)
 {
        struct serport *serport = serio->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&serport->lock, flags);
+       clear_bit(SERPORT_ACTIVE, &serport->flags);
+       set_bit(SERPORT_DEAD, &serport->flags);
+       spin_unlock_irqrestore(&serport->lock, flags);
 
-       serport->serio->id.type = 0;
        wake_up_interruptible(&serport->wait);
 }
 
@@ -61,36 +83,21 @@ static void serport_serio_close(struct serio *serio)
 static int serport_ldisc_open(struct tty_struct *tty)
 {
        struct serport *serport;
-       struct serio *serio;
-       char name[64];
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       serport = kmalloc(sizeof(struct serport), GFP_KERNEL);
-       serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
-       if (unlikely(!serport || !serio)) {
-               kfree(serport);
-               kfree(serio);
+       serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL);
+       if (!serport)
                return -ENOMEM;
-       }
 
-       memset(serport, 0, sizeof(struct serport));
-       serport->serio = serio;
-       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        serport->tty = tty;
-       tty->disc_data = serport;
-
-       memset(serio, 0, sizeof(struct serio));
-       strlcpy(serio->name, "Serial port", sizeof(serio->name));
-       snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
-       serio->id.type = SERIO_RS232;
-       serio->write = serport_serio_write;
-       serio->close = serport_serio_close;
-       serio->port_data = serport;
-
+       spin_lock_init(&serport->lock);
        init_waitqueue_head(&serport->wait);
 
+       tty->disc_data = serport;
+       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
        return 0;
 }
 
@@ -100,7 +107,8 @@ static int serport_ldisc_open(struct tty_struct *tty)
 
 static void serport_ldisc_close(struct tty_struct *tty)
 {
-       struct serport *serport = (struct serport*) tty->disc_data;
+       struct serport *serport = (struct serport *) tty->disc_data;
+
        kfree(serport);
 }
 
@@ -116,9 +124,19 @@ static void serport_ldisc_close(struct tty_struct *tty)
 static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
+       unsigned long flags;
        int i;
+
+       spin_lock_irqsave(&serport->lock, flags);
+
+       if (!test_bit(SERPORT_ACTIVE, &serport->flags))
+               goto out;
+
        for (i = 0; i < count; i++)
                serio_interrupt(serport->serio, cp[i], 0, NULL);
+
+out:
+       spin_unlock_irqrestore(&serport->lock, flags);
 }
 
 /*
@@ -141,16 +159,33 @@ static int serport_ldisc_room(struct tty_struct *tty)
 static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
+       struct serio *serio;
        char name[64];
 
        if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
                return -EBUSY;
 
+       serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL);
+       if (!serio)
+               return -ENOMEM;
+
+       strlcpy(serio->name, "Serial port", sizeof(serio->name));
+       snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
+       serio->id = serport->id;
+       serio->id.type = SERIO_RS232;
+       serio->write = serport_serio_write;
+       serio->open = serport_serio_open;
+       serio->close = serport_serio_close;
+       serio->port_data = serport;
+
        serio_register_port(serport->serio);
        printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
-       wait_event_interruptible(serport->wait, !serport->serio->id.type);
+
+       wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags));
        serio_unregister_port(serport->serio);
+       serport->serio = NULL;
 
+       clear_bit(SERPORT_DEAD, &serport->flags);
        clear_bit(SERPORT_BUSY, &serport->flags);
 
        return 0;
@@ -163,16 +198,15 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
 static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
-       struct serio *serio = serport->serio;
        unsigned long type;
 
        if (cmd == SPIOCSTYPE) {
                if (get_user(type, (unsigned long __user *) arg))
                        return -EFAULT;
 
-               serio->id.proto = type & 0x000000ff;
-               serio->id.id    = (type & 0x0000ff00) >> 8;
-               serio->id.extra = (type & 0x00ff0000) >> 16;
+               serport->id.proto = type & 0x000000ff;
+               serport->id.id    = (type & 0x0000ff00) >> 8;
+               serport->id.extra = (type & 0x00ff0000) >> 16;
 
                return 0;
        }
@@ -182,9 +216,13 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi
 
 static void serport_ldisc_write_wakeup(struct tty_struct * tty)
 {
-       struct serport *sp = (struct serport *) tty->disc_data;
+       struct serport *serport = (struct serport *) tty->disc_data;
+       unsigned long flags;
 
-       serio_drv_write_wakeup(sp->serio);
+       spin_lock_irqsave(&serport->lock, flags);
+       if (test_bit(SERPORT_ACTIVE, &serport->flags))
+               serio_drv_write_wakeup(serport->serio);
+       spin_unlock_irqrestore(&serport->lock, flags);
 }
 
 /*
index 161e9aa872917da3cc3bb2cc4719850317e7b9e1..b1941b887f46fd6f7f5a991cbb969778ecd31c61 100644 (file)
@@ -269,9 +269,8 @@ static int linear_make_request (request_queue_t *q, struct bio *bio)
                 * split it.
                 */
                struct bio_pair *bp;
-               bp = bio_split(bio, bio_split_pool, 
-                              (bio->bi_sector + (bio->bi_size >> 9) -
-                               (tmp_dev->offset + tmp_dev->size))<<1);
+               bp = bio_split(bio, bio_split_pool,
+                              ((tmp_dev->offset + tmp_dev->size)<<1) - bio->bi_sector);
                if (linear_make_request(q, &bp->bio1))
                        generic_make_request(&bp->bio1);
                if (linear_make_request(q, &bp->bio2))
index 4e4bfde3db5db8baadd5fe0242f018990970715c..2ae2d709cb1582256699b7c915436a2476129966 100644 (file)
@@ -462,10 +462,6 @@ static int multipath_run (mddev_t *mddev)
        }
        memset(conf->multipaths, 0, sizeof(struct multipath_info)*mddev->raid_disks);
 
-       mddev->queue->unplug_fn = multipath_unplug;
-
-       mddev->queue->issue_flush_fn = multipath_issue_flush;
-
        conf->working_disks = 0;
        ITERATE_RDEV(mddev,rdev,tmp) {
                disk_idx = rdev->raid_disk;
@@ -528,6 +524,10 @@ static int multipath_run (mddev_t *mddev)
         * Ok, everything is just fine now
         */
        mddev->array_size = mddev->size;
+
+       mddev->queue->unplug_fn = multipath_unplug;
+       mddev->queue->issue_flush_fn = multipath_issue_flush;
+
        return 0;
 
 out_free_conf:
index 83380b5d6593d25531a178a9aa29db17169f3a5e..1db5de52d37665e2ec1aa28c2f8678a5565fbb84 100644 (file)
@@ -1197,10 +1197,6 @@ static int run(mddev_t *mddev)
        if (!conf->r1bio_pool)
                goto out_no_mem;
 
-       mddev->queue->unplug_fn = raid1_unplug;
-
-       mddev->queue->issue_flush_fn = raid1_issue_flush;
-
        ITERATE_RDEV(mddev, rdev, tmp) {
                disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
@@ -1282,6 +1278,9 @@ static int run(mddev_t *mddev)
         */
        mddev->array_size = mddev->size;
 
+       mddev->queue->unplug_fn = raid1_unplug;
+       mddev->queue->issue_flush_fn = raid1_issue_flush;
+
        return 0;
 
 out_no_mem:
index e9dc2876a6269be27b0f726b83e468545be4be88..3c37be6423d75a1a576cd545d80c0d76e25a246e 100644 (file)
@@ -1639,9 +1639,6 @@ static int run(mddev_t *mddev)
                        mdname(mddev));
                goto out_free_conf;
        }
-       mddev->queue->unplug_fn = raid10_unplug;
-
-       mddev->queue->issue_flush_fn = raid10_issue_flush;
 
        ITERATE_RDEV(mddev, rdev, tmp) {
                disk_idx = rdev->raid_disk;
@@ -1713,6 +1710,9 @@ static int run(mddev_t *mddev)
        mddev->array_size = size/2;
        mddev->resync_max_sectors = size;
 
+       mddev->queue->unplug_fn = raid10_unplug;
+       mddev->queue->issue_flush_fn = raid10_issue_flush;
+
        /* Calculate max read-ahead size.
         * We need to readahead at least twice a whole stripe....
         * maybe...
index e96e2a10a9c96e53ebb63d562d951bba0258a380..3cb11ac232fa8ca9ada29fb9cdb99e15cf1ba0f2 100644 (file)
@@ -1620,9 +1620,6 @@ static int run (mddev_t *mddev)
        atomic_set(&conf->active_stripes, 0);
        atomic_set(&conf->preread_active_stripes, 0);
 
-       mddev->queue->unplug_fn = raid5_unplug_device;
-       mddev->queue->issue_flush_fn = raid5_issue_flush;
-
        PRINTK("raid5: run(%s) called.\n", mdname(mddev));
 
        ITERATE_RDEV(mddev,rdev,tmp) {
@@ -1728,6 +1725,10 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
        }
 
        /* Ok, everything is just fine now */
+
+       mddev->queue->unplug_fn = raid5_unplug_device;
+       mddev->queue->issue_flush_fn = raid5_issue_flush;
+
        mddev->array_size =  mddev->size * (mddev->raid_disks - 1);
        return 0;
 abort:
index 8a33f351e0920f3cd4d4189b86bae39b4462e593..908edd78a792b35740844a5048f507cb13f1285b 100644 (file)
@@ -1779,9 +1779,6 @@ static int run (mddev_t *mddev)
        atomic_set(&conf->active_stripes, 0);
        atomic_set(&conf->preread_active_stripes, 0);
 
-       mddev->queue->unplug_fn = raid6_unplug_device;
-       mddev->queue->issue_flush_fn = raid6_issue_flush;
-
        PRINTK("raid6: run(%s) called.\n", mdname(mddev));
 
        ITERATE_RDEV(mddev,rdev,tmp) {
@@ -1895,6 +1892,9 @@ static int run (mddev_t *mddev)
 
        /* Ok, everything is just fine now */
        mddev->array_size =  mddev->size * (mddev->raid_disks - 2);
+
+       mddev->queue->unplug_fn = raid6_unplug_device;
+       mddev->queue->issue_flush_fn = raid6_issue_flush;
        return 0;
 abort:
        if (conf) {
index 9f6c19ac1285354c60b024197bd65ac932f2ce6d..50e8b865401883331741896bea4eae2afc739f99 100644 (file)
@@ -23,9 +23,9 @@
 LIST_HEAD(saa7146_devices);
 DECLARE_MUTEX(saa7146_devices_lock);
 
-static int saa7146_num = 0;
+static int saa7146_num;
 
-unsigned int saa7146_debug = 0;
+unsigned int saa7146_debug;
 
 module_param(saa7146_debug, int, 0644);
 MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
index 883ec08490f417e59a36df2cc15cf37469bed49d..4983e1b1bb1d2a7ac137f56d65365544c4fbb791 100644 (file)
@@ -33,7 +33,7 @@ source "drivers/media/dvb/dibusb/Kconfig"
 source "drivers/media/dvb/cinergyT2/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
-       depends on DVB_CORE && PCI
+       depends on DVB_CORE && (PCI || USB)
 source "drivers/media/dvb/b2c2/Kconfig"
 
 comment "Supported BT878 Adapters"
index 52596907a0be59c09e32f6f52c04010fd3fddbc9..99bd675df955ba49c61041ec35e379f75e907d76 100644 (file)
@@ -1,26 +1,50 @@
-config DVB_B2C2_SKYSTAR
-       tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
-       depends on DVB_CORE && PCI
+config DVB_B2C2_FLEXCOP
+       tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
+       depends on DVB_CORE
        select DVB_STV0299
        select DVB_MT352
        select DVB_MT312
        select DVB_NXT2002
+       select DVB_STV0297
        help
-         Support for the Skystar2 PCI DVB card by Technisat, which
-         is equipped with the FlexCopII chipset by B2C2, and
-         for the B2C2/BBTI Air2PC-ATSC card.
+         Support for the digital TV receiver chip made by B2C2 Inc. included in
+         Technisats PCI cards and USB boxes.
 
          Say Y if you own such a device and want to use it.
 
-config DVB_B2C2_USB
-       tristate "B2C2/Technisat Air/Sky/Cable2PC USB"
-       depends on DVB_CORE && USB && EXPERIMENTAL
+config DVB_B2C2_FLEXCOP_PCI
+       tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
+       depends on DVB_B2C2_FLEXCOP && PCI
+       help
+         Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
+
+         Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_USB
+       tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
+       depends on DVB_B2C2_FLEXCOP && USB
+       help
+         Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
+
+         Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_DEBUG
+       bool "Enable debug for the B2C2 FlexCop drivers"
+       depends on DVB_B2C2_FLEXCOP
+       help
+         Say Y if you want to enable the module option to control debug messages
+         of all B2C2 FlexCop drivers.
+
+config DVB_B2C2_SKYSTAR
+       tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
+       depends on DVB_CORE && PCI
        select DVB_STV0299
        select DVB_MT352
+       select DVB_MT312
+       select DVB_NXT2002
        help
-         Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently
-         the does nothing, but providing basic function for the used usb 
-         protocol.
+         Support for the Skystar2 PCI DVB card by Technisat, which
+         is equipped with the FlexCopII chipset by B2C2, and
+         for the B2C2/BBTI Air2PC-ATSC card.
 
          Say Y if you own such a device and want to use it.
-
index 9fb1247bfab88db84427d28429f3b4bc3ad469a2..7703812af34f9f9001de8fcb9820bf83350e4a53 100644 (file)
@@ -1,6 +1,14 @@
-obj-b2c2-usb = b2c2-usb-core.o b2c2-common.o
+b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
+       flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o \
+       flexcop-dma.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
+
+b2c2-flexcop-pci-objs = flexcop-pci.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
+
+b2c2-flexcop-usb-objs = flexcop-usb.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
 obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
-obj-$(CONFIG_DVB_B2C2_USB) + = b2c2-usb.o
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/b2c2-common.c b/drivers/media/dvb/b2c2/b2c2-common.c
deleted file mode 100644 (file)
index 000d60c..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * b2c2-common.c - common methods for the B2C2/Technisat SkyStar2 PCI DVB card and
- *                 for the B2C2/Technisat Sky/Cable/AirStar USB devices
- *                 based on the FlexCopII/FlexCopIII by B2C2, Inc.
- *
- * Copyright (C) 2003  Vadim Catana, skystar@moldova.cc
- *
- * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
- * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
- *     Vincenzo Di Massa, hawk.it at tiscalinet.it
- *
- * Converted to Linux coding style
- * Misc reorganization, polishing, restyling
- *     Roberto Ragusa, r.ragusa at libero.it
- *
- * Added hardware filtering support,
- *     Niklas Peinecke, peinecke at gdv.uni-hannover.de
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- */
-#include "stv0299.h"
-#include "mt352.h"
-#include "mt312.h"
-
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
-       u8 aclk = 0;
-       u8 bclk = 0;
-
-       if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-       else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-       else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-       else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-       else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-       else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-       stv0299_writereg (fe, 0x13, aclk);
-       stv0299_writereg (fe, 0x14, bclk);
-       stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-       stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-       stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
-
-       return 0;
-}
-
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
-       u8 buf[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-//     struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-       div = params->frequency / 125;
-
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = div & 0xff;
-       buf[2] = 0x84;  // 0xC4
-       buf[3] = 0x08;
-
-       if (params->frequency < 1500000) buf[3] |= 0x10;
-
-//     if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
-       return 0;
-}
-
-static u8 samsung_tbmu24112_inittab[] = {
-            0x01, 0x15,
-            0x02, 0x30,
-            0x03, 0x00,
-            0x04, 0x7D,
-            0x05, 0x35,
-            0x06, 0x02,
-            0x07, 0x00,
-            0x08, 0xC3,
-            0x0C, 0x00,
-            0x0D, 0x81,
-            0x0E, 0x23,
-            0x0F, 0x12,
-            0x10, 0x7E,
-            0x11, 0x84,
-            0x12, 0xB9,
-            0x13, 0x88,
-            0x14, 0x89,
-            0x15, 0xC9,
-            0x16, 0x00,
-            0x17, 0x5C,
-            0x18, 0x00,
-            0x19, 0x00,
-            0x1A, 0x00,
-            0x1C, 0x00,
-            0x1D, 0x00,
-            0x1E, 0x00,
-            0x1F, 0x3A,
-            0x20, 0x2E,
-            0x21, 0x80,
-            0x22, 0xFF,
-            0x23, 0xC1,
-            0x28, 0x00,
-            0x29, 0x1E,
-            0x2A, 0x14,
-            0x2B, 0x0F,
-            0x2C, 0x09,
-            0x2D, 0x05,
-            0x31, 0x1F,
-            0x32, 0x19,
-            0x33, 0xFE,
-            0x34, 0x93,
-            0xff, 0xff,
-};
-
-static struct stv0299_config samsung_tbmu24112_config = {
-       .demod_address = 0x68,
-       .inittab = samsung_tbmu24112_inittab,
-       .mclk = 88000000UL,
-       .invert = 0,
-       .enhanced_tuning = 0,
-       .skip_reinit = 0,
-       .lock_output = STV0229_LOCKOUTPUT_LK,
-       .volt13_op0_op1 = STV0299_VOLT13_OP1,
-       .min_delay_ms = 100,
-       .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
-       .pll_set = samsung_tbmu24112_pll_set,
-};
-
-
-
-
-
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
-{
-       static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d };
-       static u8 mt352_reset [] = { 0x50, 0x80 };
-       static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-       static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
-       static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
-       mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-       udelay(2000);
-       mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-       mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
-       mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-       mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
-       return 0;
-}
-
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
-{
-       u32 div;
-       unsigned char bs = 0;
-
-       #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-       if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
-       if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
-       if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
-
-       pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
-       pllbuf[1] = div >> 8;
-       pllbuf[2] = div & 0xff;
-       pllbuf[3] = 0xcc;
-       pllbuf[4] = bs;
-
-       return 0;
-}
-
-static struct mt352_config samsung_tdtc9251dh0_config = {
-
-       .demod_address = 0x0f,
-       .demod_init = samsung_tdtc9251dh0_demod_init,
-       .pll_set = samsung_tdtc9251dh0_pll_set,
-};
-
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
-       u8 buf[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-//     struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-       div = (params->frequency + (125/2)) / 125;
-
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = (div >> 0) & 0xff;
-       buf[2] = 0x84 | ((div >> 10) & 0x60);
-       buf[3] = 0x80;
-
-       if (params->frequency < 1550000)
-               buf[3] |= 0x02;
-
-       //if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
-       return 0;
-}
-
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
-       .demod_address = 0x0e,
-       .pll_set = skystar23_samsung_tbdu18132_pll_set,
-};
diff --git a/drivers/media/dvb/b2c2/b2c2-usb-core.c b/drivers/media/dvb/b2c2/b2c2-usb-core.c
deleted file mode 100644 (file)
index 9306da0..0000000
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * Copyright (C) 2004 Patrick Boettcher <patrick.boettcher@desy.de>,
- *                    Luca Bertagnolio <>,
- *
- * based on information provided by John Jurrius from BBTI, Inc.
- *
- *     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, version 2.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/usb.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/version.h>
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_filter.h"
-#include "dvb_net.h"
-#include "dvb_frontend.h"
-
-/* debug */
-#define dprintk(level,args...) \
-           do { if ((debug & level)) { printk(args); } } while (0)
-#define debug_dump(b,l) if (debug) {\
-       int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
-       for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
-       deb_xfer("\n");\
-}
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able)).");
-
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_ts(args...)   dprintk(0x02,args)
-#define deb_ctrl(args...) dprintk(0x04,args)
-
-/* Version information */
-#define DRIVER_VERSION "0.0"
-#define DRIVER_DESC "Driver for B2C2/Technisat Air/Cable/Sky-2-PC USB devices"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-/* transfer parameters */
-#define B2C2_USB_FRAMES_PER_ISO                4
-#define B2C2_USB_NUM_ISO_URB           4    /* TODO check out a good value */
-
-#define B2C2_USB_CTRL_PIPE_IN          usb_rcvctrlpipe(b2c2->udev,0)
-#define B2C2_USB_CTRL_PIPE_OUT         usb_sndctrlpipe(b2c2->udev,0)
-#define B2C2_USB_DATA_PIPE                     usb_rcvisocpipe(b2c2->udev,0x81)
-
-struct usb_b2c2_usb {
-       struct usb_device *udev;
-       struct usb_interface *uintf;
-
-       u8 *iso_buffer;
-       int buffer_size;
-       dma_addr_t iso_dma_handle;
-       struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
-};
-
-
-/*
- * USB
- * 10 90 34 12 78 56 04 00
- * usb_control_msg(udev, usb_sndctrlpipe(udev,0),
- * 0x90,
- * 0x10,
- * 0x1234,
- * 0x5678,
- * buf,
- * 4,
- * 5*HZ);
- *
- * extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
- * __u8 request,
- * __u8 requesttype,
- * __u16 value,
- * __u16 index,
- * void *data,
- * __u16 size,
- * int timeout);
- *
- */
-
-/* request types */
-typedef enum {
-
-/* something is wrong with this part
-       RTYPE_READ_DW         = (1 << 6),
-       RTYPE_WRITE_DW_1      = (3 << 6),
-       RTYPE_READ_V8_MEMORY  = (6 << 6),
-       RTYPE_WRITE_V8_MEMORY = (7 << 6),
-       RTYPE_WRITE_V8_FLASH  = (8 << 6),
-       RTYPE_GENERIC         = (9 << 6),
-*/
-       RTYPE_READ_DW = (3 << 6),
-       RTYPE_WRITE_DW_1 = (1 << 6),
-       
-       RTYPE_READ_V8_MEMORY  = (6 << 6),
-       RTYPE_WRITE_V8_MEMORY = (7 << 6),
-       RTYPE_WRITE_V8_FLASH  = (8 << 6),
-       RTYPE_GENERIC         = (9 << 6),
-} b2c2_usb_request_type_t;
-
-/* request */
-typedef enum {
-       B2C2_USB_WRITE_V8_MEM = 0x04,
-       B2C2_USB_READ_V8_MEM  = 0x05,
-       B2C2_USB_READ_REG     = 0x08,
-       B2C2_USB_WRITE_REG    = 0x0A,
-/*     B2C2_USB_WRITEREGLO   = 0x0A, */
-       B2C2_USB_WRITEREGHI   = 0x0B,
-       B2C2_USB_FLASH_BLOCK  = 0x10,
-       B2C2_USB_I2C_REQUEST  = 0x11,
-       B2C2_USB_UTILITY      = 0x12,
-} b2c2_usb_request_t;
-
-/* function definition for I2C_REQUEST */
-typedef enum {
-       USB_FUNC_I2C_WRITE       = 0x01,
-       USB_FUNC_I2C_MULTIWRITE  = 0x02,
-       USB_FUNC_I2C_READ        = 0x03,
-       USB_FUNC_I2C_REPEATWRITE = 0x04,
-       USB_FUNC_GET_DESCRIPTOR  = 0x05,
-       USB_FUNC_I2C_REPEATREAD  = 0x06,
-/* DKT 020208 - add this to support special case of DiSEqC */
-       USB_FUNC_I2C_CHECKWRITE  = 0x07,
-       USB_FUNC_I2C_CHECKRESULT = 0x08,
-} b2c2_usb_i2c_function_t;
-
-/*
- * function definition for UTILITY request 0x12
- * DKT 020304 - new utility function
- */
-typedef enum {
-       UTILITY_SET_FILTER          = 0x01,
-       UTILITY_DATA_ENABLE         = 0x02,
-       UTILITY_FLEX_MULTIWRITE     = 0x03,
-       UTILITY_SET_BUFFER_SIZE     = 0x04,
-       UTILITY_FLEX_OPERATOR       = 0x05,
-       UTILITY_FLEX_RESET300_START = 0x06,
-       UTILITY_FLEX_RESET300_STOP  = 0x07,
-       UTILITY_FLEX_RESET300       = 0x08,
-       UTILITY_SET_ISO_SIZE        = 0x09,
-       UTILITY_DATA_RESET          = 0x0A,
-       UTILITY_GET_DATA_STATUS     = 0x10,
-       UTILITY_GET_V8_REG          = 0x11,
-/* DKT 020326 - add function for v1.14 */
-       UTILITY_SRAM_WRITE          = 0x12,
-       UTILITY_SRAM_READ           = 0x13,
-       UTILITY_SRAM_TESTFILL       = 0x14,
-       UTILITY_SRAM_TESTSET        = 0x15,
-       UTILITY_SRAM_TESTVERIFY     = 0x16,
-} b2c2_usb_utility_function_t;
-
-#define B2C2_WAIT_FOR_OPERATION_RW  1  // 1 s
-#define B2C2_WAIT_FOR_OPERATION_RDW 3  // 3 s
-#define B2C2_WAIT_FOR_OPERATION_WDW 1  // 1 s
-
-#define B2C2_WAIT_FOR_OPERATION_V8READ   3  // 3 s
-#define B2C2_WAIT_FOR_OPERATION_V8WRITE  3  // 3 s
-#define B2C2_WAIT_FOR_OPERATION_V8FLASH  3  // 3 s
-
-/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
- * in the IBI address, to make the V8 code simpler.
- * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
- *                  in general: 0000 0HHH 000L LL00
- * IBI ADDRESS FORMAT:                    RHHH BLLL
- *
- * where R is the read(1)/write(0) bit, B is the busy bit
- * and HHH and LLL are the two sets of three bits from the PCI address.
- */
-#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
-#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
-
-/*
- * DKT 020228 - forget about this VENDOR_BUFFER_SIZE, read and write register
- * deal with DWORD or 4 bytes, that should be should from now on
- */
-static u32 b2c2_usb_read_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI)
-{
-       u32 val;
-       u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | 0x0080;
-       int len = usb_control_msg(b2c2->udev,
-                       B2C2_USB_CTRL_PIPE_IN,
-                       B2C2_USB_READ_REG,
-                       RTYPE_READ_DW,
-                       wAddress,
-                       0,
-                       &val,
-                       sizeof(u32),
-                       B2C2_WAIT_FOR_OPERATION_RDW * 1000);
-
-       if (len != sizeof(u32)) {
-               err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
-               return -EIO;
-       } else
-               return val;
-}
-
-/*
- * DKT 020228 - from now on, we don't support anything older than firm 1.00
- * I eliminated the write register as a 2 trip of writing hi word and lo word
- * and force this to write only 4 bytes at a time.
- * NOTE: this should work with all the firmware from 1.00 and newer
- */
-static int b2c2_usb_write_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI, u32 val)
-{
-       u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI);
-       int len = usb_control_msg(b2c2->udev,
-                       B2C2_USB_CTRL_PIPE_OUT,
-                       B2C2_USB_WRITE_REG,
-                       RTYPE_WRITE_DW_1,
-                       wAddress,
-                       0,
-                       &val,
-                       sizeof(u32),
-                       B2C2_WAIT_FOR_OPERATION_RDW * 1000);
-
-       if (len != sizeof(u32)) {
-               err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
-               return -EIO;
-       } else
-               return 0;
-}
-
-/*
- * DKT 010817 - add support for V8 memory read/write and flash update
- */
-static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb *b2c2,
-               b2c2_usb_request_t req, u8 page, u16 wAddress,
-               u16 buflen, u8 *pbBuffer)
-{
-       u8 dwRequestType;
-       u16 wIndex;
-       int nWaitTime,pipe,len;
-
-       wIndex = page << 8;
-
-       switch (req) {
-               case B2C2_USB_READ_V8_MEM:
-                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
-                       dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
-                       pipe = B2C2_USB_CTRL_PIPE_IN;
-               break;
-               case B2C2_USB_WRITE_V8_MEM:
-                       wIndex |= pbBuffer[0];
-                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
-                       dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
-                       pipe = B2C2_USB_CTRL_PIPE_OUT;
-               break;
-               case B2C2_USB_FLASH_BLOCK:
-                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
-                       dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
-                       pipe = B2C2_USB_CTRL_PIPE_OUT;
-               break;
-               default:
-                       deb_info("unsupported request for v8_mem_req %x.\n",req);
-               return -EINVAL;
-       }
-       len = usb_control_msg(b2c2->udev,pipe,
-                       req,
-                       dwRequestType,
-                       wAddress,
-                       wIndex,
-                       pbBuffer,
-                       buflen,
-                       nWaitTime * 1000);
-       return len == buflen ? 0 : -EIO;
-}
-
-static int b2c2_usb_i2c_req(struct usb_b2c2_usb *b2c2,
-               b2c2_usb_request_t req, b2c2_usb_i2c_function_t func,
-               u8 port, u8 chipaddr, u8 addr, u8 buflen, u8 *buf)
-{
-       u16 wValue, wIndex;
-       int nWaitTime,pipe,len;
-       u8 dwRequestType;
-
-       switch (func) {
-               case USB_FUNC_I2C_WRITE:
-               case USB_FUNC_I2C_MULTIWRITE:
-               case USB_FUNC_I2C_REPEATWRITE:
-               /* DKT 020208 - add this to support special case of DiSEqC */
-               case USB_FUNC_I2C_CHECKWRITE:
-                       pipe = B2C2_USB_CTRL_PIPE_OUT;
-                       nWaitTime = 2;
-                       dwRequestType = (u8) RTYPE_GENERIC;
-               break;
-               case USB_FUNC_I2C_READ:
-               case USB_FUNC_I2C_REPEATREAD:
-                       pipe = B2C2_USB_CTRL_PIPE_IN;
-                       nWaitTime = 2;
-                       dwRequestType = (u8) RTYPE_GENERIC;
-               break;
-               default:
-                       deb_info("unsupported function for i2c_req %x\n",func);
-                       return -EINVAL;
-       }
-       wValue = (func << 8 ) | port;
-       wIndex = (chipaddr << 8 ) | addr;
-
-       len = usb_control_msg(b2c2->udev,pipe,
-                       req,
-                       dwRequestType,
-                       addr,
-                       wIndex,
-                       buf,
-                       buflen,
-                       nWaitTime * 1000);
-       return len == buflen ? 0 : -EIO;
-}
-
-int static b2c2_usb_utility_req(struct usb_b2c2_usb *b2c2, int set,
-               b2c2_usb_utility_function_t func, u8 extra, u16 wIndex,
-               u16 buflen, u8 *pvBuffer)
-{
-       u16 wValue;
-       int nWaitTime = 2,
-               pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
-               len;
-
-       wValue = (func << 8) | extra;
-
-       len = usb_control_msg(b2c2->udev,pipe,
-                       B2C2_USB_UTILITY,
-                       (u8) RTYPE_GENERIC,
-                       wValue,
-                       wIndex,
-                       pvBuffer,
-                       buflen,
-                       nWaitTime * 1000);
-       return len == buflen ? 0 : -EIO;
-}
-
-
-
-static void b2c2_dumpfourreg(struct usb_b2c2_usb *b2c2, u16 offs)
-{
-       u32 r0,r1,r2,r3;
-       r0 = r1 = r2 = r3 = 0;
-       r0 = b2c2_usb_read_dw(b2c2,offs);
-       r1 = b2c2_usb_read_dw(b2c2,offs + 0x04);
-       r2 = b2c2_usb_read_dw(b2c2,offs + 0x08);
-       r3 = b2c2_usb_read_dw(b2c2,offs + 0x0c);
-       deb_ctrl("dump: offset: %03x, %08x, %08x, %08x, %08x\n",offs,r0,r1,r2,r3);
-}
-
-static void b2c2_urb_complete(struct urb *urb, struct pt_regs *ptregs)
-{
-       struct usb_b2c2_usb *b2c2 = urb->context;
-       deb_ts("urb completed, bufsize: %d\n",urb->transfer_buffer_length);
-
-//     urb_submit_urb(urb,GFP_ATOMIC); enable for real action
-}
-
-static void b2c2_exit_usb(struct usb_b2c2_usb *b2c2)
-{
-       int i;
-       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
-               if (b2c2->iso_urb[i] != NULL) { /* not sure about unlink_urb and iso-urbs TODO */
-                       deb_info("unlinking/killing urb no. %d\n",i);
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
-                       usb_unlink_urb(b2c2->iso_urb[i]);
-#else
-                       usb_kill_urb(b2c2->iso_urb[i]);
-#endif
-                       usb_free_urb(b2c2->iso_urb[i]);
-               }
-
-       if (b2c2->iso_buffer != NULL)
-               pci_free_consistent(NULL,b2c2->buffer_size, b2c2->iso_buffer, b2c2->iso_dma_handle);
-
-}
-
-static int b2c2_init_usb(struct usb_b2c2_usb *b2c2)
-{
-       u16 frame_size = le16_to_cpu(b2c2->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
-       int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
-       int buffer_offset = 0;
-
-       deb_info("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
-                       B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
-
-       b2c2->iso_buffer = pci_alloc_consistent(NULL,bufsize,&b2c2->iso_dma_handle);
-       if (b2c2->iso_buffer == NULL)
-               return -ENOMEM;
-       memset(b2c2->iso_buffer, 0, bufsize);
-       b2c2->buffer_size = bufsize;
-
-       /* creating iso urbs */
-       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
-               if (!(b2c2->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
-                       ret = -ENOMEM;
-                       goto urb_error;
-               }
-       /* initialising and submitting iso urbs */
-       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
-               int frame_offset = 0;
-               struct urb *urb = b2c2->iso_urb[i];
-               deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
-
-               urb->dev = b2c2->udev;
-               urb->context = b2c2;
-               urb->complete = b2c2_urb_complete;
-               urb->pipe = B2C2_USB_DATA_PIPE;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->interval = 1;
-               urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
-               urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
-               urb->transfer_buffer = b2c2->iso_buffer + buffer_offset;
-
-               buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
-               for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
-                       deb_info("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
-                       urb->iso_frame_desc[j].offset = frame_offset;
-                       urb->iso_frame_desc[j].length = frame_size;
-                       frame_offset += frame_size;
-               }
-
-               if ((ret = usb_submit_urb(b2c2->iso_urb[i],GFP_ATOMIC))) {
-                       err("submitting urb %d failed with %d.",i,ret);
-                       goto urb_error;
-               }
-               deb_info("submitted urb no. %d.\n",i);
-       }
-
-       ret = 0;
-       goto success;
-urb_error:
-       b2c2_exit_usb(b2c2);
-success:
-       return ret;
-}
-
-static int b2c2_usb_probe(struct usb_interface *intf,
-               const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct usb_b2c2_usb *b2c2 = NULL;
-       int ret;
-
-       b2c2 = kmalloc(sizeof(struct usb_b2c2_usb),GFP_KERNEL);
-       if (b2c2 == NULL) {
-               err("no memory");
-               return -ENOMEM;
-       }
-       b2c2->udev = udev;
-       b2c2->uintf = intf;
-
-       /* use the alternate setting with the larges buffer */
-       usb_set_interface(udev,0,1);
-
-       if ((ret = b2c2_init_usb(b2c2)))
-               goto usb_init_error;
-
-       usb_set_intfdata(intf,b2c2);
-
-       switch (udev->speed) {
-               case USB_SPEED_LOW:
-                       err("cannot handle USB speed because it is to sLOW.");
-                       break;
-               case USB_SPEED_FULL:
-                       info("running at FULL speed.");
-                       break;
-               case USB_SPEED_HIGH:
-                       info("running at HIGH speed.");
-                       break;
-               case USB_SPEED_UNKNOWN: /* fall through */
-               default:
-                       err("cannot handle USB speed because it is unkown.");
-               break;
-       }
-
-       b2c2_dumpfourreg(b2c2,0x200);
-       b2c2_dumpfourreg(b2c2,0x300);
-       b2c2_dumpfourreg(b2c2,0x400);
-       b2c2_dumpfourreg(b2c2,0x700);
-
-
-       if (ret == 0)
-               info("%s successfully initialized and connected.",DRIVER_DESC);
-       else
-               info("%s error while loading driver (%d)",DRIVER_DESC,ret);
-
-       ret = 0;
-       goto success;
-
-usb_init_error:
-       kfree(b2c2);
-success:
-       return ret;
-}
-
-static void b2c2_usb_disconnect(struct usb_interface *intf)
-{
-       struct usb_b2c2_usb *b2c2 = usb_get_intfdata(intf);
-       usb_set_intfdata(intf,NULL);
-       if (b2c2 != NULL) {
-               b2c2_exit_usb(b2c2);
-               kfree(b2c2);
-       }
-       info("%s successfully deinitialized and disconnected.",DRIVER_DESC);
-
-}
-
-static struct usb_device_id b2c2_usb_table [] = {
-           { USB_DEVICE(0x0af7, 0x0101) }
-};
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver b2c2_usb_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "dvb_b2c2_usb",
-       .probe          = b2c2_usb_probe,
-       .disconnect = b2c2_usb_disconnect,
-       .id_table       = b2c2_usb_table,
-};
-
-/* module stuff */
-static int __init b2c2_usb_init(void)
-{
-       int result;
-       if ((result = usb_register(&b2c2_usb_driver))) {
-               err("usb_register failed. Error number %d",result);
-               return result;
-       }
-
-       return 0;
-}
-
-static void __exit b2c2_usb_exit(void)
-{
-       /* deregister this driver from the USB subsystem */
-       usb_deregister(&b2c2_usb_driver);
-}
-
-module_init (b2c2_usb_init);
-module_exit (b2c2_usb_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, b2c2_usb_table);
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
new file mode 100644 (file)
index 0000000..773d158
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-common.h - common header file for device-specific source files also.
+ *
+ * see flexcop.c for copyright information.
+ */
+#ifndef __FLEXCOP_COMMON_H__
+#define __FLEXCOP_COMMON_H__
+
+#include <linux/config.h>
+#include <linux/pci.h>
+
+#include "flexcop-reg.h"
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+#define FC_MAX_FEED 256
+
+#ifndef FC_LOG_PREFIX
+#warning please define a log prefix for your file, using a default one
+#define FC_LOG_PREFIX "b2c2-undef"
+#endif
+
+/* Steal from usb.h */
+#undef err
+#define err(format,  arg...) printk(KERN_ERR     FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
+
+struct flexcop_dma {
+       struct pci_dev *pdev;
+
+       u8 *cpu_addr0;
+       dma_addr_t dma_addr0;
+       u8 *cpu_addr1;
+       dma_addr_t dma_addr1;
+       u32 size; /* size of each address in bytes */
+};
+
+/* Control structure for data definitions that are common to
+ * the B2C2-based PCI and USB devices.
+ */
+struct flexcop_device {
+       /* general */
+       struct device *dev; /* for firmware_class */
+
+#define FC_STATE_DVB_INIT 0x01
+#define FC_STATE_I2C_INIT 0x02
+#define FC_STATE_FE_INIT  0x04
+       int init_state;
+
+       /* device information */
+       int has_32_hw_pid_filter;
+       flexcop_revision_t rev;
+       flexcop_device_type_t dev_type;
+       flexcop_bus_t bus_type;
+
+       /* dvb stuff */
+       struct dvb_adapter dvb_adapter;
+       struct dvb_frontend *fe;
+       struct dvb_net dvbnet;
+       struct dvb_demux demux;
+       struct dmxdev dmxdev;
+       struct dmx_frontend hw_frontend;
+       struct dmx_frontend mem_frontend;
+       int (*fe_sleep) (struct dvb_frontend *);
+
+       struct i2c_adapter i2c_adap;
+       struct semaphore i2c_sem;
+
+       struct module *owner;
+
+       /* options and status */
+       int extra_feedcount;
+       int feedcount;
+       int pid_filtering;
+       int fullts_streaming_state;
+
+       /* bus specific callbacks */
+       flexcop_ibi_value (*read_ibi_reg)  (struct flexcop_device *, flexcop_ibi_register);
+       int               (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
+
+
+       int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+       int (*stream_control) (struct flexcop_device*, int);
+
+       int (*get_mac_addr) (struct flexcop_device *fc, int extended);
+
+       void *bus_specific;
+};
+
+/* exported prototypes */
+
+/* from flexcop.c */
+void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
+void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
+
+struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
+void flexcop_device_kfree(struct flexcop_device*);
+
+int  flexcop_device_initialize(struct flexcop_device*);
+void flexcop_device_exit(struct flexcop_device *fc);
+
+/* from flexcop-dma.c */
+int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
+void flexcop_dma_free(struct flexcop_dma *dma);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index);
+int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
+int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets);
+
+/* from flexcop-eeprom.c */
+/* the PCI part uses this call to get the MAC address, the USB part has its own */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
+
+/* from flexcop-i2c.c */
+/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
+ * one. We have it in flexcop-i2c.c, because it is going via the actual
+ * I2C-channel of the flexcop.
+ */
+int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t,
+                       flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+
+/* from flexcop-sram.c */
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
+void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
+void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill);
+
+/* global prototypes for the flexcop-chip */
+/* from flexcop-fe-tuner.c */
+int flexcop_frontend_init(struct flexcop_device *card);
+void flexcop_frontend_exit(struct flexcop_device *fc);
+
+/* from flexcop-i2c.c */
+int flexcop_i2c_init(struct flexcop_device *fc);
+void flexcop_i2c_exit(struct flexcop_device *fc);
+
+/* from flexcop-sram.c */
+int flexcop_sram_init(struct flexcop_device *fc);
+
+/* from flexcop-misc.c */
+void flexcop_determine_revision(struct flexcop_device *fc);
+void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
+
+/* from flexcop-hw-filter.c */
+int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
+void flexcop_hw_filter_init(struct flexcop_device *fc);
+
+void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
+
+void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
+void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff);
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
new file mode 100644 (file)
index 0000000..8d27060
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
+{
+       u8 *tcpu;
+       dma_addr_t tdma;
+
+       if (size % 2) {
+               err("dma buffersize has to be even.");
+               return -EINVAL;
+       }
+
+       if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
+               dma->pdev = pdev;
+               dma->cpu_addr0 = tcpu;
+               dma->dma_addr0 = tdma;
+               dma->cpu_addr1 = tcpu + size/2;
+               dma->dma_addr1 = tdma + size/2;
+               dma->size = size/2;
+               return 0;
+       }
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(flexcop_dma_allocate);
+
+void flexcop_dma_free(struct flexcop_dma *dma)
+{
+       pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0);
+       memset(dma,0,sizeof(struct flexcop_dma));
+}
+EXPORT_SYMBOL(flexcop_dma_free);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+       flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+       if (no & FC_DMA_1)
+               v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+
+       if (no & FC_DMA_2)
+               v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+
+       fc->write_ibi_reg(fc,ctrl_208,v);
+       return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+
+int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+       flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+       if (no & FC_DMA_1)
+               v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
+
+       if (no & FC_DMA_2)
+               v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
+
+       fc->write_ibi_reg(fc,ctrl_208,v);
+       return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_size_irq);
+
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+       flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+       if (no & FC_DMA_1)
+               v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+
+       if (no & FC_DMA_2)
+               v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+
+       fc->write_ibi_reg(fc,ctrl_208,v);
+       return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
+
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
+{
+
+       flexcop_ibi_value v0x0,v0x4,v0xc;
+       v0x0.raw = v0x4.raw = v0xc.raw = 0;
+
+       v0x0.dma_0x0.dma_address0        = dma->dma_addr0 >> 2;
+       v0xc.dma_0xc.dma_address1        = dma->dma_addr1 >> 2;
+       v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
+
+       if (index & FC_DMA_SUBADDR_0)
+               v0x0.dma_0x0.dma_0start = 1;
+
+       if (index & FC_DMA_SUBADDR_1)
+               v0xc.dma_0xc.dma_1start = 1;
+
+       if (dma_idx & FC_DMA_1) {
+               fc->write_ibi_reg(fc,dma1_000,v0x0);
+               fc->write_ibi_reg(fc,dma1_004,v0x4);
+               fc->write_ibi_reg(fc,dma1_00c,v0xc);
+       } else { /* (dma_idx & FC_DMA_2) */
+               fc->write_ibi_reg(fc,dma2_010,v0x0);
+               fc->write_ibi_reg(fc,dma2_014,v0x4);
+               fc->write_ibi_reg(fc,dma2_01c,v0xc);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config);
+
+static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
+{
+       flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
+       flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+       v.dma_0xc.remap_enable = onoff;
+       fc->write_ibi_reg(fc,r,v);
+       return 0;
+}
+
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
+{
+       flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+       flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+       flexcop_dma_remap(fc,dma_idx,0);
+
+       v.dma_0x4_write.dmatimer = cycles >> 1;
+       fc->write_ibi_reg(fc,r,v);
+       return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
+
+int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
+{
+       flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+       flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+       flexcop_dma_remap(fc,dma_idx,1);
+
+       v.dma_0x4_remap.DMA_maxpackets = packets;
+       fc->write_ibi_reg(fc,r,v);
+       return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_packet_count);
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c
new file mode 100644 (file)
index 0000000..bbcf070
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used)
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#if 0
+/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
+static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
+{
+       return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
+}
+
+static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
+{
+       int i;
+
+       for (i = 0; i < retries; i++) {
+               if (eeprom_write(adapter, addr, wbuf, len) == len) {
+                       if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+/* These functions could be used to unlock SkyStar2 cards. */
+
+static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
+{
+       u8 rbuf[20];
+       u8 wbuf[20];
+
+       if (len != 16)
+               return 0;
+
+       memcpy(wbuf, key, len);
+
+       wbuf[16] = 0;
+       wbuf[17] = 0;
+       wbuf[18] = 0;
+       wbuf[19] = calc_lrc(wbuf, 19);
+
+       return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
+}
+
+static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
+{
+       u8 buf[20];
+
+       if (len != 16)
+               return 0;
+
+       if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
+               return 0;
+
+       memcpy(key, buf, len);
+
+       return 1;
+}
+
+static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
+{
+       u8 tmp[8];
+
+       if (type != 0) {
+               tmp[0] = mac[0];
+               tmp[1] = mac[1];
+               tmp[2] = mac[2];
+               tmp[3] = mac[5];
+               tmp[4] = mac[6];
+               tmp[5] = mac[7];
+
+       } else {
+
+               tmp[0] = mac[0];
+               tmp[1] = mac[1];
+               tmp[2] = mac[2];
+               tmp[3] = mac[3];
+               tmp[4] = mac[4];
+               tmp[5] = mac[5];
+       }
+
+       tmp[6] = 0;
+       tmp[7] = calc_lrc(tmp, 7);
+
+       if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
+               return 1;
+
+       return 0;
+}
+
+static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len)
+{
+       return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
+}
+
+#endif
+
+static u8 calc_lrc(u8 *buf, int len)
+{
+       int i;
+       u8 sum = 0;
+       for (i = 0; i < len; i++)
+               sum = sum ^ buf[i];
+       return sum;
+}
+
+static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
+{
+       int i,ret = 0;
+       u8 chipaddr =  0x50 | ((addr >> 8) & 3);
+       for (i = 0; i < retries; i++)
+               if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0)
+                       break;
+       return ret;
+}
+
+static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
+{
+       int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries);
+       if (ret == 0)
+               if (calc_lrc(buf, len - 1) != buf[len - 1])
+                       ret = -EINVAL;
+       return ret;
+}
+
+/* JJ's comment about extended == 1: it is not presently used anywhere but was
+ * added to the low-level functions for possible support of EUI64
+ */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
+{
+       u8 buf[8];
+       int ret = 0;
+
+       if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
+               if (extended != 0) {
+                       err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
+                       ret = -EINVAL;
+/*                     memcpy(fc->dvb_adapter.proposed_mac,buf,3);
+                       mac[3] = 0xfe;
+                       mac[4] = 0xff;
+                       memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */
+               } else
+                       memcpy(fc->dvb_adapter.proposed_mac,buf,6);
+       }
+       return ret;
+}
+EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
new file mode 100644 (file)
index 0000000..71be400
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#include "stv0299.h"
+#include "mt352.h"
+#include "nxt2002.h"
+#include "stv0297.h"
+#include "mt312.h"
+
+/* lnb control */
+
+static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct flexcop_device *fc = fe->dvb->priv;
+       flexcop_ibi_value v;
+       deb_tuner("polarity/voltage = %u\n", voltage);
+
+       v = fc->read_ibi_reg(fc, misc_204);
+       switch (voltage) {
+               case SEC_VOLTAGE_OFF:
+                       v.misc_204.ACPI1_sig = 1;
+                       break;
+               case SEC_VOLTAGE_13:
+                       v.misc_204.ACPI1_sig = 0;
+                       v.misc_204.LNB_L_H_sig = 0;
+                       break;
+               case SEC_VOLTAGE_18:
+                       v.misc_204.ACPI1_sig = 0;
+                       v.misc_204.LNB_L_H_sig = 1;
+                       break;
+               default:
+                       err("unknown SEC_VOLTAGE value");
+                       return -EINVAL;
+       }
+       return fc->write_ibi_reg(fc, misc_204, v);
+}
+
+static int flexcop_sleep(struct dvb_frontend* fe)
+{
+       struct flexcop_device *fc = fe->dvb->priv;
+/*     flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
+
+       if (fc->fe_sleep)
+               return fc->fe_sleep(fe);
+
+/*     v.misc_204.ACPI3_sig = 1;
+       fc->write_ibi_reg(fc,misc_204,v);*/
+
+       return 0;
+}
+
+static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
+       struct flexcop_device *fc = fe->dvb->priv;
+       flexcop_ibi_value v;
+       u16 ax;
+       v.raw = 0;
+
+       deb_tuner("tone = %u\n",tone);
+
+       switch (tone) {
+               case SEC_TONE_ON:
+                       ax = 0x01ff;
+                       break;
+               case SEC_TONE_OFF:
+                       ax = 0;
+                       break;
+               default:
+                       err("unknown SEC_TONE value");
+                       return -EINVAL;
+       }
+
+       v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
+
+       v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
+       v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
+
+       return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
+}
+
+static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
+{
+       flexcop_set_tone(fe, SEC_TONE_ON);
+       udelay(data ? 500 : 1000);
+       flexcop_set_tone(fe, SEC_TONE_OFF);
+       udelay(data ? 1000 : 500);
+}
+
+static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
+{
+       int i, par = 1, d;
+
+       for (i = 7; i >= 0; i--) {
+               d = (data >> i) & 1;
+               par ^= d;
+               flexcop_diseqc_send_bit(fe, d);
+       }
+
+       flexcop_diseqc_send_bit(fe, par);
+}
+
+static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
+{
+       int i;
+
+       flexcop_set_tone(fe, SEC_TONE_OFF);
+       mdelay(16);
+
+       for (i = 0; i < len; i++)
+               flexcop_diseqc_send_byte(fe,msg[i]);
+
+       mdelay(16);
+
+       if (burst != -1) {
+               if (burst)
+                       flexcop_diseqc_send_byte(fe, 0xff);
+               else {
+                       flexcop_set_tone(fe, SEC_TONE_ON);
+                       udelay(12500);
+                       flexcop_set_tone(fe, SEC_TONE_OFF);
+               }
+               msleep(20);
+       }
+       return 0;
+}
+
+static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+       return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
+}
+
+static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+       return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
+}
+
+/* dvb-s stv0299 */
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+       u8 aclk = 0;
+       u8 bclk = 0;
+
+       if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+       else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+       else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+       else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+       else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+       else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+       stv0299_writereg (fe, 0x13, aclk);
+       stv0299_writereg (fe, 0x14, bclk);
+       stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+       stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
+       stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
+
+       return 0;
+}
+
+static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       struct flexcop_device *fc = fe->dvb->priv;
+
+       div = params->frequency / 125;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0x84;  /* 0xC4 */
+       buf[3] = 0x08;
+
+       if (params->frequency < 1500000) buf[3] |= 0x10;
+
+       if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static u8 samsung_tbmu24112_inittab[] = {
+            0x01, 0x15,
+            0x02, 0x30,
+            0x03, 0x00,
+            0x04, 0x7D,
+            0x05, 0x35,
+            0x06, 0x02,
+            0x07, 0x00,
+            0x08, 0xC3,
+            0x0C, 0x00,
+            0x0D, 0x81,
+            0x0E, 0x23,
+            0x0F, 0x12,
+            0x10, 0x7E,
+            0x11, 0x84,
+            0x12, 0xB9,
+            0x13, 0x88,
+            0x14, 0x89,
+            0x15, 0xC9,
+            0x16, 0x00,
+            0x17, 0x5C,
+            0x18, 0x00,
+            0x19, 0x00,
+            0x1A, 0x00,
+            0x1C, 0x00,
+            0x1D, 0x00,
+            0x1E, 0x00,
+            0x1F, 0x3A,
+            0x20, 0x2E,
+            0x21, 0x80,
+            0x22, 0xFF,
+            0x23, 0xC1,
+            0x28, 0x00,
+            0x29, 0x1E,
+            0x2A, 0x14,
+            0x2B, 0x0F,
+            0x2C, 0x09,
+            0x2D, 0x05,
+            0x31, 0x1F,
+            0x32, 0x19,
+            0x33, 0xFE,
+            0x34, 0x93,
+            0xff, 0xff,
+};
+
+static struct stv0299_config samsung_tbmu24112_config = {
+       .demod_address = 0x68,
+       .inittab = samsung_tbmu24112_inittab,
+       .mclk = 88000000UL,
+       .invert = 0,
+       .enhanced_tuning = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_LK,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
+       .pll_set = samsung_tbmu24112_pll_set,
+};
+
+/* dvb-t mt352 */
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+{
+       static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
+       static u8 mt352_reset [] = { 0x50, 0x80 };
+       static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+       static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+       static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+       mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+       udelay(2000);
+       mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+       mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+       mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+       mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+       return 0;
+}
+
+static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+       u32 div;
+       unsigned char bs = 0;
+
+       #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+       if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
+       if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
+       if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
+
+       pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+       pllbuf[1] = div >> 8;
+       pllbuf[2] = div & 0xff;
+       pllbuf[3] = 0xcc;
+       pllbuf[4] = bs;
+
+       return 0;
+}
+
+static struct mt352_config samsung_tdtc9251dh0_config = {
+
+       .demod_address = 0x0f,
+       .demod_init = samsung_tdtc9251dh0_demod_init,
+       .pll_set = samsung_tdtc9251dh0_pll_set,
+};
+
+static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+       struct flexcop_device *fc = fe->dvb->priv;
+       return request_firmware(fw, name, fc->dev);
+}
+
+static struct nxt2002_config samsung_tbmv_config = {
+       .demod_address = 0x0a,
+       .request_firmware = nxt2002_request_firmware,
+};
+
+static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       struct flexcop_device *fc = fe->dvb->priv;
+
+       div = (params->frequency + (125/2)) / 125;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = (div >> 0) & 0xff;
+       buf[2] = 0x84 | ((div >> 10) & 0x60);
+       buf[3] = 0x80;
+
+       if (params->frequency < 1550000)
+               buf[3] |= 0x02;
+
+       if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static struct mt312_config skystar23_samsung_tbdu18132_config = {
+
+       .demod_address = 0x0e,
+       .pll_set = skystar23_samsung_tbdu18132_pll_set,
+};
+
+static struct stv0297_config alps_tdee4_stv0297_config = {
+       .demod_address = 0x1c,
+//     .invert = 1,
+//     .pll_set = alps_tdee4_stv0297_pll_set,
+};
+
+/* try to figure out the frontend, each card/box can have on of the following list */
+int flexcop_frontend_init(struct flexcop_device *fc)
+{
+       /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
+       if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
+               fc->fe->ops->set_voltage = flexcop_set_voltage;
+
+               fc->fe_sleep             = fc->fe->ops->sleep;
+               fc->fe->ops->sleep       = flexcop_sleep;
+
+               fc->dev_type          = FC_SKY;
+               info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
+       } else
+       /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
+       if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
+               fc->dev_type          = FC_AIR_DVB;
+               info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
+       } else
+       /* try the air atsc (nxt2002) */
+       if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
+               fc->dev_type          = FC_AIR_ATSC;
+               info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
+       } else
+       /* try the cable dvb (stv0297) */
+       if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
+               fc->dev_type                        = FC_CABLE;
+               info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
+       } else
+       /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
+       if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
+               fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+               fc->fe->ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+               fc->fe->ops->set_tone               = flexcop_set_tone;
+               fc->fe->ops->set_voltage            = flexcop_set_voltage;
+
+               fc->fe_sleep                        = fc->fe->ops->sleep;
+               fc->fe->ops->sleep                  = flexcop_sleep;
+
+               fc->dev_type                        = FC_SKY_OLD;
+               info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
+       }
+
+       if (fc->fe == NULL) {
+               err("no frontend driver found for this B2C2/FlexCop adapter");
+               return -ENODEV;
+       } else {
+               if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
+                       err("frontend registration failed!");
+                       if (fc->fe->ops->release != NULL)
+                               fc->fe->ops->release(fc->fe);
+                       fc->fe = NULL;
+                       return -EINVAL;
+               }
+       }
+       fc->init_state |= FC_STATE_FE_INIT;
+       return 0;
+}
+
+void flexcop_frontend_exit(struct flexcop_device *fc)
+{
+       if (fc->init_state & FC_STATE_FE_INIT)
+               dvb_unregister_frontend(fc->fe);
+
+       fc->init_state &= ~FC_STATE_FE_INIT;
+}
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
new file mode 100644 (file)
index 0000000..2baf43d
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
+{
+       flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
+}
+
+void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
+{
+       flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff);
+}
+
+void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+       flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff);
+}
+
+void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
+{
+       flexcop_ibi_value v418,v41c;
+       v41c = fc->read_ibi_reg(fc,mac_address_41c);
+
+       v418.mac_address_418.MAC1 = mac[0];
+       v418.mac_address_418.MAC2 = mac[1];
+       v418.mac_address_418.MAC3 = mac[2];
+       v418.mac_address_418.MAC6 = mac[3];
+       v41c.mac_address_41c.MAC7 = mac[4];
+       v41c.mac_address_41c.MAC8 = mac[5];
+
+       fc->write_ibi_reg(fc,mac_address_418,v418);
+       fc->write_ibi_reg(fc,mac_address_41c,v41c);
+}
+
+void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+       flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff);
+}
+
+static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask)
+{
+       /* index_reg_310.extra_index_reg need to 0 or 7 to work */
+       flexcop_ibi_value v30c;
+       v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
+       v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
+       fc->write_ibi_reg(fc,pid_filter_30c,v30c);
+}
+
+static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+       flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff);
+}
+
+/* this fancy define reduces the code size of the quite similar PID controlling of
+ * the first 6 PIDs
+ */
+
+#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
+       flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
+                                         v208 = fc->read_ibi_reg(fc, ctrl_208); \
+\
+       vpid.vregname.field = onoff ? pid : 0x1fff; \
+       vpid.vregname.trans_field = transval; \
+       v208.ctrl_208.enablefield = onoff; \
+\
+       fc->write_ibi_reg(fc,vregname,vpid); \
+       fc->write_ibi_reg(fc,ctrl_208,v208);
+
+static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+       pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0);
+}
+
+static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+       pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0);
+}
+
+static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+       pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0);
+}
+
+static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+       pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0);
+}
+
+static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+       pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0);
+}
+
+static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+       pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0);
+}
+
+static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff)
+{
+       if (pid == 0x2000)
+               return;
+
+       deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off");
+
+       /* We could use bit magic here to reduce source code size.
+        * I decided against it, but to use the real register names */
+       switch (index) {
+               case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break;
+               case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break;
+               case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break;
+               case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break;
+               case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break;
+               case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break;
+               default:
+                       if (fc->has_32_hw_pid_filter && index < 38) {
+                               flexcop_ibi_value vpid,vid;
+
+                               /* set the index */
+                               vid = fc->read_ibi_reg(fc,index_reg_310);
+                               vid.index_reg_310.index_reg = index - 6;
+                               fc->write_ibi_reg(fc,index_reg_310, vid);
+
+                               vpid = fc->read_ibi_reg(fc,pid_n_reg_314);
+                               vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
+                               vpid.pid_n_reg_314.PID_enable_bit = onoff;
+                               fc->write_ibi_reg(fc,pid_n_reg_314, vpid);
+                       }
+                       break;
+       }
+}
+
+static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff)
+{
+       if (fc->fullts_streaming_state != onoff) {
+               deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
+               flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
+               flexcop_pid_group_filter_ctrl(fc,onoff);
+               fc->fullts_streaming_state = onoff;
+       }
+       return 0;
+}
+
+int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+       int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
+
+       fc->feedcount += onoff ? 1 : -1;
+       if (dvbdmxfeed->index >= max_pid_filter)
+               fc->extra_feedcount += onoff ? 1 : -1;
+
+       /* toggle complete-TS-streaming when:
+        * - pid_filtering is not enabled and it is the first or last feed requested
+        * - pid_filtering is enabled,
+        *   - but the number of requested feeds is exceeded
+        *   - or the requested pid is 0x2000 */
+
+       if (!fc->pid_filtering && fc->feedcount == onoff)
+               flexcop_toggle_fullts_streaming(fc,onoff);
+
+       if (fc->pid_filtering) {
+               flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+
+               if (fc->extra_feedcount > 0)
+                       flexcop_toggle_fullts_streaming(fc,1);
+               else if (dvbdmxfeed->pid == 0x2000)
+                       flexcop_toggle_fullts_streaming(fc,onoff);
+               else
+                       flexcop_toggle_fullts_streaming(fc,0);
+       }
+
+       /* if it was the first or last feed request change the stream-status */
+       if (fc->feedcount == onoff) {
+               flexcop_rcv_data_ctrl(fc,onoff);
+               if (fc->stream_control)
+                       fc->stream_control(fc,onoff);
+       }
+
+       return 0;
+}
+
+void flexcop_hw_filter_init(struct flexcop_device *fc)
+{
+       int i;
+       flexcop_ibi_value v;
+       for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
+               flexcop_pid_control(fc,i,0x1fff,0);
+
+       flexcop_pid_group_filter(fc, 0, 0x1fe0);
+       flexcop_pid_group_filter_ctrl(fc,0);
+
+       v = fc->read_ibi_reg(fc,pid_filter_308);
+       v.pid_filter_308.EMM_filter_4 = 1;
+       v.pid_filter_308.EMM_filter_6 = 0;
+       fc->write_ibi_reg(fc,pid_filter_308,v);
+
+       flexcop_null_filter_ctrl(fc, 1);
+}
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
new file mode 100644 (file)
index 0000000..be4266d
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#define FC_MAX_I2C_RETRIES 100000
+
+static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100)
+{
+       int i;
+       flexcop_ibi_value r;
+
+       r100->tw_sm_c_100.working_start = 1;
+       deb_i2c("r100 before: %08x\n",r100->raw);
+
+       fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
+       fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
+
+       for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
+               r = fc->read_ibi_reg(fc, tw_sm_c_100);
+
+               if (!r.tw_sm_c_100.no_base_addr_ack_error) {
+                       if (r.tw_sm_c_100.st_done) {  /* && !r.tw_sm_c_100.working_start */
+                               *r100 = r;
+                               deb_i2c("i2c success\n");
+                               return 0;
+                       }
+               } else {
+                       deb_i2c("suffering from an i2c ack_error\n");
+                       return -EREMOTEIO;
+               }
+       }
+       deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i);
+       return -EREMOTEIO;
+}
+
+static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
+{
+       flexcop_ibi_value r104;
+       int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
+               ret;
+
+       if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
+               /* The Cablestar needs a different kind of i2c-transfer (does not
+                * support "Repeat Start"):
+                * wait for the ACK failure,
+                * and do a subsequent read with the Bit 30 enabled
+                */
+               r100.tw_sm_c_100.no_base_addr_ack_error = 1;
+               if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
+                       deb_i2c("no_base_addr read failed. %d\n",ret);
+                       return ret;
+         &n